<commit_before>// (c) Copyright 2015 JONNALAGADDA Srinivas
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package flow

import (
	"fmt"
	"sync"
	"time"
)

// Mailbox is the message delivery destination for both action and
// informational messages.
//
// Both users and groups have mailboxes.  In all normal cases, a
// message is 'consumed' by the recipient.  Messages can be moved into
// and out of mailboxes to facilitate reassignments under specific or
// extraordinary conditions.
type Mailbox struct {
	id    uint64 // globally-unique
	user  *User  // in case of an individual user
	group *Group // in case of a group; does not receive broadcast messages

	mutex sync.Mutex
	msgs  []*Message // messages awaiting user consumption
}

// newMailbox creates and sets up a mailbox for the given user or
// group.
func newMailbox(u *User, grp *Group) (*Mailbox, error) {
	if u == nil && grp == nil {
		return nil, fmt.Errorf("neither user nor group given")
	}

	t := time.Now().UTC().UnixNano()
	if u != nil {
		return &Mailbox{id: uint64(t), user: u, msgs: make([]*Message, 1)}, nil
	}
	return &Mailbox{id: uint64(t), group: grp, msgs: make([]*Message, 1)}, nil
}

// TODO(js): implement `OpenMailbox()`

// ID answers this mailbox's ID.
func (mb *Mailbox) ID() uint64 {
	return mb.id
}

// User answers the recipient user of this mailbox.
func (mb *Mailbox) User() *User {
	return mb.user
}

// Group answers the recipient group of this mailbox.
func (mb *Mailbox) Group() *Group {
	return mb.group
}

// MsgCount answers the number of messages in this mailbox.
func (mb *Mailbox) MsgCount() int {
	mb.mutex.Lock()
	defer mb.mutex.Unlock()

	return len(mb.msgs)
}

// recvMsg delivers the given message into this mailbox.
func (mb *Mailbox) recvMsg(msg *Message) error {
	if msg == nil {
		return fmt.Errorf("`nil` message given")
	}

	mb.mutex.Lock()
	defer mb.mutex.Unlock()

	for _, el := range mb.msgs {
		if el.id == msg.id {
			return nil
		}
	}

	mb.msgs = append(mb.msgs, msg)
	return nil
}

// reassignMsg removes the message with the given ID from this
// mailbox, and delivers it to the given other mailbox.
func (mb *Mailbox) reassignMsg(msgID uint64, other *Mailbox) error {
	if msgID == 0 || other == nil {
		return fmt.Errorf("invalid inputs -- message ID: %d, mailbox: %v", msgID, other)
	}

	mb.mutex.Lock()
	defer mb.mutex.Unlock()

	idx := -1
	var msg *Message
	for i, el := range mb.msgs {
		if el.id == msgID {
			idx = i
			msg = el
			break
		}
	}
	if msg == nil {
		return fmt.Errorf("message not found -- ID: %d", msgID)
	}

	other.mutex.Lock()
	defer other.mutex.Unlock()

	mb.msgs = append(mb.msgs[:idx], mb.msgs[idx+1:]...)
	other.msgs = append(other.msgs, msg)
	return nil
}
<commit_msg>Change `sync.Mutex` in `Mailbox` to `sync.RWMutex`<commit_after>// (c) Copyright 2015 JONNALAGADDA Srinivas
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package flow

import (
	"fmt"
	"sync"
	"time"
)

// Mailbox is the message delivery destination for both action and
// informational messages.
//
// Both users and groups have mailboxes.  In all normal cases, a
// message is 'consumed' by the recipient.  Messages can be moved into
// and out of mailboxes to facilitate reassignments under specific or
// extraordinary conditions.
type Mailbox struct {
	id    uint64 // globally-unique
	user  *User  // in case of an individual user
	group *Group // in case of a group; does not receive broadcast messages

	mutex sync.RWMutex
	msgs  []*Message // messages awaiting user consumption
}

// newMailbox creates and sets up a mailbox for the given user or
// group.
func newMailbox(u *User, grp *Group) (*Mailbox, error) {
	if u == nil && grp == nil {
		return nil, fmt.Errorf("neither user nor group given")
	}

	t := time.Now().UTC().UnixNano()
	if u != nil {
		return &Mailbox{id: uint64(t), user: u, msgs: make([]*Message, 1)}, nil
	}
	return &Mailbox{id: uint64(t), group: grp, msgs: make([]*Message, 1)}, nil
}

// TODO(js): `OpenMailbox()`

// ID answers this mailbox's ID.
func (mb *Mailbox) ID() uint64 {
	return mb.id
}

// User answers the recipient user of this mailbox.
func (mb *Mailbox) User() *User {
	return mb.user
}

// Group answers the recipient group of this mailbox.
func (mb *Mailbox) Group() *Group {
	return mb.group
}

// MsgCount answers the number of messages in this mailbox.
func (mb *Mailbox) MsgCount() int {
	mb.mutex.RLock()
	defer mb.mutex.RUnlock()

	return len(mb.msgs)
}

// recvMsg delivers the given message into this mailbox.
func (mb *Mailbox) recvMsg(msg *Message) error {
	if msg == nil {
		return fmt.Errorf("`nil` message given")
	}

	mb.mutex.Lock()
	defer mb.mutex.Unlock()

	for _, el := range mb.msgs {
		if el.id == msg.id {
			return nil
		}
	}

	mb.msgs = append(mb.msgs, msg)
	return nil
}

// reassignMsg removes the message with the given ID from this
// mailbox, and delivers it to the given other mailbox.
func (mb *Mailbox) reassignMsg(msgID uint64, other *Mailbox) error {
	if msgID == 0 || other == nil {
		return fmt.Errorf("invalid inputs -- message ID: %d, mailbox: %v", msgID, other)
	}

	// TODO(js): this can deadlock currently; resolution needed

	mb.mutex.Lock()
	defer mb.mutex.Unlock()

	idx := -1
	var msg *Message
	for i, el := range mb.msgs {
		if el.id == msgID {
			idx = i
			msg = el
			break
		}
	}
	if msg == nil {
		return fmt.Errorf("message not found -- ID: %d", msgID)
	}

	other.mutex.Lock()
	defer other.mutex.Unlock()

	mb.msgs = append(mb.msgs[:idx], mb.msgs[idx+1:]...)
	other.msgs = append(other.msgs, msg)
	return nil
}
<|endoftext|>


<commit_before>package logmunch

import (
	"net/url"
	"testing"
	"time"
)

func TestSourceLoaderGetSource(t *testing.T) {
	s := SourceLoader{
		Config: map[string]url.URL{
			"logentries": url.URL{
				Scheme: "logentries",
				User:   url.UserPassword("", "logentries_password"),
			},
			"file": url.URL{
				Path: "-", // stdin
			},
		},
	}

	_, config, _ := s.GetConfig("logentries:///Path/name/to/fetch")

	if config.User.String() != ":logentries_password" {
		t.Errorf("Expected %v to have User info ':logentries_password', got %s", config, config.User)
	}

	if config.Path != "/Path/name/to/fetch" {
		t.Errorf("Expected %v to have Path '/Path/name/to/fetch', got %s", config, config.Path)
	}
}

func TestSourceLoaderGetData(t *testing.T) {
	s := SourceLoader{
		Config: map[string]url.URL{
			"file": url.URL{
				Scheme: "file",
				Path:   "-", // stdin
			},
		},
	}

	out := make(chan string, 0)
	lines := make([]string, 0)

	go func() {
		for line := range out {
			lines = append(lines, line)
		}
	}()

	_, err := s.GetData("file:/./source_test.go", Query{}, out)

	if err != nil {
		t.Fatalf("s.GetData() error: '%s'.", err)
	}

	if len(lines) == 0 {
		t.Errorf("No lines fetched")
	}
}
<commit_msg>Fix test by removing unused import.<commit_after>package logmunch

import (
	"net/url"
	"testing"
)

func TestSourceLoaderGetSource(t *testing.T) {
	s := SourceLoader{
		Config: map[string]url.URL{
			"logentries": url.URL{
				Scheme: "logentries",
				User:   url.UserPassword("", "logentries_password"),
			},
			"file": url.URL{
				Path: "-", // stdin
			},
		},
	}

	_, config, _ := s.GetConfig("logentries:///Path/name/to/fetch")

	if config.User.String() != ":logentries_password" {
		t.Errorf("Expected %v to have User info ':logentries_password', got %s", config, config.User)
	}

	if config.Path != "/Path/name/to/fetch" {
		t.Errorf("Expected %v to have Path '/Path/name/to/fetch', got %s", config, config.Path)
	}
}

func TestSourceLoaderGetData(t *testing.T) {
	s := SourceLoader{
		Config: map[string]url.URL{
			"file": url.URL{
				Scheme: "file",
				Path:   "-", // stdin
			},
		},
	}

	out := make(chan string, 0)
	lines := make([]string, 0)

	go func() {
		for line := range out {
			lines = append(lines, line)
		}
	}()

	_, err := s.GetData("file:/./source_test.go", Query{}, out)

	if err != nil {
		t.Fatalf("s.GetData() error: '%s'.", err)
	}

	if len(lines) == 0 {
		t.Errorf("No lines fetched")
	}
}
<|endoftext|>


<commit_before>/*
library for connecting go applications into i2p with relative ease

implements `net.Listener`, `net.Conn`, `net.Addr`, `net.Dial` that goes over i2p

    package main

    import (
      "github.com/majestrate/i2p-tools/lib/i2p"
      "fmt"
      "net"
      "path/filepath"
    )

    // see i2p.Session interface for more usage

    func main() {
       var err error
       var sess i2p.Session
       // connect to an i2p router
       // you can pass in "" to generate a transient session that doesn't save the destination keys
       sess, err = i2p.NewSessionEasy("127.0.0.1:7656", filepath.Join("some", "path", "to", "privatekey.txt"))
       if err != nil {
         log.Println("failed to open connection to i2p router", err)
         return
       }
       // close our connection to i2p when done
       defer sess.Close()

       // i2p.Session implements net.Listener
       // we can pass it to http.Serve to serve an http server via i2p
       fmt.Printf("http server going up at http://%s/", sess.B32())
       err = http.Serve(sess, nil)
    }

*/
package i2p
<commit_msg>make example compile :-DDDD<commit_after>/*
library for connecting go applications into i2p with relative ease

implements `net.Listener`, `net.Conn`, `net.Addr`, `net.Dial` that goes over i2p

    package main

    import (
      "github.com/majestrate/i2p-tools/lib/i2p"
      "fmt"
      "net"
      "net/http"
      "path/filepath"
    )

    // see i2p.Session interface for more usage

    func main() {
       var err error
       var sess i2p.Session
       // connect to an i2p router
       // you can pass in "" to generate a transient session that doesn't save the destination keys
       sess, err = i2p.NewSessionEasy("127.0.0.1:7656", filepath.Join("some", "path", "to", "privatekey.txt"))
       if err != nil {
         log.Println("failed to open connection to i2p router", err)
         return
       }
       // close our connection to i2p when done
       defer sess.Close()

       // i2p.Session implements net.Listener
       // we can pass it to http.Serve to serve an http server via i2p
       fmt.Printf("http server going up at http://%s/", sess.B32())
       err = http.Serve(sess, nil)
    }

*/
package i2p
<|endoftext|>


<commit_before>package lib

import (
	"io/ioutil"
	"log"
	"testing"

	"github.com/stretchr/testify/assert"
)

func TestEncryptFileAndDecryptFile(t *testing.T) {
	var (
		cleartext1 []byte
		cleartext2 []byte
		key1       []byte
		key2       []byte
		nonce1     []byte
		nonce2     []byte
		password   []byte
		salt1      []byte
		salt2      []byte
	)

	tmp, err := ioutil.TempFile("", "")
	if err != nil {
		log.Fatal(err)
	}

	cleartext1 = []byte("The quick brown fox jumps over the lazy dog.")
	password = []byte("mysuperdupersecurepassword")
	salt1 = NewNonce()
	key1 = NewKey(salt1, password)
	nonce1 = NewNonce()

	EncryptFile(tmp.Name(), cleartext1, nonce1, key1, salt1)
	cleartext2, nonce2, key2, salt2 = DecryptFile(tmp.Name(), password)

	assert.Equal(t, cleartext1, cleartext2, "cleartext should match")
	assert.Equal(t, nonce1, nonce2, "nonce should match")
	assert.Equal(t, key1, key2, "key should match")
	assert.Equal(t, salt1, salt2, "salt should match")
}

func TestGetRawFileName(t *testing.T) {
	var (
		config     Config
		filenameA1 string
		filenameA2 string
		filenameB1 string
	)

	config.Files = make(map[string]string, 0)

	filenameA1 = getRawFileName(config, "hello.txt")
	assert.Len(t, filenameA1, rawFileNameLength, "generated raw filename is incorrect length")
	config.Files["hello.txt"] = filenameA1

	filenameA2 = getRawFileName(config, "hello.txt")
	assert.Equal(t, filenameA1, filenameA2, "raw filenames should match")

	filenameB1 = getRawFileName(config, "foo.jpg")
	assert.NotEqual(t, filenameA1, filenameB1, "raw filenames should not match")
}
<commit_msg>Test ConfigWrite and ConfigRead<commit_after>package lib

import (
	"io/ioutil"
	"log"
	"testing"

	"github.com/stretchr/testify/assert"
)

func TestEncryptFileAndDecryptFile(t *testing.T) {
	var (
		cleartext1 []byte
		cleartext2 []byte
		key1       []byte
		key2       []byte
		nonce1     []byte
		nonce2     []byte
		password   []byte
		salt1      []byte
		salt2      []byte
	)

	tmp, err := ioutil.TempFile("", "")
	if err != nil {
		log.Fatal(err)
	}

	cleartext1 = []byte("The quick brown fox jumps over the lazy dog.")
	password = []byte("mysuperdupersecurepassword")
	salt1 = NewNonce()
	key1 = NewKey(salt1, password)
	nonce1 = NewNonce()

	EncryptFile(tmp.Name(), cleartext1, nonce1, key1, salt1)
	cleartext2, nonce2, key2, salt2 = DecryptFile(tmp.Name(), password)

	assert.Equal(t, cleartext1, cleartext2, "cleartext should match")
	assert.Equal(t, nonce1, nonce2, "nonce should match")
	assert.Equal(t, key1, key2, "key should match")
	assert.Equal(t, salt1, salt2, "salt should match")
}

func TestConfigReadAndConfigWrite(t *testing.T) {
	var (
		config1  Config
		config2  Config
		key1     []byte
		key2     []byte
		nonce1   []byte
		nonce2   []byte
		password []byte
		salt1    []byte
		salt2    []byte
	)

	tmp, err := ioutil.TempDir("", "")
	if err != nil {
		log.Fatal(err)
	}

	config1.Files = make(map[string]string, 1)
	config1.Files["foo"] = "bar"
	password = []byte("mysuperdupersecurepassword")
	salt1 = NewNonce()
	key1 = NewKey(salt1, password)
	nonce1 = NewNonce()

	ConfigWrite(tmp, config1, nonce1, key1, salt1)
	config2, nonce2, key2, salt2 = ConfigRead(tmp, password)

	assert.True(t, assert.ObjectsAreEqual(config1, config2), "config should match.\nExpected: %v\nActual: %v", config1, config2)
	assert.Equal(t, nonce1, nonce2, "nonce should match")
	assert.Equal(t, key1, key2, "key should match")
	assert.Equal(t, salt1, salt2, "salt should match")
}

func TestGetRawFileName(t *testing.T) {
	var (
		config     Config
		filenameA1 string
		filenameA2 string
		filenameB1 string
	)

	config.Files = make(map[string]string, 0)

	filenameA1 = getRawFileName(config, "hello.txt")
	assert.Len(t, filenameA1, rawFileNameLength, "generated raw filename is incorrect length")
	config.Files["hello.txt"] = filenameA1

	filenameA2 = getRawFileName(config, "hello.txt")
	assert.Equal(t, filenameA1, filenameA2, "raw filenames should match")

	filenameB1 = getRawFileName(config, "foo.jpg")
	assert.NotEqual(t, filenameA1, filenameB1, "raw filenames should not match")
}
<|endoftext|>


<commit_before>package scs

import (
	"context"
	"log"
	"net/http"
	"time"

	"github.com/alexedwards/scs/stores/cookiestore"
)

// Manager is a session manager.
type Manager struct {
	store Store
	opts  *options
}

// NewManager returns a pointer to a new session manager.
func NewManager(store Store) *Manager {
	defaultOptions := &options{
		domain:      "",
		httpOnly:    true,
		idleTimeout: 0,
		lifetime:    24 * time.Hour,
		name:        "session",
		path:        "/",
		persist:     false,
		secure:      false,
	}

	return &Manager{
		store: store,
		opts:  defaultOptions,
	}
}

// Domain sets the 'Domain' attribute on the session cookie. By default it will
// be set to the domain name that the cookie was issued from.
func (m *Manager) Domain(s string) {
	m.opts.domain = s
}

// HttpOnly sets the 'HttpOnly' attribute on the session cookie. The default value
// is true.
func (m *Manager) HttpOnly(b bool) {
	m.opts.httpOnly = b
}

// IdleTimeout sets the maximum length of time a session can be inactive before it
// expires. For example, some applications may wish to set this so there is a timeout
// after 20 minutes of inactivity. The inactivity period is reset whenever the
// session data is changed (but not read).
//
// By default IdleTimeout is not set and there is no inactivity timeout.
func (m *Manager) IdleTimeout(t time.Duration) {
	m.opts.idleTimeout = t
}

// Lifetime sets the maximum length of time that a session is valid for before
// it expires. The lifetime is an 'absolute expiry' which is set when the session
// is first created and does not change.
//
// The default value is 24 hours.
func (m *Manager) Lifetime(t time.Duration) {
	m.opts.lifetime = t
}

// Name sets the name of the session cookie. This name should not contain whitespace,
// commas, semicolons, backslashes, the equals sign or control characters as per
// RFC6265.
func (m *Manager) Name(s string) {
	m.opts.name = s
}

// Path sets the 'Path' attribute on the session cookie. The default value is "/".
// Passing the empty string "" will result in it being set to the path that the
// cookie was issued from.
func (m *Manager) Path(s string) {
	m.opts.path = s
}

// Persist sets whether the session cookie should be persistent or not (i.e. whether
// it should be retained after a user closes their browser).
//
// The default value is false, which means that the session cookie will be destroyed
// when the user closes their browser. If set to true, explicit 'Expires' and
// 'MaxAge' values will be added to the cookie and it will be retained by the
// user's browser until the given expiry time is reached.
func (m *Manager) Persist(b bool) {
	m.opts.persist = b
}

// Secure sets the 'Secure' attribute on the session cookie. The default value
// is false. It's recommended that you set this to true and serve all requests
// over HTTPS in production environments.
func (m *Manager) Secure(b bool) {
	m.opts.secure = b
}

// Load returns the session data for the current request.
func (m *Manager) Load(r *http.Request) *Session {
	return load(r, m.store, m.opts)
}

func NewCookieManager(key string) *Manager {
	store := cookiestore.New([]byte(key))
	return NewManager(store)
}

func (m *Manager) Multi(next http.Handler) http.Handler {
	return m.Use(next)
}

func (m *Manager) Use(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		session := m.Load(r)

		if m.opts.idleTimeout > 0 {
			err := session.Touch(w)
			if err != nil {
				log.Println(err)
				http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
				return
			}
		}

		ctx := context.WithValue(r.Context(), sessionName(m.opts.name), session)
		next.ServeHTTP(w, r.WithContext(ctx))
	})
}
<commit_msg>[feature] Add LoadFromContext and AddToContext methods<commit_after>package scs

import (
	"context"
	"fmt"
	"log"
	"net/http"
	"time"

	"github.com/alexedwards/scs/stores/cookiestore"
)

// Manager is a session manager.
type Manager struct {
	store Store
	opts  *options
}

// NewManager returns a pointer to a new session manager.
func NewManager(store Store) *Manager {
	defaultOptions := &options{
		domain:      "",
		httpOnly:    true,
		idleTimeout: 0,
		lifetime:    24 * time.Hour,
		name:        "session",
		path:        "/",
		persist:     false,
		secure:      false,
	}

	return &Manager{
		store: store,
		opts:  defaultOptions,
	}
}

// Domain sets the 'Domain' attribute on the session cookie. By default it will
// be set to the domain name that the cookie was issued from.
func (m *Manager) Domain(s string) {
	m.opts.domain = s
}

// HttpOnly sets the 'HttpOnly' attribute on the session cookie. The default value
// is true.
func (m *Manager) HttpOnly(b bool) {
	m.opts.httpOnly = b
}

// IdleTimeout sets the maximum length of time a session can be inactive before it
// expires. For example, some applications may wish to set this so there is a timeout
// after 20 minutes of inactivity. The inactivity period is reset whenever the
// session data is changed (but not read).
//
// By default IdleTimeout is not set and there is no inactivity timeout.
func (m *Manager) IdleTimeout(t time.Duration) {
	m.opts.idleTimeout = t
}

// Lifetime sets the maximum length of time that a session is valid for before
// it expires. The lifetime is an 'absolute expiry' which is set when the session
// is first created and does not change.
//
// The default value is 24 hours.
func (m *Manager) Lifetime(t time.Duration) {
	m.opts.lifetime = t
}

// Name sets the name of the session cookie. This name should not contain whitespace,
// commas, semicolons, backslashes, the equals sign or control characters as per
// RFC6265.
func (m *Manager) Name(s string) {
	m.opts.name = s
}

// Path sets the 'Path' attribute on the session cookie. The default value is "/".
// Passing the empty string "" will result in it being set to the path that the
// cookie was issued from.
func (m *Manager) Path(s string) {
	m.opts.path = s
}

// Persist sets whether the session cookie should be persistent or not (i.e. whether
// it should be retained after a user closes their browser).
//
// The default value is false, which means that the session cookie will be destroyed
// when the user closes their browser. If set to true, explicit 'Expires' and
// 'MaxAge' values will be added to the cookie and it will be retained by the
// user's browser until the given expiry time is reached.
func (m *Manager) Persist(b bool) {
	m.opts.persist = b
}

// Secure sets the 'Secure' attribute on the session cookie. The default value
// is false. It's recommended that you set this to true and serve all requests
// over HTTPS in production environments.
func (m *Manager) Secure(b bool) {
	m.opts.secure = b
}

// Load returns the session data for the current request.
func (m *Manager) Load(r *http.Request) *Session {
	return load(r, m.store, m.opts)
}

// LoadFromContext returns session data from a given context.Context object.
func (m *Manager) LoadFromContext(ctx context.Context) *Session {
	val := ctx.Value(sessionName(m.opts.name))
	if val == nil {
		return &Session{loadErr: fmt.Errorf("scs: value %s not in context", m.opts.name)}
	}

	s, ok := val.(*Session)
	if !ok {
		return &Session{loadErr: fmt.Errorf("scs: can not assert %T to *Session", val)}
	}
	return s
}

// AddToContext adds session data to a given context.Context object.
func (m *Manager) AddToContext(ctx context.Context, session *Session) context.Context {
	return context.WithValue(ctx, sessionName(m.opts.name), session)
}

func NewCookieManager(key string) *Manager {
	store := cookiestore.New([]byte(key))
	return NewManager(store)
}

func (m *Manager) Multi(next http.Handler) http.Handler {
	return m.Use(next)
}

func (m *Manager) Use(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		session := m.Load(r)

		if m.opts.idleTimeout > 0 {
			err := session.Touch(w)
			if err != nil {
				log.Println(err)
				http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
				return
			}
		}

		ctx := m.AddToContext(r.Context(), session)
		next.ServeHTTP(w, r.WithContext(ctx))
	})
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2013-2016 Dave Collins <dave@davec.name>
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

package spew

import (
	"bytes"
	"fmt"
	"io"
	"reflect"
	"sort"
	"strconv"
)

// Some constants in the form of bytes to avoid string overhead.  This mirrors
// the technique used in the fmt package.
var (
	panicBytes            = []byte("(PANIC=")
	plusBytes             = []byte("+")
	iBytes                = []byte("i")
	trueBytes             = []byte("true")
	falseBytes            = []byte("false")
	interfaceBytes        = []byte("(interface {})")
	commaNewlineBytes     = []byte(",\n")
	newlineBytes          = []byte("\n")
	openBraceBytes        = []byte("{")
	openBraceNewlineBytes = []byte("{\n")
	closeBraceBytes       = []byte("}")
	asteriskBytes         = []byte("*")
	colonBytes            = []byte(":")
	colonSpaceBytes       = []byte(": ")
	openParenBytes        = []byte("(")
	closeParenBytes       = []byte(")")
	spaceBytes            = []byte(" ")
	pointerChainBytes     = []byte("->")
	nilAngleBytes         = []byte("<nil>")
	maxNewlineBytes       = []byte("<max depth reached>\n")
	maxShortBytes         = []byte("<max>")
	circularBytes         = []byte("<already shown>")
	circularShortBytes    = []byte("<shown>")
	invalidAngleBytes     = []byte("<invalid>")
	openBracketBytes      = []byte("[")
	closeBracketBytes     = []byte("]")
	percentBytes          = []byte("%")
	precisionBytes        = []byte(".")
	openAngleBytes        = []byte("<")
	closeAngleBytes       = []byte(">")
	openMapBytes          = []byte("map[")
	closeMapBytes         = []byte("]")
	lenEqualsBytes        = []byte("len=")
	capEqualsBytes        = []byte("cap=")
)

// hexDigits is used to map a decimal value to a hex digit.
var hexDigits = "0123456789abcdef"

// catchPanic handles any panics that might occur during the handleMethods
// calls.
func catchPanic(w io.Writer, v reflect.Value) {
	if err := recover(); err != nil {
		w.Write(panicBytes)
		fmt.Fprintf(w, "%v", err)
		w.Write(closeParenBytes)
	}
}

// handleMethods attempts to call the Error and String methods on the underlying
// type the passed reflect.Value represents and outputes the result to Writer w.
//
// It handles panics in any called methods by catching and displaying the error
// as the formatted value.
func handleMethods(cs *ConfigState, w io.Writer, v reflect.Value) (handled bool) {
	// We need an interface to check if the type implements the error or
	// Stringer interface.  However, the reflect package won't give us an
	// interface on certain things like unexported struct fields in order
	// to enforce visibility rules.  We use unsafe, when it's available,
	// to bypass these restrictions since this package does not mutate the
	// values.
	if !v.CanInterface() {
		if UnsafeDisabled {
			return false
		}

		v = unsafeReflectValue(v)
	}

	// Choose whether or not to do error and Stringer interface lookups against
	// the base type or a pointer to the base type depending on settings.
	// Technically calling one of these methods with a pointer receiver can
	// mutate the value, however, types which choose to satisify an error or
	// Stringer interface with a pointer receiver should not be mutating their
	// state inside these interface methods.
	if !cs.DisablePointerMethods && !UnsafeDisabled && !v.CanAddr() {
		v = unsafeReflectValue(v)
	}
	if v.CanAddr() {
		v = v.Addr()
	}

	// Is it an error or Stringer?
	switch iface := v.Interface().(type) {
	case error:
		defer catchPanic(w, v)
		if cs.ContinueOnMethod {
			w.Write(openParenBytes)
			w.Write([]byte(iface.Error()))
			w.Write(closeParenBytes)
			w.Write(spaceBytes)
			return false
		}

		w.Write([]byte(iface.Error()))
		return true

	case fmt.Stringer:
		defer catchPanic(w, v)
		if cs.ContinueOnMethod {
			w.Write(openParenBytes)
			w.Write([]byte(iface.String()))
			w.Write(closeParenBytes)
			w.Write(spaceBytes)
			return false
		}
		w.Write([]byte(iface.String()))
		return true
	}
	return false
}

// printBool outputs a boolean value as true or false to Writer w.
func printBool(w io.Writer, val bool) {
	if val {
		w.Write(trueBytes)
	} else {
		w.Write(falseBytes)
	}
}

// printInt outputs a signed integer value to Writer w.
func printInt(w io.Writer, val int64, base int) {
	w.Write([]byte(strconv.FormatInt(val, base)))
}

// printUint outputs an unsigned integer value to Writer w.
func printUint(w io.Writer, val uint64, base int) {
	w.Write([]byte(strconv.FormatUint(val, base)))
}

// printFloat outputs a floating point value using the specified precision,
// which is expected to be 32 or 64bit, to Writer w.
func printFloat(w io.Writer, val float64, precision int) {
	w.Write([]byte(strconv.FormatFloat(val, 'g', -1, precision)))
}

// printComplex outputs a complex value using the specified float precision
// for the real and imaginary parts to Writer w.
func printComplex(w io.Writer, c complex128, floatPrecision int) {
	r := real(c)
	w.Write(openParenBytes)
	w.Write([]byte(strconv.FormatFloat(r, 'g', -1, floatPrecision)))
	i := imag(c)
	if i >= 0 {
		w.Write(plusBytes)
	}
	w.Write([]byte(strconv.FormatFloat(i, 'g', -1, floatPrecision)))
	w.Write(iBytes)
	w.Write(closeParenBytes)
}

// printHexPtr outputs a uintptr formatted as hexidecimal with a leading '0x'
// prefix to Writer w.
func printHexPtr(w io.Writer, p uintptr) {
	// Null pointer.
	num := uint64(p)
	if num == 0 {
		w.Write(nilAngleBytes)
		return
	}

	// Max uint64 is 16 bytes in hex + 2 bytes for '0x' prefix
	buf := make([]byte, 18)

	// It's simpler to construct the hex string right to left.
	base := uint64(16)
	i := len(buf) - 1
	for num >= base {
		buf[i] = hexDigits[num%base]
		num /= base
		i--
	}
	buf[i] = hexDigits[num]

	// Add '0x' prefix.
	i--
	buf[i] = 'x'
	i--
	buf[i] = '0'

	// Strip unused leading bytes.
	buf = buf[i:]
	w.Write(buf)
}

// valuesSorter implements sort.Interface to allow a slice of reflect.Value
// elements to be sorted.
type valuesSorter struct {
	values  []reflect.Value
	strings []string // either nil or same len and values
	cs      *ConfigState
}

// newValuesSorter initializes a valuesSorter instance, which holds a set of
// surrogate keys on which the data should be sorted.  It uses flags in
// ConfigState to decide if and how to populate those surrogate keys.
func newValuesSorter(values []reflect.Value, cs *ConfigState) sort.Interface {
	vs := &valuesSorter{values: values, cs: cs}
	if canSortSimply(vs.values[0].Kind()) {
		return vs
	}
	if !cs.DisableMethods {
		vs.strings = make([]string, len(values))
		for i := range vs.values {
			b := bytes.Buffer{}
			if !handleMethods(cs, &b, vs.values[i]) {
				vs.strings = nil
				break
			}
			vs.strings[i] = b.String()
		}
	}
	if vs.strings == nil && cs.SpewKeys {
		vs.strings = make([]string, len(values))
		for i := range vs.values {
			vs.strings[i] = Sprintf("%#v", vs.values[i].Interface())
		}
	}
	return vs
}

// canSortSimply tests whether a reflect.Kind is a primitive that can be sorted
// directly, or whether it should be considered for sorting by surrogate keys
// (if the ConfigState allows it).
func canSortSimply(kind reflect.Kind) bool {
	// This switch parallels valueSortLess, except for the default case.
	switch kind {
	case reflect.Bool:
		return true
	case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int:
		return true
	case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint:
		return true
	case reflect.Float32, reflect.Float64:
		return true
	case reflect.String:
		return true
	case reflect.Uintptr:
		return true
	case reflect.Array:
		return true
	}
	return false
}

// Len returns the number of values in the slice.  It is part of the
// sort.Interface implementation.
func (s *valuesSorter) Len() int {
	return len(s.values)
}

// Swap swaps the values at the passed indices.  It is part of the
// sort.Interface implementation.
func (s *valuesSorter) Swap(i, j int) {
	s.values[i], s.values[j] = s.values[j], s.values[i]
	if s.strings != nil {
		s.strings[i], s.strings[j] = s.strings[j], s.strings[i]
	}
}

// valueSortLess returns whether the first value should sort before the second
// value.  It is used by valueSorter.Less as part of the sort.Interface
// implementation.
func valueSortLess(a, b reflect.Value) bool {
	switch a.Kind() {
	case reflect.Bool:
		return !a.Bool() && b.Bool()
	case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int:
		return a.Int() < b.Int()
	case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint:
		return a.Uint() < b.Uint()
	case reflect.Float32, reflect.Float64:
		return a.Float() < b.Float()
	case reflect.String:
		return a.String() < b.String()
	case reflect.Uintptr:
		return a.Uint() < b.Uint()
	case reflect.Array:
		// Compare the contents of both arrays.
		l := a.Len()
		for i := 0; i < l; i++ {
			av := a.Index(i)
			bv := b.Index(i)
			if av.Interface() == bv.Interface() {
				continue
			}
			return valueSortLess(av, bv)
		}
	}
	return a.String() < b.String()
}

// Less returns whether the value at index i should sort before the
// value at index j.  It is part of the sort.Interface implementation.
func (s *valuesSorter) Less(i, j int) bool {
	if s.strings == nil {
		return valueSortLess(s.values[i], s.values[j])
	}
	return s.strings[i] < s.strings[j]
}

// sortValues is a sort function that handles both native types and any type that
// can be converted to error or Stringer.  Other inputs are sorted according to
// their Value.String() value to ensure display stability.
func sortValues(values []reflect.Value, cs *ConfigState) {
	if len(values) == 0 {
		return
	}
	sort.Sort(newValuesSorter(values, cs))
}
<commit_msg>correct misspell on spew/common.go#L183<commit_after>/*
 * Copyright (c) 2013-2016 Dave Collins <dave@davec.name>
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

package spew

import (
	"bytes"
	"fmt"
	"io"
	"reflect"
	"sort"
	"strconv"
)

// Some constants in the form of bytes to avoid string overhead.  This mirrors
// the technique used in the fmt package.
var (
	panicBytes            = []byte("(PANIC=")
	plusBytes             = []byte("+")
	iBytes                = []byte("i")
	trueBytes             = []byte("true")
	falseBytes            = []byte("false")
	interfaceBytes        = []byte("(interface {})")
	commaNewlineBytes     = []byte(",\n")
	newlineBytes          = []byte("\n")
	openBraceBytes        = []byte("{")
	openBraceNewlineBytes = []byte("{\n")
	closeBraceBytes       = []byte("}")
	asteriskBytes         = []byte("*")
	colonBytes            = []byte(":")
	colonSpaceBytes       = []byte(": ")
	openParenBytes        = []byte("(")
	closeParenBytes       = []byte(")")
	spaceBytes            = []byte(" ")
	pointerChainBytes     = []byte("->")
	nilAngleBytes         = []byte("<nil>")
	maxNewlineBytes       = []byte("<max depth reached>\n")
	maxShortBytes         = []byte("<max>")
	circularBytes         = []byte("<already shown>")
	circularShortBytes    = []byte("<shown>")
	invalidAngleBytes     = []byte("<invalid>")
	openBracketBytes      = []byte("[")
	closeBracketBytes     = []byte("]")
	percentBytes          = []byte("%")
	precisionBytes        = []byte(".")
	openAngleBytes        = []byte("<")
	closeAngleBytes       = []byte(">")
	openMapBytes          = []byte("map[")
	closeMapBytes         = []byte("]")
	lenEqualsBytes        = []byte("len=")
	capEqualsBytes        = []byte("cap=")
)

// hexDigits is used to map a decimal value to a hex digit.
var hexDigits = "0123456789abcdef"

// catchPanic handles any panics that might occur during the handleMethods
// calls.
func catchPanic(w io.Writer, v reflect.Value) {
	if err := recover(); err != nil {
		w.Write(panicBytes)
		fmt.Fprintf(w, "%v", err)
		w.Write(closeParenBytes)
	}
}

// handleMethods attempts to call the Error and String methods on the underlying
// type the passed reflect.Value represents and outputes the result to Writer w.
//
// It handles panics in any called methods by catching and displaying the error
// as the formatted value.
func handleMethods(cs *ConfigState, w io.Writer, v reflect.Value) (handled bool) {
	// We need an interface to check if the type implements the error or
	// Stringer interface.  However, the reflect package won't give us an
	// interface on certain things like unexported struct fields in order
	// to enforce visibility rules.  We use unsafe, when it's available,
	// to bypass these restrictions since this package does not mutate the
	// values.
	if !v.CanInterface() {
		if UnsafeDisabled {
			return false
		}

		v = unsafeReflectValue(v)
	}

	// Choose whether or not to do error and Stringer interface lookups against
	// the base type or a pointer to the base type depending on settings.
	// Technically calling one of these methods with a pointer receiver can
	// mutate the value, however, types which choose to satisify an error or
	// Stringer interface with a pointer receiver should not be mutating their
	// state inside these interface methods.
	if !cs.DisablePointerMethods && !UnsafeDisabled && !v.CanAddr() {
		v = unsafeReflectValue(v)
	}
	if v.CanAddr() {
		v = v.Addr()
	}

	// Is it an error or Stringer?
	switch iface := v.Interface().(type) {
	case error:
		defer catchPanic(w, v)
		if cs.ContinueOnMethod {
			w.Write(openParenBytes)
			w.Write([]byte(iface.Error()))
			w.Write(closeParenBytes)
			w.Write(spaceBytes)
			return false
		}

		w.Write([]byte(iface.Error()))
		return true

	case fmt.Stringer:
		defer catchPanic(w, v)
		if cs.ContinueOnMethod {
			w.Write(openParenBytes)
			w.Write([]byte(iface.String()))
			w.Write(closeParenBytes)
			w.Write(spaceBytes)
			return false
		}
		w.Write([]byte(iface.String()))
		return true
	}
	return false
}

// printBool outputs a boolean value as true or false to Writer w.
func printBool(w io.Writer, val bool) {
	if val {
		w.Write(trueBytes)
	} else {
		w.Write(falseBytes)
	}
}

// printInt outputs a signed integer value to Writer w.
func printInt(w io.Writer, val int64, base int) {
	w.Write([]byte(strconv.FormatInt(val, base)))
}

// printUint outputs an unsigned integer value to Writer w.
func printUint(w io.Writer, val uint64, base int) {
	w.Write([]byte(strconv.FormatUint(val, base)))
}

// printFloat outputs a floating point value using the specified precision,
// which is expected to be 32 or 64bit, to Writer w.
func printFloat(w io.Writer, val float64, precision int) {
	w.Write([]byte(strconv.FormatFloat(val, 'g', -1, precision)))
}

// printComplex outputs a complex value using the specified float precision
// for the real and imaginary parts to Writer w.
func printComplex(w io.Writer, c complex128, floatPrecision int) {
	r := real(c)
	w.Write(openParenBytes)
	w.Write([]byte(strconv.FormatFloat(r, 'g', -1, floatPrecision)))
	i := imag(c)
	if i >= 0 {
		w.Write(plusBytes)
	}
	w.Write([]byte(strconv.FormatFloat(i, 'g', -1, floatPrecision)))
	w.Write(iBytes)
	w.Write(closeParenBytes)
}

// printHexPtr outputs a uintptr formatted as hexadecimal with a leading '0x'
// prefix to Writer w.
func printHexPtr(w io.Writer, p uintptr) {
	// Null pointer.
	num := uint64(p)
	if num == 0 {
		w.Write(nilAngleBytes)
		return
	}

	// Max uint64 is 16 bytes in hex + 2 bytes for '0x' prefix
	buf := make([]byte, 18)

	// It's simpler to construct the hex string right to left.
	base := uint64(16)
	i := len(buf) - 1
	for num >= base {
		buf[i] = hexDigits[num%base]
		num /= base
		i--
	}
	buf[i] = hexDigits[num]

	// Add '0x' prefix.
	i--
	buf[i] = 'x'
	i--
	buf[i] = '0'

	// Strip unused leading bytes.
	buf = buf[i:]
	w.Write(buf)
}

// valuesSorter implements sort.Interface to allow a slice of reflect.Value
// elements to be sorted.
type valuesSorter struct {
	values  []reflect.Value
	strings []string // either nil or same len and values
	cs      *ConfigState
}

// newValuesSorter initializes a valuesSorter instance, which holds a set of
// surrogate keys on which the data should be sorted.  It uses flags in
// ConfigState to decide if and how to populate those surrogate keys.
func newValuesSorter(values []reflect.Value, cs *ConfigState) sort.Interface {
	vs := &valuesSorter{values: values, cs: cs}
	if canSortSimply(vs.values[0].Kind()) {
		return vs
	}
	if !cs.DisableMethods {
		vs.strings = make([]string, len(values))
		for i := range vs.values {
			b := bytes.Buffer{}
			if !handleMethods(cs, &b, vs.values[i]) {
				vs.strings = nil
				break
			}
			vs.strings[i] = b.String()
		}
	}
	if vs.strings == nil && cs.SpewKeys {
		vs.strings = make([]string, len(values))
		for i := range vs.values {
			vs.strings[i] = Sprintf("%#v", vs.values[i].Interface())
		}
	}
	return vs
}

// canSortSimply tests whether a reflect.Kind is a primitive that can be sorted
// directly, or whether it should be considered for sorting by surrogate keys
// (if the ConfigState allows it).
func canSortSimply(kind reflect.Kind) bool {
	// This switch parallels valueSortLess, except for the default case.
	switch kind {
	case reflect.Bool:
		return true
	case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int:
		return true
	case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint:
		return true
	case reflect.Float32, reflect.Float64:
		return true
	case reflect.String:
		return true
	case reflect.Uintptr:
		return true
	case reflect.Array:
		return true
	}
	return false
}

// Len returns the number of values in the slice.  It is part of the
// sort.Interface implementation.
func (s *valuesSorter) Len() int {
	return len(s.values)
}

// Swap swaps the values at the passed indices.  It is part of the
// sort.Interface implementation.
func (s *valuesSorter) Swap(i, j int) {
	s.values[i], s.values[j] = s.values[j], s.values[i]
	if s.strings != nil {
		s.strings[i], s.strings[j] = s.strings[j], s.strings[i]
	}
}

// valueSortLess returns whether the first value should sort before the second
// value.  It is used by valueSorter.Less as part of the sort.Interface
// implementation.
func valueSortLess(a, b reflect.Value) bool {
	switch a.Kind() {
	case reflect.Bool:
		return !a.Bool() && b.Bool()
	case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int:
		return a.Int() < b.Int()
	case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint:
		return a.Uint() < b.Uint()
	case reflect.Float32, reflect.Float64:
		return a.Float() < b.Float()
	case reflect.String:
		return a.String() < b.String()
	case reflect.Uintptr:
		return a.Uint() < b.Uint()
	case reflect.Array:
		// Compare the contents of both arrays.
		l := a.Len()
		for i := 0; i < l; i++ {
			av := a.Index(i)
			bv := b.Index(i)
			if av.Interface() == bv.Interface() {
				continue
			}
			return valueSortLess(av, bv)
		}
	}
	return a.String() < b.String()
}

// Less returns whether the value at index i should sort before the
// value at index j.  It is part of the sort.Interface implementation.
func (s *valuesSorter) Less(i, j int) bool {
	if s.strings == nil {
		return valueSortLess(s.values[i], s.values[j])
	}
	return s.strings[i] < s.strings[j]
}

// sortValues is a sort function that handles both native types and any type that
// can be converted to error or Stringer.  Other inputs are sorted according to
// their Value.String() value to ensure display stability.
func sortValues(values []reflect.Value, cs *ConfigState) {
	if len(values) == 0 {
		return
	}
	sort.Sort(newValuesSorter(values, cs))
}
<|endoftext|>


<commit_before>package frameworkgo

import "strings"

const routePattern string = "/"

type Params map[string]string

func (params Params) Get(key string) (string, bool) {
	value, ok := params[key]
	return value, ok
}

func cleanComponents(raw_components, pattern string) []string {
	var components []string = strings.Split(raw_components, pattern)

	var cleaned []string
	for _, c := range components {
		if strings.TrimSpace(c) != "" {
			cleaned = append(cleaned, c)
		}
	}

	return cleaned
}

//Extract url params and check if route match with path
func ParseParams(route Route, path string) (bool, Params) {
	var attrs []string
	var params Params = make(Params)

	var routeComponents []string = cleanComponents(route.path, routePattern)
	var pathComponents []string = cleanComponents(path, routePattern)

	if len(routeComponents) == len(pathComponents) {
		for _, s := range routeComponents {
			if len(s) > 0 && string(s[0]) == string(":") {
				attrs = append(attrs, s[1:])
			}
		}

		if route.rgx.MatchString(path) {
			var values []string = route.rgx.FindStringSubmatch(path)[1:]
			for i, v := range values {
				params[attrs[i]] = v
			}

			return true, params
		}
	}
	return false, params
}
<commit_msg>casted params helpers<commit_after>package frameworkgo

import (
	"strings"
	"strconv"
)

const routePattern string = "/"

type Params map[string]string

// Return attribute casted to int from Params if exists
func (p Params) GetInt(key string) (res int, exists bool) {
	var raw string
	if raw, exists = p[key]; exists {
		if res, e := strconv.Atoi(raw); e == nil {
			return res, true
		}
	}

	return res, false
}

// Return attribute casted to float from Params if exists
func (p Params) GetFloat(key string) (res float64, exists bool) {
	var raw string
	if raw, exists = p[key]; exists {
		if res, e := strconv.ParseFloat(raw, 64); e == nil {
			return res, true
		}
	}

	return res, false
}

// Return attribute casted to bool from Params if exists
func (p Params) GetBool(key string) (res bool, exists bool) {
	var raw string
	if raw, exists = p[key]; exists {
		if res, e := strconv.ParseBool(raw); e == nil {
			return res, true
		}
	}

	return res, false
}

// Return raw attribute from Params if exists
func (p Params) GetRaw(key string) (string, bool) {
	value, ok := p[key]
	return value, ok
}

func cleanComponents(raw_components, pattern string) []string {
	var components []string = strings.Split(raw_components, pattern)

	var cleaned []string
	for _, c := range components {
		if strings.TrimSpace(c) != "" {
			cleaned = append(cleaned, c)
		}
	}

	return cleaned
}

//Extract url params and check if route match with path
func ParseParams(route Route, path string) (bool, Params) {
	var attrs []string
	var params Params = make(Params)

	var routeComponents []string = cleanComponents(route.path, routePattern)
	var pathComponents []string = cleanComponents(path, routePattern)

	if len(routeComponents) == len(pathComponents) {
		for _, s := range routeComponents {
			if len(s) > 0 && string(s[0]) == string(":") {
				attrs = append(attrs, s[1:])
			}
		}

		if route.rgx.MatchString(path) {
			var values []string = route.rgx.FindStringSubmatch(path)[1:]
			for i, v := range values {
				params[attrs[i]] = v
			}

			return true, params
		}
	}
	return false, params
}
<|endoftext|>


<commit_before>package css

import (
	"fmt"
	"github.com/gorilla/css/scanner"
	"strings"
)

type State int

const (
	STATE_NONE State = iota
	STATE_SELECTOR
	STATE_DECLARE_BLOCK
	STATE_PROPERTY
	STATE_VALUE
)

type ParserContext struct {
	State           State
	NowSelectorText string
	NowProperty     string
	NowValue        string
	NowImportant    int
	NowRuleType     RuleType

	CurrentRule *CSSRule
}

func Parse(csstext string) *CSSStyleSheet {
	context := &ParserContext{
		State:           STATE_NONE,
		NowSelectorText: "",
		NowProperty:     "",
		NowValue:        "",
		NowImportant:    0,
		NowRuleType:     STYLE_RULE,
	}

	css := &CSSStyleSheet{}
	css.CssRuleList = make([]*CSSRule, 0)
	s := scanner.New(csstext)

	for {
		token := s.Next()

		fmt.Printf("%s:'%s'\n", token.Type.String(), token.Value)

		if token.Type == scanner.TokenEOF || token.Type == scanner.TokenError {
			break
		}

		switch token.Type {
		case scanner.TokenAtKeyword:
			context.State = STATE_SELECTOR
			switch token.Value {
			case "@media":
				context.NowRuleType = MEDIA_RULE
			}

		case scanner.TokenString:
			if context.State == STATE_SELECTOR {
				context.NowSelectorText += token.Value
			}
		case scanner.TokenURI:
		case scanner.TokenUnicodeRange:
		case scanner.TokenCDO:
		case scanner.TokenCDC:
		case scanner.TokenComment:
		case scanner.TokenIdent:

			if context.State == STATE_NONE || context.State == STATE_SELECTOR {
				context.State = STATE_SELECTOR
				context.NowSelectorText += strings.TrimSpace(token.Value)
				break
			}

			if context.State == STATE_DECLARE_BLOCK {
				context.State = STATE_PROPERTY
				context.NowProperty = strings.TrimSpace(token.Value)
				break
			}

			if context.State == STATE_VALUE {
				if token.Value == "important" {
					context.NowImportant = 1
				} else {
					context.NowValue = token.Value + " "
				}
				break
			}

		case scanner.TokenDimension:
			fallthrough
		case scanner.TokenS:
			if context.State == STATE_SELECTOR {
				context.NowSelectorText += token.Value
			} else if context.State == STATE_VALUE {
				context.NowValue += token.Value
			}

		case scanner.TokenChar:
			if context.State == STATE_NONE {
				if string('.') == token.Value {
					context.State = STATE_SELECTOR
					context.NowSelectorText += token.Value
					break
				}
			}
			if context.State == STATE_SELECTOR {
				if string('{') == token.Value {
					context.State = STATE_DECLARE_BLOCK
					context.CurrentRule = NewRule(context.NowRuleType)
					context.CurrentRule.Style.SelectorText = strings.TrimSpace(context.NowSelectorText)
					break
				} else {
					context.NowSelectorText += token.Value
				}
				break
			}

			if context.State == STATE_PROPERTY {
				if token.Value == ":" {
					context.State = STATE_VALUE
				}
				break
			}

			if context.State == STATE_DECLARE_BLOCK {
				if token.Value == "}" {
					css.CssRuleList = append(css.CssRuleList, context.CurrentRule)
					context.NowSelectorText = ""
					context.NowProperty = ""
					context.NowValue = ""
					context.NowImportant = 0
					context.NowRuleType = STYLE_RULE
					context.State = STATE_NONE
				}
				break
			}

			if context.State == STATE_VALUE {
				if token.Value == ";" {
					decl := NewCSSStyleDeclaration(context.NowProperty, strings.TrimSpace(context.NowValue), context.NowImportant)
					context.CurrentRule.Style.Styles[context.NowProperty] = decl

					context.NowProperty = ""
					context.NowValue = ""
					context.NowImportant = 0
					context.State = STATE_DECLARE_BLOCK
				} else if token.Value == "}" {
					decl := NewCSSStyleDeclaration(context.NowProperty, strings.TrimSpace(context.NowValue), context.NowImportant)
					context.CurrentRule.Style.Styles[context.NowProperty] = decl
					css.CssRuleList = append(css.CssRuleList, context.CurrentRule)
					context.NowSelectorText = ""
					context.NowProperty = ""
					context.NowValue = ""
					context.NowImportant = 0
					context.NowRuleType = STYLE_RULE
					context.State = STATE_NONE
				} else if token.Value != "!" {
						context.NowValue += token.Value
				}
				break

			}
		case scanner.TokenPercentage:
			fallthrough
		case scanner.TokenHash:
			if context.State == STATE_NONE || context.State == STATE_SELECTOR {
				context.State = STATE_SELECTOR
				context.NowSelectorText += strings.TrimSpace(token.Value)
				break
			}

			fallthrough
		case scanner.TokenNumber:
			fallthrough
		case scanner.TokenFunction:
			fallthrough
		case scanner.TokenIncludes:
			fallthrough
		case scanner.TokenDashMatch:
			fallthrough
		case scanner.TokenPrefixMatch:
			fallthrough
		case scanner.TokenSuffixMatch:
			fallthrough
		case scanner.TokenSubstringMatch:
			if context.State == STATE_VALUE {
				context.NowValue += token.Value
			}
		}
	}
	return css
}
<commit_msg>Consistent literal string<commit_after>package css

import (
	"fmt"
	"github.com/gorilla/css/scanner"
	"strings"
)

type State int

const (
	STATE_NONE State = iota
	STATE_SELECTOR
	STATE_DECLARE_BLOCK
	STATE_PROPERTY
	STATE_VALUE
)

type ParserContext struct {
	State           State
	NowSelectorText string
	NowProperty     string
	NowValue        string
	NowImportant    int
	NowRuleType     RuleType

	CurrentRule *CSSRule
}

func Parse(csstext string) *CSSStyleSheet {
	context := &ParserContext{
		State:           STATE_NONE,
		NowSelectorText: "",
		NowProperty:     "",
		NowValue:        "",
		NowImportant:    0,
		NowRuleType:     STYLE_RULE,
	}

	css := &CSSStyleSheet{}
	css.CssRuleList = make([]*CSSRule, 0)
	s := scanner.New(csstext)

	for {
		token := s.Next()

		fmt.Printf("%s:'%s'\n", token.Type.String(), token.Value)

		if token.Type == scanner.TokenEOF || token.Type == scanner.TokenError {
			break
		}

		switch token.Type {
		case scanner.TokenAtKeyword:
			context.State = STATE_SELECTOR
			switch token.Value {
			case "@media":
				context.NowRuleType = MEDIA_RULE
			}

		case scanner.TokenString:
			if context.State == STATE_SELECTOR {
				context.NowSelectorText += token.Value
			}
		case scanner.TokenURI:
		case scanner.TokenUnicodeRange:
		case scanner.TokenCDO:
		case scanner.TokenCDC:
		case scanner.TokenComment:
		case scanner.TokenIdent:

			if context.State == STATE_NONE || context.State == STATE_SELECTOR {
				context.State = STATE_SELECTOR
				context.NowSelectorText += strings.TrimSpace(token.Value)
				break
			}

			if context.State == STATE_DECLARE_BLOCK {
				context.State = STATE_PROPERTY
				context.NowProperty = strings.TrimSpace(token.Value)
				break
			}

			if context.State == STATE_VALUE {
				if token.Value == "important" {
					context.NowImportant = 1
				} else {
					context.NowValue = token.Value + " "
				}
				break
			}

		case scanner.TokenDimension:
			fallthrough
		case scanner.TokenS:
			if context.State == STATE_SELECTOR {
				context.NowSelectorText += token.Value
			} else if context.State == STATE_VALUE {
				context.NowValue += token.Value
			}

		case scanner.TokenChar:
			if context.State == STATE_NONE {
				if "." == token.Value {
					context.State = STATE_SELECTOR
					context.NowSelectorText += token.Value
					break
				}
			}
			if context.State == STATE_SELECTOR {
				if "{" == token.Value {
					context.State = STATE_DECLARE_BLOCK
					context.CurrentRule = NewRule(context.NowRuleType)
					context.CurrentRule.Style.SelectorText = strings.TrimSpace(context.NowSelectorText)
					break
				} else {
					context.NowSelectorText += token.Value
				}
				break
			}

			if context.State == STATE_PROPERTY {
				if token.Value == ":" {
					context.State = STATE_VALUE
				}
				break
			}

			if context.State == STATE_DECLARE_BLOCK {
				if token.Value == "}" {
					css.CssRuleList = append(css.CssRuleList, context.CurrentRule)
					context.NowSelectorText = ""
					context.NowProperty = ""
					context.NowValue = ""
					context.NowImportant = 0
					context.NowRuleType = STYLE_RULE
					context.State = STATE_NONE
				}
				break
			}

			if context.State == STATE_VALUE {
				if token.Value == ";" {
					decl := NewCSSStyleDeclaration(context.NowProperty, strings.TrimSpace(context.NowValue), context.NowImportant)
					context.CurrentRule.Style.Styles[context.NowProperty] = decl

					context.NowProperty = ""
					context.NowValue = ""
					context.NowImportant = 0
					context.State = STATE_DECLARE_BLOCK
				} else if token.Value == "}" { // last property in a block can have optional ;
					decl := NewCSSStyleDeclaration(context.NowProperty, strings.TrimSpace(context.NowValue), context.NowImportant)
					context.CurrentRule.Style.Styles[context.NowProperty] = decl
					css.CssRuleList = append(css.CssRuleList, context.CurrentRule)
					context.NowSelectorText = ""
					context.NowProperty = ""
					context.NowValue = ""
					context.NowImportant = 0
					context.NowRuleType = STYLE_RULE
					context.State = STATE_NONE
				} else if token.Value != "!" {
						context.NowValue += token.Value
				}
				break

			}
		case scanner.TokenPercentage:
			fallthrough
		case scanner.TokenHash:
			if context.State == STATE_NONE || context.State == STATE_SELECTOR {
				context.State = STATE_SELECTOR
				context.NowSelectorText += strings.TrimSpace(token.Value)
				break
			}

			fallthrough
		case scanner.TokenNumber:
			fallthrough
		case scanner.TokenFunction:
			fallthrough
		case scanner.TokenIncludes:
			fallthrough
		case scanner.TokenDashMatch:
			fallthrough
		case scanner.TokenPrefixMatch:
			fallthrough
		case scanner.TokenSuffixMatch:
			fallthrough
		case scanner.TokenSubstringMatch:
			if context.State == STATE_VALUE {
				context.NowValue += token.Value
			}
		}
	}
	return css
}
<|endoftext|>


<commit_before>// Copyright 2012 Jesse van den Kieboom. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package flags

import (
	"os"
	"path"
)

// A Parser provides command line option parsing. It can contain several
// option groups each with their own set of options.
type Parser struct {
	// Embedded, see Command for more information
	*Command

	// A usage string to be displayed in the help message.
	Usage string

	// Option flags changing the behavior of the parser.
	Options Options

	// NamespaceDelimiter separates group namespaces and option long names
	NamespaceDelimiter string

	internalError error
}

// Options provides parser options that change the behavior of the option
// parser.
type Options uint

const (
	// None indicates no options.
	None Options = 0

	// HelpFlag adds a default Help Options group to the parser containing
	// -h and --help options. When either -h or --help is specified on the
	// command line, the parser will return the special error of type
	// ErrHelp. When PrintErrors is also specified, then the help message
	// will also be automatically printed to os.Stderr.
	HelpFlag = 1 << iota

	// PassDoubleDash passes all arguments after a double dash, --, as
	// remaining command line arguments (i.e. they will not be parsed for
	// flags).
	PassDoubleDash

	// IgnoreUnknown ignores any unknown options and passes them as
	// remaining command line arguments instead of generating an error.
	IgnoreUnknown

	// PrintErrors prints any errors which occurred during parsing to
	// os.Stderr.
	PrintErrors

	// PassAfterNonOption passes all arguments after the first non option
	// as remaining command line arguments. This is equivalent to strict
	// POSIX processing.
	PassAfterNonOption

	// Default is a convenient default set of options which should cover
	// most of the uses of the flags package.
	Default = HelpFlag | PrintErrors | PassDoubleDash
)

// Parse is a convenience function to parse command line options with default
// settings. The provided data is a pointer to a struct representing the
// default option group (named "Application Options"). For more control, use
// flags.NewParser.
func Parse(data interface{}) ([]string, error) {
	return NewParser(data, Default).Parse()
}

// ParseArgs is a convenience function to parse command line options with default
// settings. The provided data is a pointer to a struct representing the
// default option group (named "Application Options"). The args argument is
// the list of command line arguments to parse. If you just want to parse the
// default program command line arguments (i.e. os.Args), then use flags.Parse
// instead. For more control, use flags.NewParser.
func ParseArgs(data interface{}, args []string) ([]string, error) {
	return NewParser(data, Default).ParseArgs(args)
}

// NewParser creates a new parser. It uses os.Args[0] as the application
// name and then calls Parser.NewNamedParser (see Parser.NewNamedParser for
// more details). The provided data is a pointer to a struct representing the
// default option group (named "Application Options"), or nil if the default
// group should not be added. The options parameter specifies a set of options
// for the parser.
func NewParser(data interface{}, options Options) *Parser {
	p := NewNamedParser(path.Base(os.Args[0]), options)

	if data != nil {
		g, err := p.AddGroup("Application Options", "", data)

		if err == nil {
			g.parent = p
		}

		p.internalError = err
	}

	return p
}

// NewNamedParser creates a new parser. The appname is used to display the
// executable name in the built-in help message. Option groups and commands can
// be added to this parser by using AddGroup and AddCommand.
func NewNamedParser(appname string, options Options) *Parser {
	p := &Parser{
		Command:            newCommand(appname, "", "", nil),
		Options:            options,
		NamespaceDelimiter: ".",
	}

	p.Command.parent = p

	if len(os.Getenv("GO_FLAGS_COMPLETION")) != 0 {
		p.AddCommand("__complete", "completion", "automatic flags completion", &completion{parser: p})

		p.Options |= PassDoubleDash
	}

	return p
}

// Parse parses the command line arguments from os.Args using Parser.ParseArgs.
// For more detailed information see ParseArgs.
func (p *Parser) Parse() ([]string, error) {
	return p.ParseArgs(os.Args[1:])
}

// ParseArgs parses the command line arguments according to the option groups that
// were added to the parser. On successful parsing of the arguments, the
// remaining, non-option, arguments (if any) are returned. The returned error
// indicates a parsing error and can be used with PrintError to display
// contextual information on where the error occurred exactly.
//
// When the common help group has been added (AddHelp) and either -h or --help
// was specified in the command line arguments, a help message will be
// automatically printed. Furthermore, the special error type ErrHelp is returned.
// It is up to the caller to exit the program if so desired.
func (p *Parser) ParseArgs(args []string) ([]string, error) {
	if p.internalError != nil {
		return nil, p.internalError
	}

	p.clearIsSet()

	// Add built-in help group to all commands if necessary
	if (p.Options & HelpFlag) != None {
		p.addHelpGroups(p.showBuiltinHelp)
	}

	s := &parseState{
		args:    args,
		retargs: make([]string, 0, len(args)),
	}

	p.fillParseState(s)

	for !s.eof() {
		arg := s.pop()

		// When PassDoubleDash is set and we encounter a --, then
		// simply append all the rest as arguments and break out
		if (p.Options&PassDoubleDash) != None && arg == "--" {
			s.addArgs(s.args...)
			break
		}

		if !argumentIsOption(arg) {
			// Note: this also sets s.err, so we can just check for
			// nil here and use s.err later
			if p.parseNonOption(s) != nil {
				break
			}

			continue
		}

		var err error

		prefix, optname, islong := stripOptionPrefix(arg)
		optname, _, argument := splitOption(prefix, optname, islong)

		if islong {
			err = p.parseLong(s, optname, argument)
		} else {
			err = p.parseShort(s, optname, argument)
		}

		if err != nil {
			ignoreUnknown := (p.Options & IgnoreUnknown) != None
			parseErr := wrapError(err)

			if !(parseErr.Type == ErrUnknownFlag && ignoreUnknown) {
				s.err = parseErr
				break
			}

			if ignoreUnknown {
				s.addArgs(arg)
			}
		}
	}

	if s.err == nil {
		p.eachCommand(func(c *Command) {
			c.eachGroup(func(g *Group) {
				for _, option := range g.options {
					if option.isSet {
						continue
					}

					option.clearDefault()
				}
			})
		}, true)

		s.checkRequired(p)
	}

	var reterr error

	if s.err != nil {
		reterr = p.printError(s.err)
	} else if len(s.command.commands) != 0 && !s.command.SubcommandsOptional {
		reterr = p.printError(s.estimateCommand())
	} else if cmd, ok := s.command.data.(Commander); ok {
		reterr = p.printError(cmd.Execute(s.retargs))
	}

	if reterr != nil {
		return append([]string{s.arg}, s.args...), reterr
	}

	return s.retargs, nil
}
<commit_msg>refactor completion into Parser.ParseArgs<commit_after>// Copyright 2012 Jesse van den Kieboom. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package flags

import (
	"os"
	"path"
)

// A Parser provides command line option parsing. It can contain several
// option groups each with their own set of options.
type Parser struct {
	// Embedded, see Command for more information
	*Command

	// A usage string to be displayed in the help message.
	Usage string

	// Option flags changing the behavior of the parser.
	Options Options

	// NamespaceDelimiter separates group namespaces and option long names
	NamespaceDelimiter string

	internalError error
}

// Options provides parser options that change the behavior of the option
// parser.
type Options uint

const (
	// None indicates no options.
	None Options = 0

	// HelpFlag adds a default Help Options group to the parser containing
	// -h and --help options. When either -h or --help is specified on the
	// command line, the parser will return the special error of type
	// ErrHelp. When PrintErrors is also specified, then the help message
	// will also be automatically printed to os.Stderr.
	HelpFlag = 1 << iota

	// PassDoubleDash passes all arguments after a double dash, --, as
	// remaining command line arguments (i.e. they will not be parsed for
	// flags).
	PassDoubleDash

	// IgnoreUnknown ignores any unknown options and passes them as
	// remaining command line arguments instead of generating an error.
	IgnoreUnknown

	// PrintErrors prints any errors which occurred during parsing to
	// os.Stderr.
	PrintErrors

	// PassAfterNonOption passes all arguments after the first non option
	// as remaining command line arguments. This is equivalent to strict
	// POSIX processing.
	PassAfterNonOption

	// Default is a convenient default set of options which should cover
	// most of the uses of the flags package.
	Default = HelpFlag | PrintErrors | PassDoubleDash
)

// Parse is a convenience function to parse command line options with default
// settings. The provided data is a pointer to a struct representing the
// default option group (named "Application Options"). For more control, use
// flags.NewParser.
func Parse(data interface{}) ([]string, error) {
	return NewParser(data, Default).Parse()
}

// ParseArgs is a convenience function to parse command line options with default
// settings. The provided data is a pointer to a struct representing the
// default option group (named "Application Options"). The args argument is
// the list of command line arguments to parse. If you just want to parse the
// default program command line arguments (i.e. os.Args), then use flags.Parse
// instead. For more control, use flags.NewParser.
func ParseArgs(data interface{}, args []string) ([]string, error) {
	return NewParser(data, Default).ParseArgs(args)
}

// NewParser creates a new parser. It uses os.Args[0] as the application
// name and then calls Parser.NewNamedParser (see Parser.NewNamedParser for
// more details). The provided data is a pointer to a struct representing the
// default option group (named "Application Options"), or nil if the default
// group should not be added. The options parameter specifies a set of options
// for the parser.
func NewParser(data interface{}, options Options) *Parser {
	p := NewNamedParser(path.Base(os.Args[0]), options)

	if data != nil {
		g, err := p.AddGroup("Application Options", "", data)

		if err == nil {
			g.parent = p
		}

		p.internalError = err
	}

	return p
}

// NewNamedParser creates a new parser. The appname is used to display the
// executable name in the built-in help message. Option groups and commands can
// be added to this parser by using AddGroup and AddCommand.
func NewNamedParser(appname string, options Options) *Parser {
	p := &Parser{
		Command:            newCommand(appname, "", "", nil),
		Options:            options,
		NamespaceDelimiter: ".",
	}

	p.Command.parent = p

	return p
}

// Parse parses the command line arguments from os.Args using Parser.ParseArgs.
// For more detailed information see ParseArgs.
func (p *Parser) Parse() ([]string, error) {
	return p.ParseArgs(os.Args[1:])
}

// ParseArgs parses the command line arguments according to the option groups that
// were added to the parser. On successful parsing of the arguments, the
// remaining, non-option, arguments (if any) are returned. The returned error
// indicates a parsing error and can be used with PrintError to display
// contextual information on where the error occurred exactly.
//
// When the common help group has been added (AddHelp) and either -h or --help
// was specified in the command line arguments, a help message will be
// automatically printed. Furthermore, the special error type ErrHelp is returned.
// It is up to the caller to exit the program if so desired.
func (p *Parser) ParseArgs(args []string) ([]string, error) {
	if p.internalError != nil {
		return nil, p.internalError
	}

	p.clearIsSet()

	// Add built-in help group to all commands if necessary
	if (p.Options & HelpFlag) != None {
		p.addHelpGroups(p.showBuiltinHelp)
	}

	if len(os.Getenv("GO_FLAGS_COMPLETION")) != 0 {
		comp := &completion{parser: p}

		reterr := comp.Execute(args)

		return args, p.printError(reterr)
	}

	s := &parseState{
		args:    args,
		retargs: make([]string, 0, len(args)),
	}

	p.fillParseState(s)

	for !s.eof() {
		arg := s.pop()

		// When PassDoubleDash is set and we encounter a --, then
		// simply append all the rest as arguments and break out
		if (p.Options&PassDoubleDash) != None && arg == "--" {
			s.addArgs(s.args...)
			break
		}

		if !argumentIsOption(arg) {
			// Note: this also sets s.err, so we can just check for
			// nil here and use s.err later
			if p.parseNonOption(s) != nil {
				break
			}

			continue
		}

		var err error

		prefix, optname, islong := stripOptionPrefix(arg)
		optname, _, argument := splitOption(prefix, optname, islong)

		if islong {
			err = p.parseLong(s, optname, argument)
		} else {
			err = p.parseShort(s, optname, argument)
		}

		if err != nil {
			ignoreUnknown := (p.Options & IgnoreUnknown) != None
			parseErr := wrapError(err)

			if !(parseErr.Type == ErrUnknownFlag && ignoreUnknown) {
				s.err = parseErr
				break
			}

			if ignoreUnknown {
				s.addArgs(arg)
			}
		}
	}

	if s.err == nil {
		p.eachCommand(func(c *Command) {
			c.eachGroup(func(g *Group) {
				for _, option := range g.options {
					if option.isSet {
						continue
					}

					option.clearDefault()
				}
			})
		}, true)

		s.checkRequired(p)
	}

	var reterr error

	if s.err != nil {
		reterr = p.printError(s.err)
	} else if len(s.command.commands) != 0 && !s.command.SubcommandsOptional {
		reterr = p.printError(s.estimateCommand())
	} else if cmd, ok := s.command.data.(Commander); ok {
		reterr = p.printError(cmd.Execute(s.retargs))
	}

	if reterr != nil {
		return append([]string{s.arg}, s.args...), reterr
	}

	return s.retargs, nil
}
<|endoftext|>


<commit_before>package php

import (
	"fmt"

	"stephensearles.com/php/ast"
	"stephensearles.com/php/token"
)

// Parser handles scanning through and parsing a PHP source string into an AST. It is configurable
// to have various types of debugging features.
type Parser struct {
	Debug       bool // Debug causes the parser to print all errors to stdout and relay any panic upon internal panic recovery.
	PrintTokens bool // PrintTokens causes the parser to print all tokens received from the lexer to stdout.
	MaxErrors   int  // Indicates the number of errors to allow before triggering a panic. The default is 10.

	lexer      *lexer
	previous   []Item
	idx        int
	current    Item
	errors     []error
	parenLevel int
	errorMap   map[int]bool
	errorCount int

	instantiation bool
}

// NewParser readies a parser object for the given input string.
func NewParser(input string) *Parser {
	p := &Parser{
		idx:       -1,
		MaxErrors: 10,
		lexer:     newLexer(input),
		errorMap:  make(map[int]bool),
	}
	return p
}

// Parse consumes the input string to produce an AST that represents it.
func (p *Parser) Parse() (nodes []ast.Node, errors []error) {
	defer func() {
		if r := recover(); r != nil {
			errors = append([]error{fmt.Errorf("%s", r)}, p.errors...)
			if p.Debug {
				for _, err := range p.errors {
					fmt.Println(err)
				}
				panic(r)
			}
		}
	}()
	// expecting either token.HTML or token.PHPBegin
	nodes = make([]ast.Node, 0, 1)
TokenLoop:
	for {
		p.next()
		switch p.current.typ {
		case token.EOF:
			break TokenLoop
		default:
			n := p.parseNode()
			if n != nil {
				nodes = append(nodes, n)
			}
		}
	}
	errors = p.errors
	return nodes, errors
}

func (p *Parser) parseNode() ast.Node {
	switch p.current.typ {
	case token.HTML:
		return ast.Echo(ast.Literal{Type: ast.String, Value: p.current.val})
	case token.PHPBegin:
		return nil
	case token.PHPEnd:
		return nil
	}
	return p.parseStmt()
}

func (p *Parser) next() {
	p.idx += 1
	if len(p.previous) <= p.idx {
		p.current = p.lexer.nextItem()
		if p.PrintTokens {
			fmt.Println(p.current)
		}
		p.previous = append(p.previous, p.current)
	} else {
		p.current = p.previous[p.idx]
	}
}

func (p *Parser) backup() {
	p.idx -= 1
	p.current = p.previous[p.idx]
}

func (p *Parser) peek() (i Item) {
	p.next()
	i = p.current
	p.backup()
	return
}

func (p *Parser) expectCurrent(i ...token.Token) {
	for _, typ := range i {
		if p.current.typ == typ {
			return
		}
	}
	p.expected(i...)
}

func (p *Parser) expectAndNext(i ...token.Token) {
	defer p.next()
	for _, typ := range i {
		if p.current.typ == typ {
			return
		}
	}
	p.expected(i...)
}

func (p *Parser) expect(i ...token.Token) {
	p.next()
	p.expectCurrent(i...)
}

func (p *Parser) expected(i ...token.Token) {
	p.errorf("Found %s, expected %s", p.current, i)
}

func (p *Parser) errorf(str string, args ...interface{}) {
	if p.errorCount > p.MaxErrors {
		panic("too many errors")
	}
	if _, ok := p.errorMap[p.current.pos.Line]; ok {
		return
	}
	errString := fmt.Sprintf(str, args...)
	p.errorCount += 1
	p.errors = append(p.errors, fmt.Errorf("%s: %s", p.errorPrefix(), errString))
	p.errorMap[p.current.pos.Line] = true
}

func (p *Parser) errorPrefix() string {
	return fmt.Sprintf("%s %d", p.lexer.file, p.current.pos.Line)
}

func (p *Parser) parseNextExpression() ast.Expression {
	p.next()
	return p.parseExpression()
}

func (p *Parser) parseStmt() ast.Statement {
	switch p.current.typ {
	case token.BlockBegin:
		p.backup()
		return p.parseBlock()
	case token.Global:
		p.next()
		g := &ast.GlobalDeclaration{
			Identifiers: make([]*ast.Variable, 0, 1),
		}
		for p.current.typ == token.VariableOperator {
			variable, ok := p.parseVariable().(*ast.Variable)
			if !ok {
				p.errorf("global declarations must be of standard variables")
				break
			}
			g.Identifiers = append(g.Identifiers, variable)
			if p.peek().typ != token.Comma {
				break
			}
			p.expect(token.Comma)
			p.next()
		}
		p.expectStmtEnd()
		return g
	case token.Namespace:
		p.expect(token.Identifier)
		p.expectStmtEnd()
		// We are ignoring this for now
		return nil
	case token.Use:
		p.expect(token.Identifier)
		if p.peek().typ == token.AsOperator {
			p.expect(token.AsOperator)
			p.expect(token.Identifier)
		}
		p.expectStmtEnd()
		// We are ignoring this for now
		return nil
	case token.VariableOperator, token.UnaryOperator:
		expr := ast.ExpressionStmt{p.parseExpression()}
		p.expectStmtEnd()
		return expr
	case token.Function:
		return p.parseFunctionStmt()
	case token.PHPEnd:
		if p.peek().typ == token.EOF {
			return nil
		}
		p.expect(token.HTML)
		expr := ast.Echo(&ast.Literal{Type: ast.String, Value: p.current.val})
		p.next()
		if p.current.typ != token.EOF {
			p.expectCurrent(token.PHPBegin)
		}
		return expr
	case token.Echo:
		exprs := []ast.Expression{
			p.parseNextExpression(),
		}
		for p.peek().typ == token.Comma {
			p.expect(token.Comma)
			exprs = append(exprs, p.parseNextExpression())
		}
		p.expectStmtEnd()
		return ast.Echo(exprs...)
	case token.If:
		return p.parseIf()
	case token.While:
		return p.parseWhile()
	case token.Do:
		return p.parseDo()
	case token.For:
		return p.parseFor()
	case token.Foreach:
		return p.parseForeach()
	case token.Switch:
		return p.parseSwitch()
	case token.Abstract, token.Final, token.Class:
		return p.parseClass()
	case token.Interface:
		return p.parseInterface()
	case token.Return:
		p.next()
		stmt := ast.ReturnStmt{}
		if p.current.typ != token.StatementEnd {
			stmt.Expression = p.parseExpression()
			p.expectStmtEnd()
		}
		return stmt
	case token.Break:
		p.next()
		stmt := ast.BreakStmt{}
		if p.current.typ != token.StatementEnd {
			stmt.Expression = p.parseExpression()
			p.expectStmtEnd()
		}
		return stmt
	case token.Continue:
		p.next()
		stmt := ast.ContinueStmt{}
		if p.current.typ != token.StatementEnd {
			stmt.Expression = p.parseExpression()
			p.expectStmtEnd()
		}
		return stmt
	case token.Throw:
		stmt := ast.ThrowStmt{Expression: p.parseNextExpression()}
		p.expectStmtEnd()
		return stmt
	case token.Exit:
		stmt := ast.ExitStmt{}
		if p.peek().typ == token.OpenParen {
			p.expect(token.OpenParen)
			if p.peek().typ != token.CloseParen {
				stmt.Expression = p.parseNextExpression()
			}
			p.expect(token.CloseParen)
		}
		p.expectStmtEnd()
		return stmt
	case token.Try:
		stmt := &ast.TryStmt{}
		stmt.TryBlock = p.parseBlock()
		for p.expect(token.Catch); p.current.typ == token.Catch; p.next() {
			caught := &ast.CatchStmt{}
			p.expect(token.OpenParen)
			p.expect(token.Identifier)
			caught.CatchType = p.current.val
			p.expect(token.VariableOperator)
			p.expect(token.Identifier)
			caught.CatchVar = ast.NewVariable(p.current.val)
			p.expect(token.CloseParen)
			caught.CatchBlock = p.parseBlock()
			stmt.CatchStmts = append(stmt.CatchStmts, caught)
		}
		p.backup()
		return stmt
	case token.IgnoreErrorOperator:
		// Ignore this operator
		p.next()
		return p.parseStmt()
	case token.StatementEnd:
		// this is an empty statement
		p.next()
		return p.parseStmt()
	default:
		expr := p.parseExpression()
		if expr != nil {
			p.expectStmtEnd()
			return ast.ExpressionStmt{expr}
		}
		p.errorf("Found %s, statement or expression", p.current)
		return nil
	}
}

func (p *Parser) expectStmtEnd() {
	if p.peek().typ != token.PHPEnd {
		p.expect(token.StatementEnd)
	}
}

func (p *Parser) parseBlock() *ast.Block {
	p.expect(token.BlockBegin)
	b := p.parseStatementsUntil(token.BlockEnd)
	p.expectCurrent(token.BlockEnd)
	return b
}

func (p *Parser) parseStatementsUntil(endTokens ...token.Token) *ast.Block {
	block := &ast.Block{}
	breakTypes := map[token.Token]bool{}
	for _, typ := range endTokens {
		breakTypes[typ] = true
	}
	for {
		p.next()
		if _, ok := breakTypes[p.current.typ]; ok {
			break
		}
		stmt := p.parseStmt()
		if stmt == nil {
			return block
		}
		block.Statements = append(block.Statements, stmt)
	}
	return block
}

func (p *Parser) parseExpressionsUntil(separator token.Token, endTokens ...token.Token) []ast.Expression {
	exprs := make([]ast.Expression, 0, 1)
	breakTypes := map[token.Token]bool{}
	for _, typ := range endTokens {
		breakTypes[typ] = true
	}
	p.next()
	first := true
	for {
		if _, ok := breakTypes[p.current.typ]; ok {
			break
		} else if first {
			first = false
		} else {
			p.expectCurrent(separator)
			p.next()
		}
		expr := p.parseExpression()
		if expr == nil {
			return exprs
		}
		exprs = append(exprs, expr)
		p.next()
	}
	return exprs
}
<commit_msg>Ignoring empty statements at the end of a file also<commit_after>package php

import (
	"fmt"

	"stephensearles.com/php/ast"
	"stephensearles.com/php/token"
)

// Parser handles scanning through and parsing a PHP source string into an AST. It is configurable
// to have various types of debugging features.
type Parser struct {
	Debug       bool // Debug causes the parser to print all errors to stdout and relay any panic upon internal panic recovery.
	PrintTokens bool // PrintTokens causes the parser to print all tokens received from the lexer to stdout.
	MaxErrors   int  // Indicates the number of errors to allow before triggering a panic. The default is 10.

	lexer      *lexer
	previous   []Item
	idx        int
	current    Item
	errors     []error
	parenLevel int
	errorMap   map[int]bool
	errorCount int

	instantiation bool
}

// NewParser readies a parser object for the given input string.
func NewParser(input string) *Parser {
	p := &Parser{
		idx:       -1,
		MaxErrors: 10,
		lexer:     newLexer(input),
		errorMap:  make(map[int]bool),
	}
	return p
}

// Parse consumes the input string to produce an AST that represents it.
func (p *Parser) Parse() (nodes []ast.Node, errors []error) {
	defer func() {
		if r := recover(); r != nil {
			errors = append([]error{fmt.Errorf("%s", r)}, p.errors...)
			if p.Debug {
				for _, err := range p.errors {
					fmt.Println(err)
				}
				panic(r)
			}
		}
	}()
	// expecting either token.HTML or token.PHPBegin
	nodes = make([]ast.Node, 0, 1)
TokenLoop:
	for {
		p.next()
		switch p.current.typ {
		case token.EOF:
			break TokenLoop
		default:
			n := p.parseNode()
			if n != nil {
				nodes = append(nodes, n)
			}
		}
	}
	errors = p.errors
	return nodes, errors
}

func (p *Parser) parseNode() ast.Node {
	switch p.current.typ {
	case token.HTML:
		return ast.Echo(ast.Literal{Type: ast.String, Value: p.current.val})
	case token.PHPBegin:
		return nil
	case token.PHPEnd:
		return nil
	}
	return p.parseStmt()
}

func (p *Parser) next() {
	p.idx += 1
	if len(p.previous) <= p.idx {
		p.current = p.lexer.nextItem()
		if p.PrintTokens {
			fmt.Println(p.current)
		}
		p.previous = append(p.previous, p.current)
	} else {
		p.current = p.previous[p.idx]
	}
}

func (p *Parser) backup() {
	p.idx -= 1
	p.current = p.previous[p.idx]
}

func (p *Parser) peek() (i Item) {
	p.next()
	i = p.current
	p.backup()
	return
}

func (p *Parser) expectCurrent(i ...token.Token) {
	for _, typ := range i {
		if p.current.typ == typ {
			return
		}
	}
	p.expected(i...)
}

func (p *Parser) expectAndNext(i ...token.Token) {
	defer p.next()
	for _, typ := range i {
		if p.current.typ == typ {
			return
		}
	}
	p.expected(i...)
}

func (p *Parser) expect(i ...token.Token) {
	p.next()
	p.expectCurrent(i...)
}

func (p *Parser) expected(i ...token.Token) {
	p.errorf("Found %s, expected %s", p.current, i)
}

func (p *Parser) errorf(str string, args ...interface{}) {
	if p.errorCount > p.MaxErrors {
		panic("too many errors")
	}
	if _, ok := p.errorMap[p.current.pos.Line]; ok {
		return
	}
	errString := fmt.Sprintf(str, args...)
	p.errorCount += 1
	p.errors = append(p.errors, fmt.Errorf("%s: %s", p.errorPrefix(), errString))
	p.errorMap[p.current.pos.Line] = true
}

func (p *Parser) errorPrefix() string {
	return fmt.Sprintf("%s %d", p.lexer.file, p.current.pos.Line)
}

func (p *Parser) parseNextExpression() ast.Expression {
	p.next()
	return p.parseExpression()
}

func (p *Parser) parseStmt() ast.Statement {
	switch p.current.typ {
	case token.BlockBegin:
		p.backup()
		return p.parseBlock()
	case token.Global:
		p.next()
		g := &ast.GlobalDeclaration{
			Identifiers: make([]*ast.Variable, 0, 1),
		}
		for p.current.typ == token.VariableOperator {
			variable, ok := p.parseVariable().(*ast.Variable)
			if !ok {
				p.errorf("global declarations must be of standard variables")
				break
			}
			g.Identifiers = append(g.Identifiers, variable)
			if p.peek().typ != token.Comma {
				break
			}
			p.expect(token.Comma)
			p.next()
		}
		p.expectStmtEnd()
		return g
	case token.Namespace:
		p.expect(token.Identifier)
		p.expectStmtEnd()
		// We are ignoring this for now
		return nil
	case token.Use:
		p.expect(token.Identifier)
		if p.peek().typ == token.AsOperator {
			p.expect(token.AsOperator)
			p.expect(token.Identifier)
		}
		p.expectStmtEnd()
		// We are ignoring this for now
		return nil
	case token.VariableOperator, token.UnaryOperator:
		expr := ast.ExpressionStmt{p.parseExpression()}
		p.expectStmtEnd()
		return expr
	case token.Function:
		return p.parseFunctionStmt()
	case token.PHPEnd:
		if p.peek().typ == token.EOF {
			return nil
		}
		p.expect(token.HTML)
		expr := ast.Echo(&ast.Literal{Type: ast.String, Value: p.current.val})
		p.next()
		if p.current.typ != token.EOF {
			p.expectCurrent(token.PHPBegin)
		}
		return expr
	case token.Echo:
		exprs := []ast.Expression{
			p.parseNextExpression(),
		}
		for p.peek().typ == token.Comma {
			p.expect(token.Comma)
			exprs = append(exprs, p.parseNextExpression())
		}
		p.expectStmtEnd()
		return ast.Echo(exprs...)
	case token.If:
		return p.parseIf()
	case token.While:
		return p.parseWhile()
	case token.Do:
		return p.parseDo()
	case token.For:
		return p.parseFor()
	case token.Foreach:
		return p.parseForeach()
	case token.Switch:
		return p.parseSwitch()
	case token.Abstract, token.Final, token.Class:
		return p.parseClass()
	case token.Interface:
		return p.parseInterface()
	case token.Return:
		p.next()
		stmt := ast.ReturnStmt{}
		if p.current.typ != token.StatementEnd {
			stmt.Expression = p.parseExpression()
			p.expectStmtEnd()
		}
		return stmt
	case token.Break:
		p.next()
		stmt := ast.BreakStmt{}
		if p.current.typ != token.StatementEnd {
			stmt.Expression = p.parseExpression()
			p.expectStmtEnd()
		}
		return stmt
	case token.Continue:
		p.next()
		stmt := ast.ContinueStmt{}
		if p.current.typ != token.StatementEnd {
			stmt.Expression = p.parseExpression()
			p.expectStmtEnd()
		}
		return stmt
	case token.Throw:
		stmt := ast.ThrowStmt{Expression: p.parseNextExpression()}
		p.expectStmtEnd()
		return stmt
	case token.Exit:
		stmt := ast.ExitStmt{}
		if p.peek().typ == token.OpenParen {
			p.expect(token.OpenParen)
			if p.peek().typ != token.CloseParen {
				stmt.Expression = p.parseNextExpression()
			}
			p.expect(token.CloseParen)
		}
		p.expectStmtEnd()
		return stmt
	case token.Try:
		stmt := &ast.TryStmt{}
		stmt.TryBlock = p.parseBlock()
		for p.expect(token.Catch); p.current.typ == token.Catch; p.next() {
			caught := &ast.CatchStmt{}
			p.expect(token.OpenParen)
			p.expect(token.Identifier)
			caught.CatchType = p.current.val
			p.expect(token.VariableOperator)
			p.expect(token.Identifier)
			caught.CatchVar = ast.NewVariable(p.current.val)
			p.expect(token.CloseParen)
			caught.CatchBlock = p.parseBlock()
			stmt.CatchStmts = append(stmt.CatchStmts, caught)
		}
		p.backup()
		return stmt
	case token.IgnoreErrorOperator:
		// Ignore this operator
		p.next()
		return p.parseStmt()
	case token.StatementEnd:
		// this is an empty statement
		if p.peek().typ == token.EOF {
			return nil
		}
		p.next()
		return p.parseStmt()
	default:
		expr := p.parseExpression()
		if expr != nil {
			p.expectStmtEnd()
			return ast.ExpressionStmt{expr}
		}
		p.errorf("Found %s, statement or expression", p.current)
		return nil
	}
}

func (p *Parser) expectStmtEnd() {
	if p.peek().typ != token.PHPEnd {
		p.expect(token.StatementEnd)
	}
}

func (p *Parser) parseBlock() *ast.Block {
	p.expect(token.BlockBegin)
	b := p.parseStatementsUntil(token.BlockEnd)
	p.expectCurrent(token.BlockEnd)
	return b
}

func (p *Parser) parseStatementsUntil(endTokens ...token.Token) *ast.Block {
	block := &ast.Block{}
	breakTypes := map[token.Token]bool{}
	for _, typ := range endTokens {
		breakTypes[typ] = true
	}
	for {
		p.next()
		if _, ok := breakTypes[p.current.typ]; ok {
			break
		}
		stmt := p.parseStmt()
		if stmt == nil {
			return block
		}
		block.Statements = append(block.Statements, stmt)
	}
	return block
}

func (p *Parser) parseExpressionsUntil(separator token.Token, endTokens ...token.Token) []ast.Expression {
	exprs := make([]ast.Expression, 0, 1)
	breakTypes := map[token.Token]bool{}
	for _, typ := range endTokens {
		breakTypes[typ] = true
	}
	p.next()
	first := true
	for {
		if _, ok := breakTypes[p.current.typ]; ok {
			break
		} else if first {
			first = false
		} else {
			p.expectCurrent(separator)
			p.next()
		}
		expr := p.parseExpression()
		if expr == nil {
			return exprs
		}
		exprs = append(exprs, expr)
		p.next()
	}
	return exprs
}
<|endoftext|>