<commit_before>package glm

import (
	"fmt"
	"math"
)

/*
   M00   M01   M02   M03
   M10   M11   M12   M13
   M20   M21   M22   M23
   M30   M31   M32   M33
*/

// Column 0
const m00 = 0
const m10 = 1
const m20 = 2
const m30 = 3

// Column 1
const m01 = 4
const m11 = 5
const m21 = 6
const m31 = 7

// Column 2
const m02 = 8
const m12 = 9
const m22 = 10
const m32 = 11

// Column 3
const m03 = 12
const m13 = 13
const m23 = 14
const m33 = 15

type Mat4 struct {
	Data [16]float32
}

func NewMat4(idt bool) *Mat4 {
	mat := &Mat4{}
	if idt {
		mat.Identity()
	}
	return mat
}

func (m *Mat4) Reset() *Mat4 {
	for i := 0; i < 16; i++ {
		m.Data[i] = 0
	}

	return m
}

func (m *Mat4) Identity() *Mat4 {
	m.Reset()
	m.Data[m00] = 1
	m.Data[m11] = 1
	m.Data[m22] = 1
	m.Data[m33] = 1
	return m
}

func (m *Mat4) Set(data [16]float32) *Mat4 {
	for i := 0; i < 16; i++ {
		m.Data[i] = data[i]
	}
	return m
}

func (m *Mat4) Perspective(fov, aspectRatio, near, far float32) *Mat4 {
	m.Identity()

	q := float32(1.0 / math.Tan(ToRadians*0.5*float64(fov)))
	a := q / aspectRatio
	b := (near + far) / (near - far)
	c := (2.0 / near * far) / (near - far)

	m.Data[m00] = a
	m.Data[m11] = q
	m.Data[m22] = b
	m.Data[m32] = -1
	m.Data[m23] = c

	return m
}

func (m *Mat4) Mul(o *Mat4) *Mat4 {
	var tmp [16]float32
	tmp[m00] = m.Data[m00]*o.Data[m00] + m.Data[m01]*o.Data[m10] + m.Data[m02]*o.Data[m20] + m.Data[m03]*o.Data[m30]
	tmp[m10] = m.Data[m10]*o.Data[m00] + m.Data[m11]*o.Data[m10] + m.Data[m12]*o.Data[m20] + m.Data[m13]*o.Data[m30]
	tmp[m20] = m.Data[m20]*o.Data[m00] + m.Data[m21]*o.Data[m10] + m.Data[m22]*o.Data[m20] + m.Data[m23]*o.Data[m30]
	tmp[m30] = m.Data[m30]*o.Data[m00] + m.Data[m31]*o.Data[m10] + m.Data[m32]*o.Data[m20] + m.Data[m33]*o.Data[m30]

	tmp[m01] = m.Data[m00]*o.Data[m01] + m.Data[m01]*o.Data[m11] + m.Data[m02]*o.Data[m21] + m.Data[m03]*o.Data[m31]
	tmp[m11] = m.Data[m10]*o.Data[m01] + m.Data[m11]*o.Data[m11] + m.Data[m12]*o.Data[m21] + m.Data[m13]*o.Data[m31]
	tmp[m21] = m.Data[m20]*o.Data[m01] + m.Data[m21]*o.Data[m11] + m.Data[m22]*o.Data[m21] + m.Data[m23]*o.Data[m31]
	tmp[m31] = m.Data[m30]*o.Data[m01] + m.Data[m31]*o.Data[m11] + m.Data[m32]*o.Data[m21] + m.Data[m33]*o.Data[m31]

	tmp[m02] = m.Data[m00]*o.Data[m02] + m.Data[m01]*o.Data[m12] + m.Data[m02]*o.Data[m22] + m.Data[m03]*o.Data[m32]
	tmp[m12] = m.Data[m10]*o.Data[m02] + m.Data[m11]*o.Data[m12] + m.Data[m12]*o.Data[m22] + m.Data[m13]*o.Data[m32]
	tmp[m22] = m.Data[m20]*o.Data[m02] + m.Data[m21]*o.Data[m12] + m.Data[m22]*o.Data[m22] + m.Data[m23]*o.Data[m32]
	tmp[m32] = m.Data[m30]*o.Data[m02] + m.Data[m31]*o.Data[m12] + m.Data[m32]*o.Data[m22] + m.Data[m33]*o.Data[m32]

	tmp[m03] = m.Data[m00]*o.Data[m03] + m.Data[m01]*o.Data[m13] + m.Data[m02]*o.Data[m23] + m.Data[m03]*o.Data[m33]
	tmp[m13] = m.Data[m10]*o.Data[m03] + m.Data[m11]*o.Data[m13] + m.Data[m12]*o.Data[m23] + m.Data[m13]*o.Data[m33]
	tmp[m23] = m.Data[m20]*o.Data[m03] + m.Data[m21]*o.Data[m13] + m.Data[m22]*o.Data[m23] + m.Data[m23]*o.Data[m33]
	tmp[m33] = m.Data[m30]*o.Data[m03] + m.Data[m31]*o.Data[m13] + m.Data[m32]*o.Data[m23] + m.Data[m33]*o.Data[m33]

	return m.Set(tmp)
}

func (m *Mat4) String() string {
	return fmt.Sprintf("Matrix4 {\n  %v %v %v %v\n  %v %v %v %v\n  %v %v %v %v\n  %v %v %v %v\n}\n",
		m.Data[m00], m.Data[m01], m.Data[m02], m.Data[m03],
		m.Data[m10], m.Data[m11], m.Data[m12], m.Data[m13],
		m.Data[m20], m.Data[m21], m.Data[m22], m.Data[m23],
		m.Data[m30], m.Data[m31], m.Data[m32], m.Data[m33])
}
<commit_msg>Mat4 operations<commit_after>package glm

import (
	"fmt"
	"math"
)

/*
   M00   M01   M02   M03
   M10   M11   M12   M13
   M20   M21   M22   M23
   M30   M31   M32   M33
*/

// Column 0
const m00 = 0
const m10 = 1
const m20 = 2
const m30 = 3

// Column 1
const m01 = 4
const m11 = 5
const m21 = 6
const m31 = 7

// Column 2
const m02 = 8
const m12 = 9
const m22 = 10
const m32 = 11

// Column 3
const m03 = 12
const m13 = 13
const m23 = 14
const m33 = 15

var (
	tmpMat4 *Mat4    = NewMat4(false)
	tmpVec3 *Vector3 = &Vector3{0, 0, 0}
)

type Mat4 struct {
	Data [16]float32
}

func NewMat4(idt bool) *Mat4 {
	mat := &Mat4{}
	if idt {
		mat.Identity()
	}
	return mat
}

func (m *Mat4) Reset() *Mat4 {
	for i := 0; i < 16; i++ {
		m.Data[i] = 0
	}

	return m
}

func (m *Mat4) Identity() *Mat4 {
	m.Reset()
	m.Data[m00] = 1
	m.Data[m11] = 1
	m.Data[m22] = 1
	m.Data[m33] = 1
	return m
}

func (m *Mat4) Set(data [16]float32) *Mat4 {
	for i := 0; i < 16; i++ {
		m.Data[i] = data[i]
	}
	return m
}

func (m *Mat4) Perspective(fov, aspectRatio, near, far float32) *Mat4 {
	m.Identity()

	q := float32(1.0 / math.Tan(ToRadians*0.5*float64(fov)))
	a := q / aspectRatio
	b := (near + far) / (near - far)
	c := (2.0 / near * far) / (near - far)

	m.Data[m00] = a
	m.Data[m11] = q
	m.Data[m22] = b
	m.Data[m32] = -1
	m.Data[m23] = c

	return m
}

func (m *Mat4) Mul(o *Mat4) *Mat4 {
	var tmp [16]float32
	tmp[m00] = m.Data[m00]*o.Data[m00] + m.Data[m01]*o.Data[m10] + m.Data[m02]*o.Data[m20] + m.Data[m03]*o.Data[m30]
	tmp[m10] = m.Data[m10]*o.Data[m00] + m.Data[m11]*o.Data[m10] + m.Data[m12]*o.Data[m20] + m.Data[m13]*o.Data[m30]
	tmp[m20] = m.Data[m20]*o.Data[m00] + m.Data[m21]*o.Data[m10] + m.Data[m22]*o.Data[m20] + m.Data[m23]*o.Data[m30]
	tmp[m30] = m.Data[m30]*o.Data[m00] + m.Data[m31]*o.Data[m10] + m.Data[m32]*o.Data[m20] + m.Data[m33]*o.Data[m30]

	tmp[m01] = m.Data[m00]*o.Data[m01] + m.Data[m01]*o.Data[m11] + m.Data[m02]*o.Data[m21] + m.Data[m03]*o.Data[m31]
	tmp[m11] = m.Data[m10]*o.Data[m01] + m.Data[m11]*o.Data[m11] + m.Data[m12]*o.Data[m21] + m.Data[m13]*o.Data[m31]
	tmp[m21] = m.Data[m20]*o.Data[m01] + m.Data[m21]*o.Data[m11] + m.Data[m22]*o.Data[m21] + m.Data[m23]*o.Data[m31]
	tmp[m31] = m.Data[m30]*o.Data[m01] + m.Data[m31]*o.Data[m11] + m.Data[m32]*o.Data[m21] + m.Data[m33]*o.Data[m31]

	tmp[m02] = m.Data[m00]*o.Data[m02] + m.Data[m01]*o.Data[m12] + m.Data[m02]*o.Data[m22] + m.Data[m03]*o.Data[m32]
	tmp[m12] = m.Data[m10]*o.Data[m02] + m.Data[m11]*o.Data[m12] + m.Data[m12]*o.Data[m22] + m.Data[m13]*o.Data[m32]
	tmp[m22] = m.Data[m20]*o.Data[m02] + m.Data[m21]*o.Data[m12] + m.Data[m22]*o.Data[m22] + m.Data[m23]*o.Data[m32]
	tmp[m32] = m.Data[m30]*o.Data[m02] + m.Data[m31]*o.Data[m12] + m.Data[m32]*o.Data[m22] + m.Data[m33]*o.Data[m32]

	tmp[m03] = m.Data[m00]*o.Data[m03] + m.Data[m01]*o.Data[m13] + m.Data[m02]*o.Data[m23] + m.Data[m03]*o.Data[m33]
	tmp[m13] = m.Data[m10]*o.Data[m03] + m.Data[m11]*o.Data[m13] + m.Data[m12]*o.Data[m23] + m.Data[m13]*o.Data[m33]
	tmp[m23] = m.Data[m20]*o.Data[m03] + m.Data[m21]*o.Data[m13] + m.Data[m22]*o.Data[m23] + m.Data[m23]*o.Data[m33]
	tmp[m33] = m.Data[m30]*o.Data[m03] + m.Data[m31]*o.Data[m13] + m.Data[m32]*o.Data[m23] + m.Data[m33]*o.Data[m33]

	return m.Set(tmp)
}

func (m *Mat4) Translation(x, y, z float32) *Mat4 {
	m.Identity()
	m.Data[m03] = x
	m.Data[m13] = y
	m.Data[m23] = z
	return m
}

func (m *Mat4) Translate(x, y, z float32) *Mat4 {
	tmpMat4.Translation(x, y, z)
	return m.Mul(tmpMat4)
}

func (m *Mat4) Scaling(x, y, z float32) *Mat4 {
	m.Reset()
	m.Data[m00] = x
	m.Data[m11] = y
	m.Data[m22] = z
	return m
}

func (m *Mat4) Scale(x, y, z float32) *Mat4 {
	m.Data[m00] *= x
	m.Data[m11] *= y
	m.Data[m22] *= z
	return m
}

func (m *Mat4) Rotation(angle, xAxis, yAxis, zAxis float32) *Mat4 {
	if angle == 0 {
		return m
	}

	m.Identity()
	rad := float64(ToRadians * angle)
	c := float32(math.Cos(rad))
	s := float32(math.Sin(rad))
	omc := 1.0 - c

	m.Data[m00] = xAxis*xAxis*omc + c
	m.Data[m10] = yAxis*xAxis*omc - zAxis*s
	m.Data[m20] = xAxis*zAxis*omc + yAxis*s

	m.Data[m01] = yAxis*xAxis*omc + zAxis*s
	m.Data[m11] = yAxis*yAxis*omc + c
	m.Data[m21] = yAxis*zAxis*omc - xAxis*s

	m.Data[m02] = xAxis*zAxis*omc - yAxis*s
	m.Data[m12] = yAxis*zAxis*omc + xAxis*s
	m.Data[m22] = zAxis*zAxis*omc + c

	return m
}

func (m *Mat4) Rotate(angle, xAxis, yAxis, zAxis float32) *Mat4 {
	tmpMat4.Rotation(angle, xAxis, yAxis, zAxis)
	return m.Mul(tmpMat4)
}

func (m *Mat4) String() string {
	return fmt.Sprintf("Matrix4 {\n  %v %v %v %v\n  %v %v %v %v\n  %v %v %v %v\n  %v %v %v %v\n}\n",
		m.Data[m00], m.Data[m01], m.Data[m02], m.Data[m03],
		m.Data[m10], m.Data[m11], m.Data[m12], m.Data[m13],
		m.Data[m20], m.Data[m21], m.Data[m22], m.Data[m23],
		m.Data[m30], m.Data[m31], m.Data[m32], m.Data[m33])
}
<|endoftext|>


<commit_before>// Copyright (c) 2016, Daniel Martí <mvdan@mvdan.cc>
// See LICENSE for licensing information

package sh

// Node represents an AST node.
type Node interface {
	Pos() Pos
	End() Pos
}

// File is a shell program.
type File struct {
	Name string

	Stmts    []Stmt
	Comments []Comment
}

func (f File) Pos() Pos { return stmtFirstPos(f.Stmts) }
func (f File) End() Pos { return stmtLastEnd(f.Stmts) }

type Comment struct {
	Hash Pos
	Text string
}

type Stmt struct {
	Node
	Position   Pos
	Negated    bool
	Background bool
	Assigns    []Assign
	Redirs     []Redirect
}

func (s Stmt) Pos() Pos { return s.Position }
func (s Stmt) End() Pos {
	end := s.Position
	if s.Negated {
		end = posAfter(end, NOT)
	}
	if s.Node != nil {
		end = s.Node.End()
	}
	if len(s.Assigns) > 0 {
		assEnd := s.Assigns[len(s.Assigns)-1].End()
		end = posMax(end, assEnd)
	}
	if len(s.Redirs) > 0 {
		redEnd := s.Redirs[len(s.Redirs)-1].End()
		end = posMax(end, redEnd)
	}
	return end
}

type Assign struct {
	Append bool
	Name   Node
	Value  Word
}

func (a Assign) Pos() Pos {
	if a.Name == nil {
		return a.Value.Pos()
	}
	return a.Name.Pos()
}
func (a Assign) End() Pos {
	if a.Name != nil {
		return posMax(a.Name.End(), a.Value.End())
	}
	return a.Value.End()
}

type Redirect struct {
	OpPos Pos
	Op    Token
	N     Lit
	Word  Word
	Hdoc  string
}

func (r Redirect) Pos() Pos { return r.N.Pos() }
func (r Redirect) End() Pos { return r.Word.End() }

type Command struct {
	Args []Word
}

func (c Command) Pos() Pos { return wordFirstPos(c.Args) }
func (c Command) End() Pos { return wordLastEnd(c.Args) }

type Subshell struct {
	Lparen, Rparen Pos
	Stmts          []Stmt
}

func (s Subshell) Pos() Pos { return s.Lparen }
func (s Subshell) End() Pos { return posAfter(s.Rparen, RPAREN) }

type Block struct {
	Lbrace, Rbrace Pos
	Stmts          []Stmt
}

func (b Block) Pos() Pos { return b.Rbrace }
func (b Block) End() Pos { return posAfter(b.Rbrace, RBRACE) }

type IfStmt struct {
	If, Then, Fi Pos
	Cond         Node
	ThenStmts    []Stmt
	Elifs        []Elif
	Else         Pos
	ElseStmts    []Stmt
}

func (s IfStmt) Pos() Pos { return s.If }
func (s IfStmt) End() Pos { return posAfter(s.Fi, FI) }

type StmtCond struct {
	Stmts []Stmt
}

func (s StmtCond) Pos() Pos { return s.Stmts[0].Pos() }
func (s StmtCond) End() Pos { return stmtLastEnd(s.Stmts) }

type CStyleCond struct {
	Lparen, Rparen Pos
	Cond           Node
}

func (c CStyleCond) Pos() Pos { return c.Lparen }
func (c CStyleCond) End() Pos { return posAfter(c.Rparen, RPAREN) }

type Elif struct {
	Elif, Then Pos
	Cond       Node
	ThenStmts  []Stmt
}

type WhileStmt struct {
	While, Do, Done Pos
	Cond            Node
	DoStmts         []Stmt
}

func (w WhileStmt) Pos() Pos { return w.While }
func (w WhileStmt) End() Pos { return posAfter(w.Done, DONE) }

type UntilStmt struct {
	Until, Do, Done Pos
	Cond            Node
	DoStmts         []Stmt
}

func (u UntilStmt) Pos() Pos { return u.Until }
func (u UntilStmt) End() Pos { return posAfter(u.Done, DONE) }

type ForStmt struct {
	For, Do, Done Pos
	Cond          Node
	DoStmts       []Stmt
}

func (f ForStmt) Pos() Pos { return f.For }
func (f ForStmt) End() Pos { return posAfter(f.Done, DONE) }

type WordIter struct {
	Name Lit
	List []Word
}

func (w WordIter) Pos() Pos { return w.Name.Pos() }
func (w WordIter) End() Pos { return posMax(w.Name.End(), wordLastEnd(w.List)) }

type CStyleLoop struct {
	Lparen, Rparen   Pos
	Init, Cond, Post Node
}

func (c CStyleLoop) Pos() Pos { return c.Lparen }
func (c CStyleLoop) End() Pos { return posAfter(c.Rparen, RPAREN) }

type UnaryExpr struct {
	OpPos Pos
	Op    Token
	Post  bool
	X     Node
}

func (u UnaryExpr) Pos() Pos {
	if u.Post {
		return u.X.Pos()
	}
	return u.OpPos
}
func (u UnaryExpr) End() Pos {
	if u.Post {
		return posAfter(u.OpPos, u.Op)
	}
	return u.X.End()
}

type BinaryExpr struct {
	OpPos Pos
	Op    Token
	X, Y  Node
}

func (b BinaryExpr) Pos() Pos { return b.X.Pos() }
func (b BinaryExpr) End() Pos { return b.Y.End() }

type FuncDecl struct {
	Position  Pos
	BashStyle bool
	Name      Lit
	Body      Stmt
}

func (f FuncDecl) Pos() Pos { return f.Position }
func (f FuncDecl) End() Pos { return f.Body.End() }

type Word struct {
	Parts []Node
}

func (w Word) Pos() Pos { return nodeFirstPos(w.Parts) }
func (w Word) End() Pos { return nodeLastEnd(w.Parts) }

type Lit struct {
	ValuePos Pos
	Value    string
}

func (l Lit) Pos() Pos { return l.ValuePos }
func (l Lit) End() Pos {
	end := l.ValuePos
	for _, b := range []byte(l.Value) {
		end = moveWith(end, b)
	}
	return end
}

type SglQuoted struct {
	Quote Pos
	Value string
}

func (q SglQuoted) Pos() Pos { return q.Quote }
func (q SglQuoted) End() Pos {
	end := posAfter(q.Quote, SQUOTE)
	for _, b := range []byte(q.Value) {
		end = moveWith(end, b)
	}
	return posAfter(end, SQUOTE)
}

type Quoted struct {
	QuotePos Pos
	Quote    Token
	Parts    []Node
}

func (q Quoted) Pos() Pos { return q.QuotePos }
func (q Quoted) End() Pos { return posAfter(nodeLastEnd(q.Parts), q.Quote) }

type CmdSubst struct {
	Left, Right Pos
	Backquotes  bool
	Stmts       []Stmt
}

func (c CmdSubst) Pos() Pos { return c.Left }
func (c CmdSubst) End() Pos { return posAfter(c.Right, RPAREN) }

type ParamExp struct {
	Dollar        Pos
	Short, Length bool
	Param         Lit
	Ind           *Index
	Repl          *Replace
	Exp           *Expansion
}

func (p ParamExp) Pos() Pos { return p.Dollar }
func (p ParamExp) End() Pos {
	end := p.Param.End()
	if p.Ind != nil {
		end = posMax(end, p.Ind.Word.End())
	}
	if p.Repl != nil {
		end = posMax(end, p.Repl.With.End())
	}
	if p.Exp != nil {
		end = posMax(end, p.Exp.Word.End())
	}
	return posAfter(end, RBRACE)
}

type Index struct {
	Word Word
}

type Replace struct {
	All        bool
	Orig, With Word
}

type Expansion struct {
	Op   Token
	Word Word
}

type ArithmExpr struct {
	Dollar, Rparen Pos
	X              Node
}

func (a ArithmExpr) Pos() Pos { return a.Dollar }
func (a ArithmExpr) End() Pos { return posAfter(a.Rparen, DRPAREN) }

type ParenExpr struct {
	Lparen, Rparen Pos
	X              Node
}

func (p ParenExpr) Pos() Pos { return p.Lparen }
func (p ParenExpr) End() Pos { return posAfter(p.Rparen, RPAREN) }

type CaseStmt struct {
	Case, Esac Pos
	Word       Word
	List       []PatternList
}

func (c CaseStmt) Pos() Pos { return c.Case }
func (c CaseStmt) End() Pos { return posAfter(c.Esac, ESAC) }

type PatternList struct {
	Dsemi    Pos
	Patterns []Word
	Stmts    []Stmt
}

type DeclStmt struct {
	Declare Pos
	Local   bool
	Opts    []Word
	Assigns []Assign
}

func (d DeclStmt) Pos() Pos { return d.Declare }
func (d DeclStmt) End() Pos {
	end := wordLastEnd(d.Opts)
	if len(d.Assigns) > 0 {
		assignEnd := d.Assigns[len(d.Assigns)-1].End()
		end = posMax(end, assignEnd)
	}
	return end
}

type ArrayExpr struct {
	Lparen, Rparen Pos
	List           []Word
}

func (a ArrayExpr) Pos() Pos { return a.Lparen }
func (a ArrayExpr) End() Pos { return posAfter(a.Rparen, RPAREN) }

type CmdInput struct {
	Lss, Rparen Pos
	Stmts       []Stmt
}

func (c CmdInput) Pos() Pos { return c.Lss }
func (c CmdInput) End() Pos { return posAfter(c.Rparen, RPAREN) }

type EvalStmt struct {
	Eval Pos
	Stmt Stmt
}

func (e EvalStmt) Pos() Pos { return e.Eval }
func (e EvalStmt) End() Pos { return e.Stmt.End() }

type LetStmt struct {
	Let   Pos
	Exprs []Node
}

func (l LetStmt) Pos() Pos { return l.Let }
func (l LetStmt) End() Pos { return nodeLastEnd(l.Exprs) }

func posAfter(pos Pos, tok Token) Pos {
	if pos.Line == 0 {
		return pos
	}
	pos.Column += len(tok.String())
	return pos
}

var defaultPos = Pos{}

func stmtFirstPos(sts []Stmt) Pos {
	if len(sts) == 0 {
		return defaultPos
	}
	return sts[0].Pos()
}

func stmtLastEnd(sts []Stmt) Pos {
	if len(sts) == 0 {
		return defaultPos
	}
	return sts[len(sts)-1].End()
}

func nodeFirstPos(ns []Node) Pos {
	if len(ns) == 0 {
		return defaultPos
	}
	return ns[0].Pos()
}

func nodeLastEnd(ns []Node) Pos {
	if len(ns) == 0 {
		return defaultPos
	}
	return ns[len(ns)-1].End()
}

func wordFirstPos(ws []Word) Pos {
	if len(ws) == 0 {
		return defaultPos
	}
	return ws[0].Pos()
}

func wordLastEnd(ws []Word) Pos {
	if len(ws) == 0 {
		return defaultPos
	}
	return ws[len(ws)-1].End()
}
<commit_msg>ast: add godoc for basic Node types<commit_after>// Copyright (c) 2016, Daniel Martí <mvdan@mvdan.cc>
// See LICENSE for licensing information

package sh

// Node represents an AST node.
type Node interface {
	// Pos returns the first character of the node
	Pos() Pos
	// End returns the character immediately after the node
	End() Pos
}

// File is a shell program.
type File struct {
	Name string

	Stmts    []Stmt
	Comments []Comment
}

func (f File) Pos() Pos { return stmtFirstPos(f.Stmts) }
func (f File) End() Pos { return stmtLastEnd(f.Stmts) }

// Comment represents a single comment on a single line.
type Comment struct {
	Hash Pos
	Text string
}

// Stmt represents a statement, otherwise known as a compound command.
// It is compromised of a node, like Command or IfStmt, and other
// components that may come before or after it.
type Stmt struct {
	Node
	Position   Pos
	Negated    bool
	Background bool
	Assigns    []Assign
	Redirs     []Redirect
}

func (s Stmt) Pos() Pos { return s.Position }
func (s Stmt) End() Pos {
	end := s.Position
	if s.Negated {
		end = posAfter(end, NOT)
	}
	if s.Node != nil {
		end = s.Node.End()
	}
	if len(s.Assigns) > 0 {
		assEnd := s.Assigns[len(s.Assigns)-1].End()
		end = posMax(end, assEnd)
	}
	if len(s.Redirs) > 0 {
		redEnd := s.Redirs[len(s.Redirs)-1].End()
		end = posMax(end, redEnd)
	}
	return end
}

// Assign represents an assignment to a variable.
type Assign struct {
	Append bool
	Name   Node
	Value  Word
}

func (a Assign) Pos() Pos {
	if a.Name == nil {
		return a.Value.Pos()
	}
	return a.Name.Pos()
}
func (a Assign) End() Pos {
	if a.Name != nil {
		return posMax(a.Name.End(), a.Value.End())
	}
	return a.Value.End()
}

// Redirect represents an input/output redirection.
type Redirect struct {
	OpPos Pos
	Op    Token
	N     Lit
	Word  Word
	Hdoc  string
}

func (r Redirect) Pos() Pos { return r.N.Pos() }
func (r Redirect) End() Pos { return r.Word.End() }

// Command represents a command execution or function call.
type Command struct {
	Args []Word
}

func (c Command) Pos() Pos { return wordFirstPos(c.Args) }
func (c Command) End() Pos { return wordLastEnd(c.Args) }

// Subshell represents a series of commands that should be executed in a
// nested shell environment.
type Subshell struct {
	Lparen, Rparen Pos
	Stmts          []Stmt
}

func (s Subshell) Pos() Pos { return s.Lparen }
func (s Subshell) End() Pos { return posAfter(s.Rparen, RPAREN) }

// Block represents a series of commands that should be executed in a
// nested scope.
type Block struct {
	Lbrace, Rbrace Pos
	Stmts          []Stmt
}

func (b Block) Pos() Pos { return b.Rbrace }
func (b Block) End() Pos { return posAfter(b.Rbrace, RBRACE) }

type IfStmt struct {
	If, Then, Fi Pos
	Cond         Node
	ThenStmts    []Stmt
	Elifs        []Elif
	Else         Pos
	ElseStmts    []Stmt
}

func (s IfStmt) Pos() Pos { return s.If }
func (s IfStmt) End() Pos { return posAfter(s.Fi, FI) }

type StmtCond struct {
	Stmts []Stmt
}

func (s StmtCond) Pos() Pos { return s.Stmts[0].Pos() }
func (s StmtCond) End() Pos { return stmtLastEnd(s.Stmts) }

type CStyleCond struct {
	Lparen, Rparen Pos
	Cond           Node
}

func (c CStyleCond) Pos() Pos { return c.Lparen }
func (c CStyleCond) End() Pos { return posAfter(c.Rparen, RPAREN) }

type Elif struct {
	Elif, Then Pos
	Cond       Node
	ThenStmts  []Stmt
}

type WhileStmt struct {
	While, Do, Done Pos
	Cond            Node
	DoStmts         []Stmt
}

func (w WhileStmt) Pos() Pos { return w.While }
func (w WhileStmt) End() Pos { return posAfter(w.Done, DONE) }

type UntilStmt struct {
	Until, Do, Done Pos
	Cond            Node
	DoStmts         []Stmt
}

func (u UntilStmt) Pos() Pos { return u.Until }
func (u UntilStmt) End() Pos { return posAfter(u.Done, DONE) }

type ForStmt struct {
	For, Do, Done Pos
	Cond          Node
	DoStmts       []Stmt
}

func (f ForStmt) Pos() Pos { return f.For }
func (f ForStmt) End() Pos { return posAfter(f.Done, DONE) }

type WordIter struct {
	Name Lit
	List []Word
}

func (w WordIter) Pos() Pos { return w.Name.Pos() }
func (w WordIter) End() Pos { return posMax(w.Name.End(), wordLastEnd(w.List)) }

type CStyleLoop struct {
	Lparen, Rparen   Pos
	Init, Cond, Post Node
}

func (c CStyleLoop) Pos() Pos { return c.Lparen }
func (c CStyleLoop) End() Pos { return posAfter(c.Rparen, RPAREN) }

type UnaryExpr struct {
	OpPos Pos
	Op    Token
	Post  bool
	X     Node
}

func (u UnaryExpr) Pos() Pos {
	if u.Post {
		return u.X.Pos()
	}
	return u.OpPos
}
func (u UnaryExpr) End() Pos {
	if u.Post {
		return posAfter(u.OpPos, u.Op)
	}
	return u.X.End()
}

type BinaryExpr struct {
	OpPos Pos
	Op    Token
	X, Y  Node
}

func (b BinaryExpr) Pos() Pos { return b.X.Pos() }
func (b BinaryExpr) End() Pos { return b.Y.End() }

type FuncDecl struct {
	Position  Pos
	BashStyle bool
	Name      Lit
	Body      Stmt
}

func (f FuncDecl) Pos() Pos { return f.Position }
func (f FuncDecl) End() Pos { return f.Body.End() }

type Word struct {
	Parts []Node
}

func (w Word) Pos() Pos { return nodeFirstPos(w.Parts) }
func (w Word) End() Pos { return nodeLastEnd(w.Parts) }

type Lit struct {
	ValuePos Pos
	Value    string
}

func (l Lit) Pos() Pos { return l.ValuePos }
func (l Lit) End() Pos {
	end := l.ValuePos
	for _, b := range []byte(l.Value) {
		end = moveWith(end, b)
	}
	return end
}

type SglQuoted struct {
	Quote Pos
	Value string
}

func (q SglQuoted) Pos() Pos { return q.Quote }
func (q SglQuoted) End() Pos {
	end := posAfter(q.Quote, SQUOTE)
	for _, b := range []byte(q.Value) {
		end = moveWith(end, b)
	}
	return posAfter(end, SQUOTE)
}

type Quoted struct {
	QuotePos Pos
	Quote    Token
	Parts    []Node
}

func (q Quoted) Pos() Pos { return q.QuotePos }
func (q Quoted) End() Pos { return posAfter(nodeLastEnd(q.Parts), q.Quote) }

type CmdSubst struct {
	Left, Right Pos
	Backquotes  bool
	Stmts       []Stmt
}

func (c CmdSubst) Pos() Pos { return c.Left }
func (c CmdSubst) End() Pos { return posAfter(c.Right, RPAREN) }

type ParamExp struct {
	Dollar        Pos
	Short, Length bool
	Param         Lit
	Ind           *Index
	Repl          *Replace
	Exp           *Expansion
}

func (p ParamExp) Pos() Pos { return p.Dollar }
func (p ParamExp) End() Pos {
	end := p.Param.End()
	if p.Ind != nil {
		end = posMax(end, p.Ind.Word.End())
	}
	if p.Repl != nil {
		end = posMax(end, p.Repl.With.End())
	}
	if p.Exp != nil {
		end = posMax(end, p.Exp.Word.End())
	}
	return posAfter(end, RBRACE)
}

type Index struct {
	Word Word
}

type Replace struct {
	All        bool
	Orig, With Word
}

type Expansion struct {
	Op   Token
	Word Word
}

type ArithmExpr struct {
	Dollar, Rparen Pos
	X              Node
}

func (a ArithmExpr) Pos() Pos { return a.Dollar }
func (a ArithmExpr) End() Pos { return posAfter(a.Rparen, DRPAREN) }

type ParenExpr struct {
	Lparen, Rparen Pos
	X              Node
}

func (p ParenExpr) Pos() Pos { return p.Lparen }
func (p ParenExpr) End() Pos { return posAfter(p.Rparen, RPAREN) }

type CaseStmt struct {
	Case, Esac Pos
	Word       Word
	List       []PatternList
}

func (c CaseStmt) Pos() Pos { return c.Case }
func (c CaseStmt) End() Pos { return posAfter(c.Esac, ESAC) }

type PatternList struct {
	Dsemi    Pos
	Patterns []Word
	Stmts    []Stmt
}

type DeclStmt struct {
	Declare Pos
	Local   bool
	Opts    []Word
	Assigns []Assign
}

func (d DeclStmt) Pos() Pos { return d.Declare }
func (d DeclStmt) End() Pos {
	end := wordLastEnd(d.Opts)
	if len(d.Assigns) > 0 {
		assignEnd := d.Assigns[len(d.Assigns)-1].End()
		end = posMax(end, assignEnd)
	}
	return end
}

type ArrayExpr struct {
	Lparen, Rparen Pos
	List           []Word
}

func (a ArrayExpr) Pos() Pos { return a.Lparen }
func (a ArrayExpr) End() Pos { return posAfter(a.Rparen, RPAREN) }

type CmdInput struct {
	Lss, Rparen Pos
	Stmts       []Stmt
}

func (c CmdInput) Pos() Pos { return c.Lss }
func (c CmdInput) End() Pos { return posAfter(c.Rparen, RPAREN) }

type EvalStmt struct {
	Eval Pos
	Stmt Stmt
}

func (e EvalStmt) Pos() Pos { return e.Eval }
func (e EvalStmt) End() Pos { return e.Stmt.End() }

type LetStmt struct {
	Let   Pos
	Exprs []Node
}

func (l LetStmt) Pos() Pos { return l.Let }
func (l LetStmt) End() Pos { return nodeLastEnd(l.Exprs) }

func posAfter(pos Pos, tok Token) Pos {
	if pos.Line == 0 {
		return pos
	}
	pos.Column += len(tok.String())
	return pos
}

var defaultPos = Pos{}

func stmtFirstPos(sts []Stmt) Pos {
	if len(sts) == 0 {
		return defaultPos
	}
	return sts[0].Pos()
}

func stmtLastEnd(sts []Stmt) Pos {
	if len(sts) == 0 {
		return defaultPos
	}
	return sts[len(sts)-1].End()
}

func nodeFirstPos(ns []Node) Pos {
	if len(ns) == 0 {
		return defaultPos
	}
	return ns[0].Pos()
}

func nodeLastEnd(ns []Node) Pos {
	if len(ns) == 0 {
		return defaultPos
	}
	return ns[len(ns)-1].End()
}

func wordFirstPos(ws []Word) Pos {
	if len(ws) == 0 {
		return defaultPos
	}
	return ws[0].Pos()
}

func wordLastEnd(ws []Word) Pos {
	if len(ws) == 0 {
		return defaultPos
	}
	return ws[len(ws)-1].End()
}
<|endoftext|>


<commit_before>package jigo

import (
	"bytes"
	"fmt"
	"strconv"
)

var textFormat = "%s" // Changed to "%q" in tests for better error messages.

type NodeType int

func (t NodeType) Type() NodeType {
	return t
}

type Node interface {
	Type() NodeType
	String() string
	// Copy does a deep copy of the Node and all its components.
	Copy() Node
	Position() Pos // byte position of start of node in full original input string
}

const (
	NodeList NodeType = iota
	NodeText
	NodeVar
	NodeLookup
	NodeUnary
	NodeFloat
	NodeInteger
	NodeString
	NodeAdd
	NodeMul
	NodeMapExpr
	NodeMapElem
	NodeIndexExpr
	NodeSet
	NodeIf
	NodeFor
)

// This is a stack of nodes starting at a position.  It has the default NodeType
// but should never end up in the AST;  it's use is in implementing order of
// operations for expressions
type nodeStack struct {
	NodeType
	Pos
	Nodes []Node
}

func newStack(pos Pos) *nodeStack {
	return &nodeStack{Pos: pos}
}

func (n *nodeStack) len() int       { return len(n.Nodes) }
func (n *nodeStack) push(node Node) { n.Nodes = append(n.Nodes, node) }
func (n *nodeStack) pop() Node {
	var r Node
	if len(n.Nodes) > 0 {
		r = n.Nodes[len(n.Nodes)-1]
		n.Nodes = n.Nodes[:len(n.Nodes)-1]
	}
	return r
}

// ListNode holds a sequence of nodes.
type ListNode struct {
	NodeType
	Pos
	Nodes []Node // The element nodes in lexical order.
}

func newList(pos Pos) *ListNode {
	return &ListNode{NodeType: NodeList, Pos: pos}
}

func (l *ListNode) append(n Node) { l.Nodes = append(l.Nodes, n) }
func (l *ListNode) len() int      { return len(l.Nodes) }

func (l *ListNode) String() string {
	b := new(bytes.Buffer)
	for _, n := range l.Nodes {
		fmt.Fprint(b, n)
	}
	return b.String()
}

func (l *ListNode) CopyList() *ListNode {
	if l == nil {
		return l
	}
	n := newList(l.Pos)
	for _, elem := range l.Nodes {
		n.append(elem.Copy())
	}
	return n
}

func (l *ListNode) Copy() Node { return l.CopyList() }

// TextNode holds plain text.
type TextNode struct {
	NodeType
	Pos
	Text []byte // The text; may span newlines.
}

func newText(pos Pos, text string) *TextNode {
	return &TextNode{NodeType: NodeText, Pos: pos, Text: []byte(text)}
}

func (t *TextNode) String() string { return fmt.Sprintf(textFormat, t.Text) }
func (t *TextNode) Copy() Node     { return &TextNode{NodeText, t.Pos, append([]byte{}, t.Text...)} }

// VarNode represents a var print expr, ie {{ ... }}.
// It is represented as a sequence of expressions.
type VarNode struct {
	NodeType
	Pos
	Node Node
}

func newVar(pos Pos) *VarNode {
	return &VarNode{NodeType: NodeVar, Pos: pos}
}

func (v *VarNode) String() string { return "{{ " + v.Node.String() + " }}" }
func (v *VarNode) Copy() Node     { return &VarNode{v.NodeType, v.Pos, v.Node} }

// A LookupNode is a variable lookup.
type LookupNode struct {
	NodeType
	Pos
	Name string
}

func newLookup(pos Pos, name string) *LookupNode {
	return &LookupNode{NodeType: NodeLookup, Pos: pos, Name: name}
}
func (l *LookupNode) String() string { return l.Name }
func (l *LookupNode) Copy() Node     { return newLookup(l.Pos, l.Name) }

type StringNode struct {
	NodeType
	Pos
	Value string
}

func (s *StringNode) Copy() Node     { return &StringNode{s.NodeType, s.Pos, s.Value} }
func (s *StringNode) String() string { return fmt.Sprintf(`"%s"`, s.Value) }

type IntegerNode struct {
	NodeType
	Pos
	Value int64
}

func (i *IntegerNode) Copy() Node     { return &IntegerNode{i.NodeType, i.Pos, i.Value} }
func (i *IntegerNode) String() string { return strconv.FormatInt(i.Value, 10) }

type FloatNode struct {
	NodeType
	Pos
	Value float64
}

func (f *FloatNode) Copy() Node     { return &FloatNode{f.NodeType, f.Pos, f.Value} }
func (f *FloatNode) String() string { return fmt.Sprint(f.Value) }

type UnaryNode struct {
	NodeType
	Pos
	Value Node
	Unary item
}

func newUnaryNode(val Node, unary item) *UnaryNode {
	return &UnaryNode{NodeUnary, val.Position(), val, unary}
}

func (u *UnaryNode) Copy() Node     { return &UnaryNode{u.NodeType, u.Pos, u.Value, u.Unary} }
func (u *UnaryNode) String() string { return fmt.Sprintf("%s%s", u.Unary.val, u.Value) }

// newLiteral creates a new string, integer, or float node depending on itemType
func newLiteral(pos Pos, typ itemType, val string) Node {
	switch typ {
	case tokenFloat:
		v, err := strconv.ParseFloat(val, 64)
		if err != nil {
			panic(err)
		}
		return &FloatNode{NodeFloat, pos, v}
	case tokenInteger:
		// FIXME: complex integer types?  hex, octal, etc?
		v, err := strconv.ParseInt(val, 10, 64)
		if err != nil {
			panic(err)
		}
		return &IntegerNode{NodeInteger, pos, v}
	case tokenString:
		return &StringNode{NodeString, pos, val}
	}
	panic(fmt.Sprint("unexpected literal type ", typ))
}

type AddExpr struct {
	NodeType
	Pos
	lhs      Node
	rhs      Node
	operator item
}

func newAddExpr(lhs, rhs Node, operator item) *AddExpr {
	return &AddExpr{NodeAdd, lhs.Position(), lhs, rhs, operator}
}

func (a *AddExpr) String() string {
	return fmt.Sprintf("%s %s %s", a.lhs, a.operator.val, a.rhs)
}

func (a *AddExpr) Copy() Node {
	return newAddExpr(a.lhs, a.rhs, a.operator)
}

type MulExpr struct {
	NodeType
	Pos
	lhs      Node
	rhs      Node
	operator item
}

func newMulExpr(lhs, rhs Node, operator item) *MulExpr {
	return &MulExpr{NodeMul, lhs.Position(), lhs, rhs, operator}
}

func (m *MulExpr) String() string {
	return fmt.Sprintf("%s %s %s", m.lhs, m.operator.val, m.rhs)
}

func (m *MulExpr) Copy() Node {
	return newMulExpr(m.lhs, m.rhs, m.operator)
}

// complex literals

type MapExpr struct {
	NodeType
	Pos
	Elems []*MapElem
}

func newMapExpr(pos Pos) *MapExpr {
	return &MapExpr{NodeType: NodeMapExpr, Pos: pos}
}

func (m *MapExpr) len() int          { return len(m.Elems) }
func (m *MapExpr) append(n *MapElem) { m.Elems = append(m.Elems, n) }

func (m *MapExpr) String() string {
	b := new(bytes.Buffer)
	b.WriteString("{")
	for i, n := range m.Elems {
		fmt.Fprint(b, n)
		if i != len(m.Elems)-1 {
			b.WriteString(", ")
		}
	}
	b.WriteString("}")
	return b.String()
}

func (m *MapExpr) Copy() Node {
	if m == nil {
		return m
	}
	n := newMapExpr(m.Pos)
	for _, elem := range m.Elems {
		n.append(elem.Copy().(*MapElem))
	}
	return n
}

type MapElem struct {
	NodeType
	Pos
	Key   Node
	Value Node
}

func newMapElem(lhs, rhs Node) *MapElem {
	return &MapElem{NodeMapElem, lhs.Position(), lhs, rhs}
}

func (m *MapElem) String() string {
	return fmt.Sprintf("%s: %s", m.Key, m.Value)
}

func (m *MapElem) Copy() Node {
	return newMapElem(m.Key, m.Value)
}

type IndexExpr struct {
	NodeType
	Pos
	Value Node
	Index Node
}

func newIndexExpr(val, idx Node) *IndexExpr {
	return &IndexExpr{NodeIndexExpr, val.Position(), val, idx}
}

func (i *IndexExpr) String() string {
	return fmt.Sprintf("%s[%s}", i.Value, i.Index)
}

func (i *IndexExpr) Copy() Node {
	return newIndexExpr(i.Value, i.Index)
}

// block types
type SetNode struct {
	NodeType
	Pos
	lhs Node
	rhs Node
}

func newSet(pos Pos, lhs, rhs Node) *SetNode {
	return &SetNode{NodeSet, pos, lhs, rhs}
}

func (s *SetNode) String() string { return fmt.Sprintf("set %s = %s", s.lhs, s.rhs) }
func (s *SetNode) Copy() Node {
	return newSet(s.Pos, s.lhs.Copy(), s.rhs.Copy())
}

type IfNode struct {
	NodeType
	Pos
	Guard Node
	Body  Node
	Elifs []Node
	Else  Node
}

func newIf(pos Pos) *IfNode {
	return &IfNode{NodeType: NodeIf, Pos: pos}
}

func (i *IfNode) String() string { return "if" }
func (i *IfNode) Copy() Node {
	n := newIf(i.Pos)
	n.Guard = i.Guard.Copy()
	n.Body = i.Body.Copy()
	n.Elifs = make([]Node, len(i.Elifs))
	for _, e := range i.Elifs {
		n.Elifs = append(n.Elifs, e.Copy())
	}
	n.Else = i.Else.Copy()
	return n
}

type ForNode struct {
	NodeType
	Pos
	ForExpr Node
	InExpr  Node
	Body    Node
}

func newFor(pos Pos) *ForNode {
	return &ForNode{NodeType: NodeFor, Pos: pos}
}

func (f *ForNode) String() string {
	return fmt.Sprintf("{% for %s in %s %}%s{% endfor %}", f.ForExpr, f.InExpr, f.Body)
}
func (f *ForNode) Copy() Node {
	n := newFor(f.Pos)
	n.ForExpr = f.ForExpr.Copy()
	n.InExpr = f.InExpr.Copy()
	n.Body = f.Body.Copy()
	return n
}

type BlockNode struct {
	NodeType
	Pos
	Name string
	Body Node
}

func (b *BlockNode) String() string {
	return fmt.Sprintf("{% block %s %}%s{% endblock %}", b.Name, b.Body)
}

func (b *BlockNode) Copy() Node {

}

type ExtendsNode struct{}
type PrintNode struct{}
type MacroNode struct{}
type IncludeNode struct{}
type FromNOde struct{}
type ImportNode struct{}
type CallNode struct{}
<commit_msg>fix test failure for no return on blocknode copy<commit_after>package jigo

import (
	"bytes"
	"fmt"
	"strconv"
)

var textFormat = "%s" // Changed to "%q" in tests for better error messages.

type NodeType int

func (t NodeType) Type() NodeType {
	return t
}

type Node interface {
	Type() NodeType
	String() string
	// Copy does a deep copy of the Node and all its components.
	Copy() Node
	Position() Pos // byte position of start of node in full original input string
}

const (
	NodeList NodeType = iota
	NodeText
	NodeVar
	NodeLookup
	NodeUnary
	NodeFloat
	NodeInteger
	NodeString
	NodeAdd
	NodeMul
	NodeMapExpr
	NodeMapElem
	NodeIndexExpr
	NodeSet
	NodeIf
	NodeFor
)

// This is a stack of nodes starting at a position.  It has the default NodeType
// but should never end up in the AST;  it's use is in implementing order of
// operations for expressions
type nodeStack struct {
	NodeType
	Pos
	Nodes []Node
}

func newStack(pos Pos) *nodeStack {
	return &nodeStack{Pos: pos}
}

func (n *nodeStack) len() int       { return len(n.Nodes) }
func (n *nodeStack) push(node Node) { n.Nodes = append(n.Nodes, node) }
func (n *nodeStack) pop() Node {
	var r Node
	if len(n.Nodes) > 0 {
		r = n.Nodes[len(n.Nodes)-1]
		n.Nodes = n.Nodes[:len(n.Nodes)-1]
	}
	return r
}

// ListNode holds a sequence of nodes.
type ListNode struct {
	NodeType
	Pos
	Nodes []Node // The element nodes in lexical order.
}

func newList(pos Pos) *ListNode {
	return &ListNode{NodeType: NodeList, Pos: pos}
}

func (l *ListNode) append(n Node) { l.Nodes = append(l.Nodes, n) }
func (l *ListNode) len() int      { return len(l.Nodes) }

func (l *ListNode) String() string {
	b := new(bytes.Buffer)
	for _, n := range l.Nodes {
		fmt.Fprint(b, n)
	}
	return b.String()
}

func (l *ListNode) CopyList() *ListNode {
	if l == nil {
		return l
	}
	n := newList(l.Pos)
	for _, elem := range l.Nodes {
		n.append(elem.Copy())
	}
	return n
}

func (l *ListNode) Copy() Node { return l.CopyList() }

// TextNode holds plain text.
type TextNode struct {
	NodeType
	Pos
	Text []byte // The text; may span newlines.
}

func newText(pos Pos, text string) *TextNode {
	return &TextNode{NodeType: NodeText, Pos: pos, Text: []byte(text)}
}

func (t *TextNode) String() string { return fmt.Sprintf(textFormat, t.Text) }
func (t *TextNode) Copy() Node     { return &TextNode{NodeText, t.Pos, append([]byte{}, t.Text...)} }

// VarNode represents a var print expr, ie {{ ... }}.
// It is represented as a sequence of expressions.
type VarNode struct {
	NodeType
	Pos
	Node Node
}

func newVar(pos Pos) *VarNode {
	return &VarNode{NodeType: NodeVar, Pos: pos}
}

func (v *VarNode) String() string { return "{{ " + v.Node.String() + " }}" }
func (v *VarNode) Copy() Node     { return &VarNode{v.NodeType, v.Pos, v.Node} }

// A LookupNode is a variable lookup.
type LookupNode struct {
	NodeType
	Pos
	Name string
}

func newLookup(pos Pos, name string) *LookupNode {
	return &LookupNode{NodeType: NodeLookup, Pos: pos, Name: name}
}
func (l *LookupNode) String() string { return l.Name }
func (l *LookupNode) Copy() Node     { return newLookup(l.Pos, l.Name) }

type StringNode struct {
	NodeType
	Pos
	Value string
}

func (s *StringNode) Copy() Node     { return &StringNode{s.NodeType, s.Pos, s.Value} }
func (s *StringNode) String() string { return fmt.Sprintf(`"%s"`, s.Value) }

type IntegerNode struct {
	NodeType
	Pos
	Value int64
}

func (i *IntegerNode) Copy() Node     { return &IntegerNode{i.NodeType, i.Pos, i.Value} }
func (i *IntegerNode) String() string { return strconv.FormatInt(i.Value, 10) }

type FloatNode struct {
	NodeType
	Pos
	Value float64
}

func (f *FloatNode) Copy() Node     { return &FloatNode{f.NodeType, f.Pos, f.Value} }
func (f *FloatNode) String() string { return fmt.Sprint(f.Value) }

type UnaryNode struct {
	NodeType
	Pos
	Value Node
	Unary item
}

func newUnaryNode(val Node, unary item) *UnaryNode {
	return &UnaryNode{NodeUnary, val.Position(), val, unary}
}

func (u *UnaryNode) Copy() Node     { return &UnaryNode{u.NodeType, u.Pos, u.Value, u.Unary} }
func (u *UnaryNode) String() string { return fmt.Sprintf("%s%s", u.Unary.val, u.Value) }

// newLiteral creates a new string, integer, or float node depending on itemType
func newLiteral(pos Pos, typ itemType, val string) Node {
	switch typ {
	case tokenFloat:
		v, err := strconv.ParseFloat(val, 64)
		if err != nil {
			panic(err)
		}
		return &FloatNode{NodeFloat, pos, v}
	case tokenInteger:
		// FIXME: complex integer types?  hex, octal, etc?
		v, err := strconv.ParseInt(val, 10, 64)
		if err != nil {
			panic(err)
		}
		return &IntegerNode{NodeInteger, pos, v}
	case tokenString:
		return &StringNode{NodeString, pos, val}
	}
	panic(fmt.Sprint("unexpected literal type ", typ))
}

type AddExpr struct {
	NodeType
	Pos
	lhs      Node
	rhs      Node
	operator item
}

func newAddExpr(lhs, rhs Node, operator item) *AddExpr {
	return &AddExpr{NodeAdd, lhs.Position(), lhs, rhs, operator}
}

func (a *AddExpr) String() string {
	return fmt.Sprintf("%s %s %s", a.lhs, a.operator.val, a.rhs)
}

func (a *AddExpr) Copy() Node {
	return newAddExpr(a.lhs, a.rhs, a.operator)
}

type MulExpr struct {
	NodeType
	Pos
	lhs      Node
	rhs      Node
	operator item
}

func newMulExpr(lhs, rhs Node, operator item) *MulExpr {
	return &MulExpr{NodeMul, lhs.Position(), lhs, rhs, operator}
}

func (m *MulExpr) String() string {
	return fmt.Sprintf("%s %s %s", m.lhs, m.operator.val, m.rhs)
}

func (m *MulExpr) Copy() Node {
	return newMulExpr(m.lhs, m.rhs, m.operator)
}

// complex literals

type MapExpr struct {
	NodeType
	Pos
	Elems []*MapElem
}

func newMapExpr(pos Pos) *MapExpr {
	return &MapExpr{NodeType: NodeMapExpr, Pos: pos}
}

func (m *MapExpr) len() int          { return len(m.Elems) }
func (m *MapExpr) append(n *MapElem) { m.Elems = append(m.Elems, n) }

func (m *MapExpr) String() string {
	b := new(bytes.Buffer)
	b.WriteString("{")
	for i, n := range m.Elems {
		fmt.Fprint(b, n)
		if i != len(m.Elems)-1 {
			b.WriteString(", ")
		}
	}
	b.WriteString("}")
	return b.String()
}

func (m *MapExpr) Copy() Node {
	if m == nil {
		return m
	}
	n := newMapExpr(m.Pos)
	for _, elem := range m.Elems {
		n.append(elem.Copy().(*MapElem))
	}
	return n
}

type MapElem struct {
	NodeType
	Pos
	Key   Node
	Value Node
}

func newMapElem(lhs, rhs Node) *MapElem {
	return &MapElem{NodeMapElem, lhs.Position(), lhs, rhs}
}

func (m *MapElem) String() string {
	return fmt.Sprintf("%s: %s", m.Key, m.Value)
}

func (m *MapElem) Copy() Node {
	return newMapElem(m.Key, m.Value)
}

type IndexExpr struct {
	NodeType
	Pos
	Value Node
	Index Node
}

func newIndexExpr(val, idx Node) *IndexExpr {
	return &IndexExpr{NodeIndexExpr, val.Position(), val, idx}
}

func (i *IndexExpr) String() string {
	return fmt.Sprintf("%s[%s}", i.Value, i.Index)
}

func (i *IndexExpr) Copy() Node {
	return newIndexExpr(i.Value, i.Index)
}

// block types
type SetNode struct {
	NodeType
	Pos
	lhs Node
	rhs Node
}

func newSet(pos Pos, lhs, rhs Node) *SetNode {
	return &SetNode{NodeSet, pos, lhs, rhs}
}

func (s *SetNode) String() string { return fmt.Sprintf("set %s = %s", s.lhs, s.rhs) }
func (s *SetNode) Copy() Node {
	return newSet(s.Pos, s.lhs.Copy(), s.rhs.Copy())
}

type IfNode struct {
	NodeType
	Pos
	Guard Node
	Body  Node
	Elifs []Node
	Else  Node
}

func newIf(pos Pos) *IfNode {
	return &IfNode{NodeType: NodeIf, Pos: pos}
}

func (i *IfNode) String() string { return "if" }
func (i *IfNode) Copy() Node {
	n := newIf(i.Pos)
	n.Guard = i.Guard.Copy()
	n.Body = i.Body.Copy()
	n.Elifs = make([]Node, len(i.Elifs))
	for _, e := range i.Elifs {
		n.Elifs = append(n.Elifs, e.Copy())
	}
	n.Else = i.Else.Copy()
	return n
}

type ForNode struct {
	NodeType
	Pos
	ForExpr Node
	InExpr  Node
	Body    Node
}

func newFor(pos Pos) *ForNode {
	return &ForNode{NodeType: NodeFor, Pos: pos}
}

func (f *ForNode) String() string {
	return fmt.Sprintf("{% for %s in %s %}%s{% endfor %}", f.ForExpr, f.InExpr, f.Body)
}
func (f *ForNode) Copy() Node {
	n := newFor(f.Pos)
	n.ForExpr = f.ForExpr.Copy()
	n.InExpr = f.InExpr.Copy()
	n.Body = f.Body.Copy()
	return n
}

type BlockNode struct {
	NodeType
	Pos
	Name string
	Body Node
}

func (b *BlockNode) String() string {
	return fmt.Sprintf("{% block %s %}%s{% endblock %}", b.Name, b.Body)
}

func (b *BlockNode) Copy() Node {
	return &BlockNode{b.NodeType, b.Pos, b.Name, b.Body.Copy()}
}

type ExtendsNode struct{}
type PrintNode struct{}
type MacroNode struct{}
type IncludeNode struct{}
type FromNOde struct{}
type ImportNode struct{}
type CallNode struct{}
<|endoftext|>


<commit_before>// various small aws helper funcitons in this file
package main

import (
	"log"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/session"
)

func awsSession() (error, *session.Session) {
	sess, err := session.NewSession(&aws.Config{Region: aws.String(region)})
	if err != nil {
		log.Fatal("Failed establishing AWS session ", err)
		return err, &session.Session{}
	}
	return nil, sess
}

// helper functions for finding ids of AWS resources
func subnetFinder(s string) (error, string) { return nil, "" }
func sgFinder(s string) (error, string)     { return nil, "" }
func amiFinder(s string) (error, string)    { return nil, "" }
func vpcFinder(s string) (error, string)    { return nil, "" }
<commit_msg>Saving<commit_after>// various small aws helper funcitons in this file
package main

import (
	"log"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/session"
)

func awsSession() (error, *session.Session) {
	sess, err := session.NewSession(&aws.Config{Region: aws.String(region)})
	if err != nil {
		log.Fatal("Failed establishing AWS session ", err)
		return err, &session.Session{}
	}
	return nil, sess
}

// helper functions for finding ids of AWS resources
func subnetFinder(s string) (error, string) { return nil, "" }
func sgFinder(s string) (error, string)     { return nil, "" }
func amiFinder(s string) (error, string)    { return nil, "" }
func vpcFinder(s string) (error, string)    { return nil, "" }
<|endoftext|>


<commit_before>// Package baa provides an express Go web framework.
package baa

import (
	"log"
	"net/http"
	"os"
	"strings"
	"sync"
)

const (
	// DEV mode
	DEV = "development"
	// PROD mode
	PROD = "production"
	// TEST mode
	TEST = "test"
)

// Baa provlider an application
type Baa struct {
	debug           bool
	name            string
	di              *DI
	router          *Router
	pool            sync.Pool
	errorHandler    ErrorHandleFunc
	notFoundHandler HandlerFunc
	middleware      []HandlerFunc
}

// Middleware middleware handler
type Middleware interface{}

// HandlerFunc context handler
type HandlerFunc func(*Context)

// ErrorHandleFunc HTTP error handleFunc
type ErrorHandleFunc func(error, *Context)

// Classic create a baa application with default config.
func Classic() *Baa {
	b := New()
	b.SetErrorHandler(b.DefaultErrorHandler)
	return b
}

// New create a baa application without any config.
func New() *Baa {
	b := new(Baa)
	b.middleware = make([]HandlerFunc, 0)
	b.pool = sync.Pool{
		New: func() interface{} {
			return newContext(nil, nil, b)
		},
	}
	if os.Getenv("Baa.Env") != PROD {
		b.debug = true
	}
	b.di = newDI()
	b.router = newRouter()
	b.SetDI("logger", log.New(os.Stderr, "[Baa] ", log.LstdFlags))
	b.SetDI("render", newRender())
	return b
}

// Server returns the internal *http.Server.
func (b *Baa) Server(addr string) *http.Server {
	s := &http.Server{Addr: addr}
	return s
}

// Run runs a server.
func (b *Baa) Run(addr string) {
	b.run(b.Server(addr))
}

// RunTLS runs a server with TLS configuration.
func (b *Baa) RunTLS(addr, certfile, keyfile string) {
	b.run(b.Server(addr), certfile, keyfile)
}

// RunServer runs a custom server.
func (b *Baa) RunServer(s *http.Server) {
	b.run(s)
}

// RunTLSServer runs a custom server with TLS configuration.
func (b *Baa) RunTLSServer(s *http.Server, crtFile, keyFile string) {
	b.run(s, crtFile, keyFile)
}

func (b *Baa) run(s *http.Server, files ...string) {
	s.Handler = b
	if len(files) == 0 {
		b.Logger().Printf("Listen %s", s.Addr)
		b.Logger().Fatal(s.ListenAndServe())
	} else if len(files) == 2 {
		b.Logger().Printf("Listen %s with TLS", s.Addr)
		b.Logger().Fatal(s.ListenAndServeTLS(files[0], files[1]))
	} else {
		b.Logger().Fatal("invalid TLS configuration")
	}
}

func (b *Baa) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	c := b.pool.Get().(*Context)
	c.reset(w, r)

	// build handler chain
	if len(b.middleware) > 0 {
		c.handlers = append(c.handlers, b.middleware...)
	}

	route := b.router.match(r.Method, r.URL.Path, c)
	if route == nil || route.handlers == nil {
		// notFound
		if b.notFoundHandler == nil {
			c.handlers = append(c.handlers, func(c *Context) {
				http.NotFound(c.Resp, c.Req)
			})
		} else {
			c.handlers = append(c.handlers, b.notFoundHandler)
		}
	} else {
		c.handlers = append(c.handlers, route.handlers...)
	}

	c.Next()

	b.pool.Put(c)
}

// SetDebug set baa debug
func (b *Baa) SetDebug(v bool) {
	b.debug = v
}

// Logger return baa logger
func (b *Baa) Logger() Logger {
	return b.GetDI("logger").(Logger)
}

// Render return baa render
func (b *Baa) Render() Renderer {
	return b.GetDI("render").(Renderer)
}

// SetErrorHandler registers a custom Baa.ErrorHandleFunc.
func (b *Baa) SetErrorHandler(h ErrorHandleFunc) {
	b.errorHandler = h
}

// DefaultErrorHandler invokes the default HTTP error handler.
func (b *Baa) DefaultErrorHandler(err error, c *Context) {
	code := http.StatusInternalServerError
	msg := http.StatusText(code)
	if b.debug {
		msg = err.Error()
	}
	http.Error(c.Resp, msg, code)
}

// Use registers a middleware
func (b *Baa) Use(m ...Middleware) {
	for i := range m {
		b.middleware = append(b.middleware, wrapMiddleware(m[i]))
	}
}

// SetDI registers a dependency injection
func (b *Baa) SetDI(name string, h interface{}) {
	b.di.set(name, h)
}

// GetDI fetch a registered dependency injection
func (b *Baa) GetDI(name string) interface{} {
	return b.di.get(name)
}

// Static set static file route
// h used for set Expries ...
func (b *Baa) Static(prefix string, dir string, index bool, h HandlerFunc) {
	if prefix == "" {
		panic("baa.Static prefix can not be empty")
	}
	if dir == "" {
		panic("baa.Static dir can not be empty")
	}
	staticHandler := newStatic(prefix, dir, index, h)
	b.Get(prefix, staticHandler)
	b.Get(prefix+":file", staticHandler)
}

// SetAutoHead sets the value who determines whether add HEAD method automatically
// when GET method is added. Combo router will not be affected by this value.
func (b *Baa) SetAutoHead(v bool) {
	b.router.autoHead = v
}

// Route is a shortcut for same handlers but different HTTP methods.
//
// Example:
// 		baa.route("/", "GET,POST", h)
func (b *Baa) Route(pattern, methods string, h ...HandlerFunc) *Route {
	var ru *Route
	for _, m := range strings.Split(methods, ",") {
		ru = b.router.add(strings.TrimSpace(m), pattern, h)
	}
	return ru
}

// Group registers a list of same prefix route
func (b *Baa) Group(pattern string, f func(), h ...HandlerFunc) {
	b.router.groupAdd(pattern, f, h)
}

// Get is a shortcut for b.router.handle("GET", pattern, handlers)
func (b *Baa) Get(pattern string, h ...HandlerFunc) *Route {
	rs := b.router.add("GET", pattern, h)
	if b.router.autoHead {
		b.Head(pattern, h...)
	}
	return rs
}

// Patch is a shortcut for b.router.handle("PATCH", pattern, handlers)
func (b *Baa) Patch(pattern string, h ...HandlerFunc) *Route {
	return b.router.add("PATCH", pattern, h)
}

// Post is a shortcut for b.router.handle("POST", pattern, handlers)
func (b *Baa) Post(pattern string, h ...HandlerFunc) *Route {
	return b.router.add("POST", pattern, h)
}

// Put is a shortcut for b.router.handle("PUT", pattern, handlers)
func (b *Baa) Put(pattern string, h ...HandlerFunc) *Route {
	return b.router.add("PUT", pattern, h)
}

// Delete is a shortcut for b.router.handle("DELETE", pattern, handlers)
func (b *Baa) Delete(pattern string, h ...HandlerFunc) *Route {
	return b.router.add("DELETE", pattern, h)
}

// Options is a shortcut for b.router.handle("OPTIONS", pattern, handlers)
func (b *Baa) Options(pattern string, h ...HandlerFunc) *Route {
	return b.router.add("OPTIONS", pattern, h)
}

// Head is a shortcut for b.router.handle("HEAD", pattern, handlers)
func (b *Baa) Head(pattern string, h ...HandlerFunc) *Route {
	return b.router.add("HEAD", pattern, h)
}

// Any is a shortcut for b.router.handle("*", pattern, handlers)
func (b *Baa) Any(pattern string, h ...HandlerFunc) *Route {
	var ru *Route
	for m := range methods {
		ru = b.router.add(m, pattern, h)
	}
	return ru
}

// Error ...
func (b *Baa) Error(err error, c *Context) {
	if b.errorHandler != nil {
		b.errorHandler(err, c)
		return
	}
	http.Error(c.Resp, err.Error(), 500)
	b.Logger().Println("Error " + err.Error())
}

// setNotFoundHandler set the route not match result.
// Configurable http.HandlerFunc which is called when no matching route is
// found. If it is not set, http.NotFound is used.
// Be sure to set 404 response code in your handler.
func (b *Baa) setNotFoundHandler(h HandlerFunc) {
	b.notFoundHandler = h
}

// NotFound execute 404 handler
func (b *Baa) NotFound(c *Context) {
	if b.notFoundHandler != nil {
		b.notFoundHandler(c)
		return
	}
	http.NotFound(c.Resp, c.Req)
}

// URLFor use named route return format url
func (b *Baa) URLFor(name string, args ...interface{}) string {
	return b.router.urlFor(name, args...)
}

// wrapMiddleware wraps middleware.
func wrapMiddleware(m Middleware) HandlerFunc {
	switch m := m.(type) {
	case HandlerFunc:
		return wrapHandlerFunc(m)
	case func(*Context):
		return wrapHandlerFunc(m)
	case http.Handler:
		return wrapHandlerFunc(func(c *Context) {
			m.ServeHTTP(c.Resp, c.Req)
		})
	case func(http.ResponseWriter, *http.Request):
		return wrapHandlerFunc(func(c *Context) {
			m(c.Resp, c.Req)
		})
	default:
		panic("unknown middleware")
	}
}
<commit_msg>update middleware support types<commit_after>// Package baa provides an express Go web framework.
package baa

import (
	"log"
	"net/http"
	"os"
	"strings"
	"sync"
)

const (
	// DEV mode
	DEV = "development"
	// PROD mode
	PROD = "production"
	// TEST mode
	TEST = "test"
)

// Baa provlider an application
type Baa struct {
	debug           bool
	name            string
	di              *DI
	router          *Router
	pool            sync.Pool
	errorHandler    ErrorHandleFunc
	notFoundHandler HandlerFunc
	middleware      []HandlerFunc
}

// Middleware middleware handler
type Middleware interface{}

// HandlerFunc context handler
type HandlerFunc func(*Context)

// ErrorHandleFunc HTTP error handleFunc
type ErrorHandleFunc func(error, *Context)

// Classic create a baa application with default config.
func Classic() *Baa {
	b := New()
	b.SetErrorHandler(b.DefaultErrorHandler)
	return b
}

// New create a baa application without any config.
func New() *Baa {
	b := new(Baa)
	b.middleware = make([]HandlerFunc, 0)
	b.pool = sync.Pool{
		New: func() interface{} {
			return newContext(nil, nil, b)
		},
	}
	if os.Getenv("Baa.Env") != PROD {
		b.debug = true
	}
	b.di = newDI()
	b.router = newRouter()
	b.SetDI("logger", log.New(os.Stderr, "[Baa] ", log.LstdFlags))
	b.SetDI("render", newRender())
	return b
}

// Server returns the internal *http.Server.
func (b *Baa) Server(addr string) *http.Server {
	s := &http.Server{Addr: addr}
	return s
}

// Run runs a server.
func (b *Baa) Run(addr string) {
	b.run(b.Server(addr))
}

// RunTLS runs a server with TLS configuration.
func (b *Baa) RunTLS(addr, certfile, keyfile string) {
	b.run(b.Server(addr), certfile, keyfile)
}

// RunServer runs a custom server.
func (b *Baa) RunServer(s *http.Server) {
	b.run(s)
}

// RunTLSServer runs a custom server with TLS configuration.
func (b *Baa) RunTLSServer(s *http.Server, crtFile, keyFile string) {
	b.run(s, crtFile, keyFile)
}

func (b *Baa) run(s *http.Server, files ...string) {
	s.Handler = b
	if len(files) == 0 {
		b.Logger().Printf("Listen %s", s.Addr)
		b.Logger().Fatal(s.ListenAndServe())
	} else if len(files) == 2 {
		b.Logger().Printf("Listen %s with TLS", s.Addr)
		b.Logger().Fatal(s.ListenAndServeTLS(files[0], files[1]))
	} else {
		b.Logger().Fatal("invalid TLS configuration")
	}
}

func (b *Baa) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	c := b.pool.Get().(*Context)
	c.reset(w, r)

	// build handler chain
	if len(b.middleware) > 0 {
		c.handlers = append(c.handlers, b.middleware...)
	}

	route := b.router.match(r.Method, r.URL.Path, c)
	if route == nil || route.handlers == nil {
		// notFound
		if b.notFoundHandler == nil {
			c.handlers = append(c.handlers, func(c *Context) {
				http.NotFound(c.Resp, c.Req)
			})
		} else {
			c.handlers = append(c.handlers, b.notFoundHandler)
		}
	} else {
		c.handlers = append(c.handlers, route.handlers...)
	}

	c.Next()

	b.pool.Put(c)
}

// SetDebug set baa debug
func (b *Baa) SetDebug(v bool) {
	b.debug = v
}

// Logger return baa logger
func (b *Baa) Logger() Logger {
	return b.GetDI("logger").(Logger)
}

// Render return baa render
func (b *Baa) Render() Renderer {
	return b.GetDI("render").(Renderer)
}

// SetErrorHandler registers a custom Baa.ErrorHandleFunc.
func (b *Baa) SetErrorHandler(h ErrorHandleFunc) {
	b.errorHandler = h
}

// DefaultErrorHandler invokes the default HTTP error handler.
func (b *Baa) DefaultErrorHandler(err error, c *Context) {
	code := http.StatusInternalServerError
	msg := http.StatusText(code)
	if b.debug {
		msg = err.Error()
	}
	http.Error(c.Resp, msg, code)
}

// Use registers a middleware
func (b *Baa) Use(m ...Middleware) {
	for i := range m {
		b.middleware = append(b.middleware, wrapMiddleware(m[i]))
	}
}

// SetDI registers a dependency injection
func (b *Baa) SetDI(name string, h interface{}) {
	b.di.set(name, h)
}

// GetDI fetch a registered dependency injection
func (b *Baa) GetDI(name string) interface{} {
	return b.di.get(name)
}

// Static set static file route
// h used for set Expries ...
func (b *Baa) Static(prefix string, dir string, index bool, h HandlerFunc) {
	if prefix == "" {
		panic("baa.Static prefix can not be empty")
	}
	if dir == "" {
		panic("baa.Static dir can not be empty")
	}
	staticHandler := newStatic(prefix, dir, index, h)
	b.Get(prefix, staticHandler)
	b.Get(prefix+":file", staticHandler)
}

// SetAutoHead sets the value who determines whether add HEAD method automatically
// when GET method is added. Combo router will not be affected by this value.
func (b *Baa) SetAutoHead(v bool) {
	b.router.autoHead = v
}

// Route is a shortcut for same handlers but different HTTP methods.
//
// Example:
// 		baa.route("/", "GET,POST", h)
func (b *Baa) Route(pattern, methods string, h ...HandlerFunc) *Route {
	var ru *Route
	for _, m := range strings.Split(methods, ",") {
		ru = b.router.add(strings.TrimSpace(m), pattern, h)
	}
	return ru
}

// Group registers a list of same prefix route
func (b *Baa) Group(pattern string, f func(), h ...HandlerFunc) {
	b.router.groupAdd(pattern, f, h)
}

// Get is a shortcut for b.router.handle("GET", pattern, handlers)
func (b *Baa) Get(pattern string, h ...HandlerFunc) *Route {
	rs := b.router.add("GET", pattern, h)
	if b.router.autoHead {
		b.Head(pattern, h...)
	}
	return rs
}

// Patch is a shortcut for b.router.handle("PATCH", pattern, handlers)
func (b *Baa) Patch(pattern string, h ...HandlerFunc) *Route {
	return b.router.add("PATCH", pattern, h)
}

// Post is a shortcut for b.router.handle("POST", pattern, handlers)
func (b *Baa) Post(pattern string, h ...HandlerFunc) *Route {
	return b.router.add("POST", pattern, h)
}

// Put is a shortcut for b.router.handle("PUT", pattern, handlers)
func (b *Baa) Put(pattern string, h ...HandlerFunc) *Route {
	return b.router.add("PUT", pattern, h)
}

// Delete is a shortcut for b.router.handle("DELETE", pattern, handlers)
func (b *Baa) Delete(pattern string, h ...HandlerFunc) *Route {
	return b.router.add("DELETE", pattern, h)
}

// Options is a shortcut for b.router.handle("OPTIONS", pattern, handlers)
func (b *Baa) Options(pattern string, h ...HandlerFunc) *Route {
	return b.router.add("OPTIONS", pattern, h)
}

// Head is a shortcut for b.router.handle("HEAD", pattern, handlers)
func (b *Baa) Head(pattern string, h ...HandlerFunc) *Route {
	return b.router.add("HEAD", pattern, h)
}

// Any is a shortcut for b.router.handle("*", pattern, handlers)
func (b *Baa) Any(pattern string, h ...HandlerFunc) *Route {
	var ru *Route
	for m := range methods {
		ru = b.router.add(m, pattern, h)
	}
	return ru
}

// Error ...
func (b *Baa) Error(err error, c *Context) {
	if b.errorHandler != nil {
		b.errorHandler(err, c)
		return
	}
	http.Error(c.Resp, err.Error(), 500)
	b.Logger().Println("Error " + err.Error())
}

// setNotFoundHandler set the route not match result.
// Configurable http.HandlerFunc which is called when no matching route is
// found. If it is not set, http.NotFound is used.
// Be sure to set 404 response code in your handler.
func (b *Baa) setNotFoundHandler(h HandlerFunc) {
	b.notFoundHandler = h
}

// NotFound execute 404 handler
func (b *Baa) NotFound(c *Context) {
	if b.notFoundHandler != nil {
		b.notFoundHandler(c)
		return
	}
	http.NotFound(c.Resp, c.Req)
}

// URLFor use named route return format url
func (b *Baa) URLFor(name string, args ...interface{}) string {
	return b.router.urlFor(name, args...)
}

// wrapMiddleware wraps middleware.
func wrapMiddleware(m Middleware) HandlerFunc {
	switch m := m.(type) {
	case HandlerFunc:
		return wrapHandlerFunc(m)
	case func(*Context):
		return wrapHandlerFunc(m)
	case http.Handler:
		return wrapHandlerFunc(func(c *Context) {
			m.ServeHTTP(c.Resp, c.Req)
		})
	case http.HandlerFunc:
		return wrapHandlerFunc(func(c *Context) {
			m(c.Resp, c.Req)
		})
	case func(http.ResponseWriter, *http.Request):
		return wrapHandlerFunc(func(c *Context) {
			m(c.Resp, c.Req)
		})
	default:
		panic("unknown middleware")
	}
}
<|endoftext|>


<commit_before>package baa

import (
	"log"
	"net/http"
	"os"
	"strings"
	"sync"
)

const (
	// DEV mode
	DEV = "development"
	// PROD mode
	PROD = "production"
	// TEST mode
	TEST = "test"
)

// Env default application runtime environment
var Env string

// Baa provlider an application
type Baa struct {
	debug           bool
	name            string
	di              *DI
	router          *Router
	pool            sync.Pool
	errorHandler    ErrorHandleFunc
	notFoundHandler HandlerFunc
	middleware      []HandlerFunc
}

// Middleware middleware handler
type Middleware interface{}

// Handler context handler
type Handler interface{}

// HandlerFunc context handler func
type HandlerFunc func(*Context)

// ErrorHandleFunc HTTP error handleFunc
type ErrorHandleFunc func(error, *Context)

// New create a baa application without any config.
func New() *Baa {
	b := new(Baa)
	b.middleware = make([]HandlerFunc, 0)
	b.pool = sync.Pool{
		New: func() interface{} {
			return newContext(nil, nil, b)
		},
	}
	if Env != PROD {
		b.debug = true
	}
	b.di = newDI()
	b.router = newRouter()
	b.notFoundHandler = b.DefaultNotFoundHandler
	b.SetDI("logger", log.New(os.Stderr, "[Baa] ", log.LstdFlags))
	b.SetDI("render", newRender())
	return b
}

// Server returns the internal *http.Server.
func (b *Baa) Server(addr string) *http.Server {
	s := &http.Server{Addr: addr}
	return s
}

// Run runs a server.
func (b *Baa) Run(addr string) {
	b.run(b.Server(addr))
}

// RunTLS runs a server with TLS configuration.
func (b *Baa) RunTLS(addr, certfile, keyfile string) {
	b.run(b.Server(addr), certfile, keyfile)
}

// RunServer runs a custom server.
func (b *Baa) RunServer(s *http.Server) {
	b.run(s)
}

// RunTLSServer runs a custom server with TLS configuration.
func (b *Baa) RunTLSServer(s *http.Server, crtFile, keyFile string) {
	b.run(s, crtFile, keyFile)
}

func (b *Baa) run(s *http.Server, files ...string) {
	s.Handler = b
	if len(files) == 0 {
		b.Logger().Printf("Listen %s", s.Addr)
		b.Logger().Fatal(s.ListenAndServe())
	} else if len(files) == 2 {
		b.Logger().Printf("Listen %s with TLS", s.Addr)
		b.Logger().Fatal(s.ListenAndServeTLS(files[0], files[1]))
	} else {
		panic("invalid TLS configuration")
	}
}

func (b *Baa) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	c := b.pool.Get().(*Context)
	c.reset(w, r)

	// build handler chain
	route := b.router.match(r.Method, r.URL.Path, c)
	// notFound
	if route == nil || route.handlers == nil {
		c.handlers = append(c.handlers, b.notFoundHandler)
	} else {
		c.handlers = append(c.handlers, route.handlers...)
	}

	c.Next()

	b.pool.Put(c)
}

// SetDebug set baa debug
func (b *Baa) SetDebug(v bool) {
	b.debug = v
}

// Debug returns baa debug state
func (b *Baa) Debug() bool {
	return b.debug
}

// Logger return baa logger
func (b *Baa) Logger() Logger {
	return b.GetDI("logger").(Logger)
}

// Render return baa render
func (b *Baa) Render() Renderer {
	return b.GetDI("render").(Renderer)
}

// Use registers a middleware
func (b *Baa) Use(m ...Middleware) {
	for i := range m {
		b.middleware = append(b.middleware, wrapMiddleware(m[i]))
	}
}

// SetDI registers a dependency injection
func (b *Baa) SetDI(name string, h interface{}) {
	b.di.set(name, h)
}

// GetDI fetch a registered dependency injection
func (b *Baa) GetDI(name string) interface{} {
	return b.di.get(name)
}

// Static set static file route
// h used for set Expries ...
func (b *Baa) Static(prefix string, dir string, index bool, h HandlerFunc) {
	if prefix == "" {
		panic("baa.Static prefix can not be empty")
	}
	if dir == "" {
		panic("baa.Static dir can not be empty")
	}
	staticHandler := newStatic(prefix, dir, index, h)
	b.Get(prefix, staticHandler)
	b.Get(prefix+":file", staticHandler)
}

// SetAutoHead sets the value who determines whether add HEAD method automatically
// when GET method is added. Combo router will not be affected by this value.
func (b *Baa) SetAutoHead(v bool) {
	b.router.autoHead = v
}

// Route is a shortcut for same handlers but different HTTP methods.
//
// Example:
// 		baa.route("/", "GET,POST", h)
func (b *Baa) Route(pattern, methods string, h ...HandlerFunc) *Route {
	var ru *Route
	var ms []string
	if methods == "*" {
		ms = b.router.methods()
	} else {
		ms = strings.Split(methods, ",")
	}
	for _, m := range ms {
		ru = b.router.add(strings.TrimSpace(m), pattern, h)
	}
	return ru
}

// Group registers a list of same prefix route
func (b *Baa) Group(pattern string, f func(), h ...HandlerFunc) {
	b.router.groupAdd(pattern, f, h)
}

// Get is a shortcut for b.router.add("GET", pattern, handlers)
func (b *Baa) Get(pattern string, h ...HandlerFunc) *Route {
	rs := b.router.add("GET", pattern, h)
	if b.router.autoHead {
		b.Head(pattern, h...)
	}
	return rs
}

// Patch is a shortcut for b.router.add("PATCH", pattern, handlers)
func (b *Baa) Patch(pattern string, h ...HandlerFunc) *Route {
	return b.router.add("PATCH", pattern, h)
}

// Post is a shortcut for b.router.add("POST", pattern, handlers)
func (b *Baa) Post(pattern string, h ...HandlerFunc) *Route {
	return b.router.add("POST", pattern, h)
}

// Put is a shortcut for b.router.add("PUT", pattern, handlers)
func (b *Baa) Put(pattern string, h ...HandlerFunc) *Route {
	return b.router.add("PUT", pattern, h)
}

// Delete is a shortcut for b.router.add("DELETE", pattern, handlers)
func (b *Baa) Delete(pattern string, h ...HandlerFunc) *Route {
	return b.router.add("DELETE", pattern, h)
}

// Options is a shortcut for b.router.add("OPTIONS", pattern, handlers)
func (b *Baa) Options(pattern string, h ...HandlerFunc) *Route {
	return b.router.add("OPTIONS", pattern, h)
}

// Head is a shortcut for b.router.add("HEAD", pattern, handlers)
func (b *Baa) Head(pattern string, h ...HandlerFunc) *Route {
	return b.router.add("HEAD", pattern, h)
}

// Any is a shortcut for b.router.add("*", pattern, handlers)
func (b *Baa) Any(pattern string, h ...HandlerFunc) *Route {
	var ru *Route
	for _, m := range b.router.methods() {
		ru = b.router.add(m, pattern, h)
	}
	return ru
}

// NotFound set not found route handler
func (b *Baa) NotFound(h HandlerFunc) {
	b.notFoundHandler = h
}

// SetError set error handler
func (b *Baa) SetError(h ErrorHandleFunc) {
	b.errorHandler = h
}

// Error execute internal error handler
func (b *Baa) Error(err error, c *Context) {
	b.Logger().Println("Context Error -> " + err.Error())
	if b.errorHandler != nil {
		b.errorHandler(err, c)
		return
	}
	code := http.StatusInternalServerError
	msg := http.StatusText(code)
	if b.debug {
		msg = err.Error()
	}
	http.Error(c.Resp, msg, code)
}

// DefaultNotFoundHandler invokes the default HTTP error handler.
func (b *Baa) DefaultNotFoundHandler(c *Context) {
	code := http.StatusNotFound
	msg := http.StatusText(code)
	http.Error(c.Resp, msg, code)
}

// URLFor use named route return format url
func (b *Baa) URLFor(name string, args ...interface{}) string {
	return b.router.urlFor(name, args...)
}

// wrapMiddleware wraps middleware.
func wrapMiddleware(m Middleware) HandlerFunc {
	switch m := m.(type) {
	case HandlerFunc:
		return m
	case func(*Context):
		return m
	case http.Handler, http.HandlerFunc:
		return wrapHandlerFunc(func(c *Context) {
			m.(http.Handler).ServeHTTP(c.Resp, c.Req)
		})
	case func(http.ResponseWriter, *http.Request):
		return wrapHandlerFunc(func(c *Context) {
			m(c.Resp, c.Req)
		})
	default:
		panic("unknown middleware")
	}
}

func init() {
	Env = os.Getenv("BAA_ENV")
	if Env == "" {
		Env = DEV
	}
}
<commit_msg>fix panic when middleware is nil<commit_after>package baa

import (
	"log"
	"net/http"
	"os"
	"strings"
	"sync"
)

const (
	// DEV mode
	DEV = "development"
	// PROD mode
	PROD = "production"
	// TEST mode
	TEST = "test"
)

// Env default application runtime environment
var Env string

// Baa provlider an application
type Baa struct {
	debug           bool
	name            string
	di              *DI
	router          *Router
	pool            sync.Pool
	errorHandler    ErrorHandleFunc
	notFoundHandler HandlerFunc
	middleware      []HandlerFunc
}

// Middleware middleware handler
type Middleware interface{}

// Handler context handler
type Handler interface{}

// HandlerFunc context handler func
type HandlerFunc func(*Context)

// ErrorHandleFunc HTTP error handleFunc
type ErrorHandleFunc func(error, *Context)

// New create a baa application without any config.
func New() *Baa {
	b := new(Baa)
	b.middleware = make([]HandlerFunc, 0)
	b.pool = sync.Pool{
		New: func() interface{} {
			return newContext(nil, nil, b)
		},
	}
	if Env != PROD {
		b.debug = true
	}
	b.di = newDI()
	b.router = newRouter()
	b.notFoundHandler = b.DefaultNotFoundHandler
	b.SetDI("logger", log.New(os.Stderr, "[Baa] ", log.LstdFlags))
	b.SetDI("render", newRender())
	return b
}

// Server returns the internal *http.Server.
func (b *Baa) Server(addr string) *http.Server {
	s := &http.Server{Addr: addr}
	return s
}

// Run runs a server.
func (b *Baa) Run(addr string) {
	b.run(b.Server(addr))
}

// RunTLS runs a server with TLS configuration.
func (b *Baa) RunTLS(addr, certfile, keyfile string) {
	b.run(b.Server(addr), certfile, keyfile)
}

// RunServer runs a custom server.
func (b *Baa) RunServer(s *http.Server) {
	b.run(s)
}

// RunTLSServer runs a custom server with TLS configuration.
func (b *Baa) RunTLSServer(s *http.Server, crtFile, keyFile string) {
	b.run(s, crtFile, keyFile)
}

func (b *Baa) run(s *http.Server, files ...string) {
	s.Handler = b
	if len(files) == 0 {
		b.Logger().Printf("Listen %s", s.Addr)
		b.Logger().Fatal(s.ListenAndServe())
	} else if len(files) == 2 {
		b.Logger().Printf("Listen %s with TLS", s.Addr)
		b.Logger().Fatal(s.ListenAndServeTLS(files[0], files[1]))
	} else {
		panic("invalid TLS configuration")
	}
}

func (b *Baa) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	c := b.pool.Get().(*Context)
	c.reset(w, r)

	// build handler chain
	route := b.router.match(r.Method, r.URL.Path, c)
	// notFound
	if route == nil || route.handlers == nil {
		c.handlers = append(c.handlers, b.notFoundHandler)
	} else {
		c.handlers = append(c.handlers, route.handlers...)
	}

	c.Next()

	b.pool.Put(c)
}

// SetDebug set baa debug
func (b *Baa) SetDebug(v bool) {
	b.debug = v
}

// Debug returns baa debug state
func (b *Baa) Debug() bool {
	return b.debug
}

// Logger return baa logger
func (b *Baa) Logger() Logger {
	return b.GetDI("logger").(Logger)
}

// Render return baa render
func (b *Baa) Render() Renderer {
	return b.GetDI("render").(Renderer)
}

// Use registers a middleware
func (b *Baa) Use(m ...Middleware) {
	for i := range m {
		if m[i] != nil {
			b.middleware = append(b.middleware, wrapMiddleware(m[i]))
		}
	}
}

// SetDI registers a dependency injection
func (b *Baa) SetDI(name string, h interface{}) {
	b.di.set(name, h)
}

// GetDI fetch a registered dependency injection
func (b *Baa) GetDI(name string) interface{} {
	return b.di.get(name)
}

// Static set static file route
// h used for set Expries ...
func (b *Baa) Static(prefix string, dir string, index bool, h HandlerFunc) {
	if prefix == "" {
		panic("baa.Static prefix can not be empty")
	}
	if dir == "" {
		panic("baa.Static dir can not be empty")
	}
	staticHandler := newStatic(prefix, dir, index, h)
	b.Get(prefix, staticHandler)
	b.Get(prefix+":file", staticHandler)
}

// SetAutoHead sets the value who determines whether add HEAD method automatically
// when GET method is added. Combo router will not be affected by this value.
func (b *Baa) SetAutoHead(v bool) {
	b.router.autoHead = v
}

// Route is a shortcut for same handlers but different HTTP methods.
//
// Example:
// 		baa.route("/", "GET,POST", h)
func (b *Baa) Route(pattern, methods string, h ...HandlerFunc) *Route {
	var ru *Route
	var ms []string
	if methods == "*" {
		ms = b.router.methods()
	} else {
		ms = strings.Split(methods, ",")
	}
	for _, m := range ms {
		ru = b.router.add(strings.TrimSpace(m), pattern, h)
	}
	return ru
}

// Group registers a list of same prefix route
func (b *Baa) Group(pattern string, f func(), h ...HandlerFunc) {
	b.router.groupAdd(pattern, f, h)
}

// Get is a shortcut for b.router.add("GET", pattern, handlers)
func (b *Baa) Get(pattern string, h ...HandlerFunc) *Route {
	rs := b.router.add("GET", pattern, h)
	if b.router.autoHead {
		b.Head(pattern, h...)
	}
	return rs
}

// Patch is a shortcut for b.router.add("PATCH", pattern, handlers)
func (b *Baa) Patch(pattern string, h ...HandlerFunc) *Route {
	return b.router.add("PATCH", pattern, h)
}

// Post is a shortcut for b.router.add("POST", pattern, handlers)
func (b *Baa) Post(pattern string, h ...HandlerFunc) *Route {
	return b.router.add("POST", pattern, h)
}

// Put is a shortcut for b.router.add("PUT", pattern, handlers)
func (b *Baa) Put(pattern string, h ...HandlerFunc) *Route {
	return b.router.add("PUT", pattern, h)
}

// Delete is a shortcut for b.router.add("DELETE", pattern, handlers)
func (b *Baa) Delete(pattern string, h ...HandlerFunc) *Route {
	return b.router.add("DELETE", pattern, h)
}

// Options is a shortcut for b.router.add("OPTIONS", pattern, handlers)
func (b *Baa) Options(pattern string, h ...HandlerFunc) *Route {
	return b.router.add("OPTIONS", pattern, h)
}

// Head is a shortcut for b.router.add("HEAD", pattern, handlers)
func (b *Baa) Head(pattern string, h ...HandlerFunc) *Route {
	return b.router.add("HEAD", pattern, h)
}

// Any is a shortcut for b.router.add("*", pattern, handlers)
func (b *Baa) Any(pattern string, h ...HandlerFunc) *Route {
	var ru *Route
	for _, m := range b.router.methods() {
		ru = b.router.add(m, pattern, h)
	}
	return ru
}

// NotFound set not found route handler
func (b *Baa) NotFound(h HandlerFunc) {
	b.notFoundHandler = h
}

// SetError set error handler
func (b *Baa) SetError(h ErrorHandleFunc) {
	b.errorHandler = h
}

// Error execute internal error handler
func (b *Baa) Error(err error, c *Context) {
	b.Logger().Println("Context Error -> " + err.Error())
	if b.errorHandler != nil {
		b.errorHandler(err, c)
		return
	}
	code := http.StatusInternalServerError
	msg := http.StatusText(code)
	if b.debug {
		msg = err.Error()
	}
	http.Error(c.Resp, msg, code)
}

// DefaultNotFoundHandler invokes the default HTTP error handler.
func (b *Baa) DefaultNotFoundHandler(c *Context) {
	code := http.StatusNotFound
	msg := http.StatusText(code)
	http.Error(c.Resp, msg, code)
}

// URLFor use named route return format url
func (b *Baa) URLFor(name string, args ...interface{}) string {
	return b.router.urlFor(name, args...)
}

// wrapMiddleware wraps middleware.
func wrapMiddleware(m Middleware) HandlerFunc {
	switch m := m.(type) {
	case HandlerFunc:
		return m
	case func(*Context):
		return m
	case http.Handler, http.HandlerFunc:
		return wrapHandlerFunc(func(c *Context) {
			m.(http.Handler).ServeHTTP(c.Resp, c.Req)
		})
	case func(http.ResponseWriter, *http.Request):
		return wrapHandlerFunc(func(c *Context) {
			m(c.Resp, c.Req)
		})
	default:
		panic("unknown middleware")
	}
}

func init() {
	Env = os.Getenv("BAA_ENV")
	if Env == "" {
		Env = DEV
	}
}
<|endoftext|>


<commit_before>// Copyright 2013 bee authors
//
// 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.

// Bee is a tool for developling applications based on beego framework.
package main

import (
	"flag"
	"fmt"
	"io"
	"log"
	"os"
	"strings"
	"text/template"
)

const version = "1.6.0"

// Command is the unit of execution
type Command struct {
	// Run runs the command.
	// The args are the arguments after the command name.
	Run func(cmd *Command, args []string) int

	// PreRun performs an operation before running the command
	PreRun func(cmd *Command, args []string)

	// UsageLine is the one-line usage message.
	// The first word in the line is taken to be the command name.
	UsageLine string

	// Short is the short description shown in the 'go help' output.
	Short string

	// Long is the long message shown in the 'go help <this-command>' output.
	Long string

	// Flag is a set of flags specific to this command.
	Flag flag.FlagSet

	// CustomFlags indicates that the command will do its own
	// flag parsing.
	CustomFlags bool

	// output out writer if set in SetOutput(w)
	output *io.Writer
}

// Name returns the command's name: the first word in the usage line.
func (c *Command) Name() string {
	name := c.UsageLine
	i := strings.Index(name, " ")
	if i >= 0 {
		name = name[:i]
	}
	return name
}

// SetOutput sets the destination for usage and error messages.
// If output is nil, os.Stderr is used.
func (c *Command) SetOutput(output io.Writer) {
	c.output = &output
}

// Out returns the out writer of the current command.
// If cmd.output is nil, os.Stderr is used.
func (c *Command) Out() io.Writer {
	if c.output != nil {
		return *c.output
	}
	return NewColorWriter(os.Stderr)
}

// Usage puts out the usage for the command.
func (c *Command) Usage() {
	tmpl(cmdUsage, c)
	os.Exit(2)
}

// Runnable reports whether the command can be run; otherwise
// it is a documentation pseudo-command such as importpath.
func (c *Command) Runnable() bool {
	return c.Run != nil
}

func (c *Command) Options() map[string]string {
	options := make(map[string]string)
	c.Flag.VisitAll(func(f *flag.Flag) {
		defaultVal := f.DefValue
		if len(defaultVal) > 0 {
			if strings.Contains(defaultVal, ":") {
				// Truncate the flag's default value by appending '...' at the end
				options[f.Name+"="+strings.Split(defaultVal, ":")[0]+":..."] = f.Usage
			} else {
				options[f.Name+"="+defaultVal] = f.Usage
			}
		} else {
			options[f.Name] = f.Usage
		}
	})
	return options
}

var availableCommands = []*Command{
	cmdNew,
	cmdRun,
	cmdPack,
	cmdApiapp,
	cmdHproseapp,
	//cmdRouter,
	//cmdTest,
	cmdBale,
	cmdVersion,
	cmdGenerate,
	//cmdRundocs,
	cmdMigrate,
	cmdFix,
}

var logger = GetBeeLogger(os.Stdout)

func main() {
	currentpath, _ := os.Getwd()

	flag.Usage = usage
	flag.Parse()
	log.SetFlags(0)

	args := flag.Args()

	if len(args) < 1 {
		usage()
	}

	if args[0] == "help" {
		help(args[1:])
		return
	}

	for _, cmd := range availableCommands {
		if cmd.Name() == args[0] && cmd.Run != nil {
			cmd.Flag.Usage = func() { cmd.Usage() }
			if cmd.CustomFlags {
				args = args[1:]
			} else {
				cmd.Flag.Parse(args[1:])
				args = cmd.Flag.Args()
			}

			if cmd.PreRun != nil {
				cmd.PreRun(cmd, args)
			}

			// Check if current directory is inside the GOPATH,
			// if so parse the packages inside it.
			if strings.Contains(currentpath, GetGOPATHs()[0]+"/src") {
				parsePackagesFromDir(currentpath)
			}

			os.Exit(cmd.Run(cmd, args))
			return
		}
	}

	printErrorAndExit("Unknown subcommand")
}

var usageTemplate = `Bee is a Fast and Flexible tool for managing your Beego Web Application.

{{"USAGE" | headline}}
    {{"bee command [arguments]" | bold}}

{{"AVAILABLE COMMANDS" | headline}}
{{range .}}{{if .Runnable}}
    {{.Name | printf "%-11s" | bold}} {{.Short}}{{end}}{{end}}

Use {{"bee help [command]" | bold}} for more information about a command.

{{"ADDITIONAL HELP TOPICS" | headline}}
{{range .}}{{if not .Runnable}}
    {{.Name | printf "%-11s"}} {{.Short}}{{end}}{{end}}

Use {{"bee help [topic]" | bold}} for more information about that topic.
`

var helpTemplate = `{{"USAGE" | headline}}
  {{.UsageLine | printf "bee %s" | bold}}
{{if .Options}}{{endline}}{{"OPTIONS" | headline}}{{range $k,$v := .Options}}
  {{$k | printf "-%-12s" | bold}} {{$v}}{{end}}{{endline}}{{end}}
{{"DESCRIPTION" | headline}}
  {{tmpltostr .Long . | trim}}
`

var errorTemplate = `bee: %s.
Use {{"bee help" | bold}} for more information.
`

var cmdUsage = `Use {{printf "bee help %s" .Name | bold}} for more information.{{endline}}`

func usage() {
	tmpl(usageTemplate, availableCommands)
	os.Exit(2)
}

func tmpl(text string, data interface{}) {
	output := NewColorWriter(os.Stderr)

	t := template.New("usage").Funcs(BeeFuncMap())
	template.Must(t.Parse(text))

	err := t.Execute(output, data)
	MustCheck(err)
}

func help(args []string) {
	if len(args) == 0 {
		usage()
	}
	if len(args) != 1 {
		printErrorAndExit("Too many arguments")
	}

	arg := args[0]

	for _, cmd := range availableCommands {
		if cmd.Name() == arg {
			tmpl(helpTemplate, cmd)
			return
		}
	}
	printErrorAndExit("Unknown help topic")
}

func printErrorAndExit(message string) {
	tmpl(fmt.Sprintf(errorTemplate, message), nil)
	os.Exit(2)
}
<commit_msg>v1.6.1<commit_after>// Copyright 2013 bee authors
//
// 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.

// Bee is a tool for developling applications based on beego framework.
package main

import (
	"flag"
	"fmt"
	"io"
	"log"
	"os"
	"strings"
	"text/template"
)

const version = "1.6.1"

// Command is the unit of execution
type Command struct {
	// Run runs the command.
	// The args are the arguments after the command name.
	Run func(cmd *Command, args []string) int

	// PreRun performs an operation before running the command
	PreRun func(cmd *Command, args []string)

	// UsageLine is the one-line usage message.
	// The first word in the line is taken to be the command name.
	UsageLine string

	// Short is the short description shown in the 'go help' output.
	Short string

	// Long is the long message shown in the 'go help <this-command>' output.
	Long string

	// Flag is a set of flags specific to this command.
	Flag flag.FlagSet

	// CustomFlags indicates that the command will do its own
	// flag parsing.
	CustomFlags bool

	// output out writer if set in SetOutput(w)
	output *io.Writer
}

// Name returns the command's name: the first word in the usage line.
func (c *Command) Name() string {
	name := c.UsageLine
	i := strings.Index(name, " ")
	if i >= 0 {
		name = name[:i]
	}
	return name
}

// SetOutput sets the destination for usage and error messages.
// If output is nil, os.Stderr is used.
func (c *Command) SetOutput(output io.Writer) {
	c.output = &output
}

// Out returns the out writer of the current command.
// If cmd.output is nil, os.Stderr is used.
func (c *Command) Out() io.Writer {
	if c.output != nil {
		return *c.output
	}
	return NewColorWriter(os.Stderr)
}

// Usage puts out the usage for the command.
func (c *Command) Usage() {
	tmpl(cmdUsage, c)
	os.Exit(2)
}

// Runnable reports whether the command can be run; otherwise
// it is a documentation pseudo-command such as importpath.
func (c *Command) Runnable() bool {
	return c.Run != nil
}

func (c *Command) Options() map[string]string {
	options := make(map[string]string)
	c.Flag.VisitAll(func(f *flag.Flag) {
		defaultVal := f.DefValue
		if len(defaultVal) > 0 {
			if strings.Contains(defaultVal, ":") {
				// Truncate the flag's default value by appending '...' at the end
				options[f.Name+"="+strings.Split(defaultVal, ":")[0]+":..."] = f.Usage
			} else {
				options[f.Name+"="+defaultVal] = f.Usage
			}
		} else {
			options[f.Name] = f.Usage
		}
	})
	return options
}

var availableCommands = []*Command{
	cmdNew,
	cmdRun,
	cmdPack,
	cmdApiapp,
	cmdHproseapp,
	//cmdRouter,
	//cmdTest,
	cmdBale,
	cmdVersion,
	cmdGenerate,
	//cmdRundocs,
	cmdMigrate,
	cmdFix,
}

var logger = GetBeeLogger(os.Stdout)

func main() {
	currentpath, _ := os.Getwd()

	flag.Usage = usage
	flag.Parse()
	log.SetFlags(0)

	args := flag.Args()

	if len(args) < 1 {
		usage()
	}

	if args[0] == "help" {
		help(args[1:])
		return
	}

	for _, cmd := range availableCommands {
		if cmd.Name() == args[0] && cmd.Run != nil {
			cmd.Flag.Usage = func() { cmd.Usage() }
			if cmd.CustomFlags {
				args = args[1:]
			} else {
				cmd.Flag.Parse(args[1:])
				args = cmd.Flag.Args()
			}

			if cmd.PreRun != nil {
				cmd.PreRun(cmd, args)
			}

			// Check if current directory is inside the GOPATH,
			// if so parse the packages inside it.
			if strings.Contains(currentpath, GetGOPATHs()[0]+"/src") {
				parsePackagesFromDir(currentpath)
			}

			os.Exit(cmd.Run(cmd, args))
			return
		}
	}

	printErrorAndExit("Unknown subcommand")
}

var usageTemplate = `Bee is a Fast and Flexible tool for managing your Beego Web Application.

{{"USAGE" | headline}}
    {{"bee command [arguments]" | bold}}

{{"AVAILABLE COMMANDS" | headline}}
{{range .}}{{if .Runnable}}
    {{.Name | printf "%-11s" | bold}} {{.Short}}{{end}}{{end}}

Use {{"bee help [command]" | bold}} for more information about a command.

{{"ADDITIONAL HELP TOPICS" | headline}}
{{range .}}{{if not .Runnable}}
    {{.Name | printf "%-11s"}} {{.Short}}{{end}}{{end}}

Use {{"bee help [topic]" | bold}} for more information about that topic.
`

var helpTemplate = `{{"USAGE" | headline}}
  {{.UsageLine | printf "bee %s" | bold}}
{{if .Options}}{{endline}}{{"OPTIONS" | headline}}{{range $k,$v := .Options}}
  {{$k | printf "-%-12s" | bold}} {{$v}}{{end}}{{endline}}{{end}}
{{"DESCRIPTION" | headline}}
  {{tmpltostr .Long . | trim}}
`

var errorTemplate = `bee: %s.
Use {{"bee help" | bold}} for more information.
`

var cmdUsage = `Use {{printf "bee help %s" .Name | bold}} for more information.{{endline}}`

func usage() {
	tmpl(usageTemplate, availableCommands)
	os.Exit(2)
}

func tmpl(text string, data interface{}) {
	output := NewColorWriter(os.Stderr)

	t := template.New("usage").Funcs(BeeFuncMap())
	template.Must(t.Parse(text))

	err := t.Execute(output, data)
	MustCheck(err)
}

func help(args []string) {
	if len(args) == 0 {
		usage()
	}
	if len(args) != 1 {
		printErrorAndExit("Too many arguments")
	}

	arg := args[0]

	for _, cmd := range availableCommands {
		if cmd.Name() == arg {
			tmpl(helpTemplate, cmd)
			return
		}
	}
	printErrorAndExit("Unknown help topic")
}

func printErrorAndExit(message string) {
	tmpl(fmt.Sprintf(errorTemplate, message), nil)
	os.Exit(2)
}
<|endoftext|>