<commit_before>package picol

import (
	"unicode"
	"unicode/utf8"
)

const (
	PT_ESC = iota
	PT_STR
	PT_CMD
	PT_VAR
	PT_SEP
	PT_EOL
	PT_EOF
)

type Token struct {
	Text string
	T    int
}

type Parser struct {
	text              string
	p, start, end, ln int
	insidequote       int
	Type              int
}

func InitParser(text string) *Parser {
	return &Parser{text, 0, 0, 0, len(text), 0, PT_EOL}
}

func (p *Parser) next() {
	_, w := utf8.DecodeRuneInString(p.text[p.p:])
	p.p += w
	p.ln -= w
}

func (p *Parser) current() rune {
	r, _ := utf8.DecodeRuneInString(p.text[p.p:])
	return r
}

func (p *Parser) token() (t string) {
	defer recover()
	return p.text[p.start:p.end]
}

func (p *Parser) parseSep() string {
	p.start = p.p
	for ; p.p < len(p.text); p.next() {
		if !unicode.IsSpace(p.current()) {
			break
		}
	}
	p.end = p.p
	p.Type = PT_SEP
	return p.token()
}

func (p *Parser) parseEol() string {
	p.start = p.p

Loop:
	for ; p.p < len(p.text); p.next() {
		switch {
		case p.current() == ';':
		case unicode.IsSpace(p.current()):
		default:
			break Loop
		}
	}

	p.end = p.p
	p.Type = PT_EOL
	return p.token()
}

func (p *Parser) parseCommand() string {
	level, blevel := 1, 0
	p.next() // skip
	p.start = p.p
Loop:
	for {
		switch {
		case p.ln == 0:
			break Loop
		case p.current() == '[' && blevel == 0:
			level++
		case p.current() == ']' && blevel == 0:
			level--
			if level == 0 {
				break Loop
			}
		case p.current() == '\\':
			p.next()
		case p.current() == '{':
			blevel++
		case p.current() == '}' && blevel != 0:
			blevel--
		}
		p.next()
	}
	p.end = p.p
	p.Type = PT_CMD
	if p.p < len(p.text) && p.current() == ']' {
		p.next()
	}
	return p.token()
}

func (p *Parser) parseVar() string {
	p.next() // skip the $
	p.start = p.p

	for p.p < len(p.text) {
		c := p.current()
		//if (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_' {
		if unicode.IsLetter(c) || unicode.IsDigit(c) || c == '_' {
			p.next()
			continue
		}
		break
	}

	if p.start == p.p { // It's just a single char string "$"
		p.start = p.p - 1
		p.end = p.p
		p.Type = PT_STR
	} else {
		p.end = p.p
		p.Type = PT_VAR
	}
	return p.token()
}

func (p *Parser) parseBrace() string {
	level := 1
	p.next() // skip
	p.start = p.p

Loop:
	for p.p < len(p.text) {
		c := p.current()
		switch {
		case p.ln >= 2 && c == '\\':
			p.next()
		case p.ln == 0 || c == '}':
			level--
			if level == 0 || p.ln == 0 {
				break Loop
			}
		case c == '{':
			level++
		}
		p.next()
	}
	p.end = p.p
	if p.ln != 0 { // Skip final closed brace
		p.next()
	}
	p.Type = PT_STR
	return p.token()
}

func (p *Parser) parseString() string {
	newword := p.Type == PT_SEP || p.Type == PT_EOL || p.Type == PT_STR

	if c := p.current(); newword && c == '{' {
		return p.parseBrace()
	} else if newword && c == '"' {
		p.insidequote = 1
		p.next() // skip
	}

	p.start = p.p

Loop:
	for {
		if p.ln == 0 {
			break Loop
		}
		switch p.current() {
		case '\\':
			if p.ln >= 2 {
				p.next()
			}
		case '$':
		case '[':
			break Loop
		case ' ', '\t', '\n', '\r', ';':
			if p.insidequote == 0 {
				break Loop
			}
		case '"':
			if p.insidequote != 0 {
				p.end = p.p
				p.Type = PT_ESC
				p.next()
				p.insidequote = 0
				return p.token()
			}
		}
		p.next()
	}

	p.end = p.p
	p.Type = PT_ESC
	return p.token() /* unreached */
}

func (p *Parser) parseComment() string {
	for p.ln != 0 && p.current() != '\n' {
		p.next()
	}
	return p.token()
}

func (p *Parser) GetToken() string {
	for {
		if p.ln == 0 {
			if p.Type != PT_EOL && p.Type != PT_EOF {
				p.Type = PT_EOL
			} else {
				p.Type = PT_EOF
			}
			return p.token()
		}

		switch p.current() {
		case ' ', '\t', '\r':
			if p.insidequote != 0 {
				return p.parseString()
			}
			return p.parseSep()
		case '\n', ';':
			if p.insidequote != 0 {
				return p.parseString()
			}
			return p.parseEol()
		case '[':
			return p.parseCommand()
		case '$':
			return p.parseVar()
		case '#':
			if p.Type == PT_EOL {
				p.parseComment()
				continue
			}
			return p.parseString()
		default:
			return p.parseString()
		}
	}
	return p.token() /* unreached */
}
<commit_msg>fix parser<commit_after>package picol

import (
	"unicode"
	"unicode/utf8"
)

const (
	PT_ESC = iota
	PT_STR
	PT_CMD
	PT_VAR
	PT_SEP
	PT_EOL
	PT_EOF
)

type Parser struct {
	text              string
	p, start, end, ln int
	insidequote       int
	Type              int
}

func InitParser(text string) *Parser {
	return &Parser{text, 0, 0, 0, len(text), 0, PT_EOL}
}

func (p *Parser) next() {
	_, w := utf8.DecodeRuneInString(p.text[p.p:])
	p.p += w
	p.ln -= w
}

func (p *Parser) current() rune {
	r, _ := utf8.DecodeRuneInString(p.text[p.p:])
	return r
}

func (p *Parser) token() (t string) {
	defer recover()
	return p.text[p.start:p.end]
}

func (p *Parser) parseSep() string {
	p.start = p.p
	for ; p.p < len(p.text); p.next() {
		if !unicode.IsSpace(p.current()) {
			break
		}
	}
	p.end = p.p
	p.Type = PT_SEP
	return p.token()
}

func (p *Parser) parseEol() string {
	p.start = p.p

	for ; p.p < len(p.text); p.next() {
		if p.current() == ';' || unicode.IsSpace(p.current()) {
			// pass
		} else {
			break
		}
	}

	p.end = p.p
	p.Type = PT_EOL
	return p.token()
}

func (p *Parser) parseCommand() string {
	level, blevel := 1, 0
	p.next() // skip
	p.start = p.p
Loop:
	for {
		switch {
		case p.ln == 0:
			break Loop
		case p.current() == '[' && blevel == 0:
			level++
		case p.current() == ']' && blevel == 0:
			level--
			if level == 0 {
				break Loop
			}
		case p.current() == '\\':
			p.next()
		case p.current() == '{':
			blevel++
		case p.current() == '}' && blevel != 0:
			blevel--
		}
		p.next()
	}
	p.end = p.p
	p.Type = PT_CMD
	if p.p < len(p.text) && p.current() == ']' {
		p.next()
	}
	return p.token()
}

func (p *Parser) parseVar() string {
	p.next() // skip the $
	p.start = p.p

	for p.p < len(p.text) {
		c := p.current()
		if unicode.IsLetter(c) || unicode.IsDigit(c) || c == '_' {
			p.next()
			continue
		}
		break
	}

	if p.start == p.p { // It's just a single char string "$"
		p.start = p.p - 1
		p.end = p.p
		p.Type = PT_STR
	} else {
		p.end = p.p
		p.Type = PT_VAR
	}
	return p.token()
}

func (p *Parser) parseBrace() string {
	level := 1
	p.next() // skip
	p.start = p.p

Loop:
	for p.p < len(p.text) {
		c := p.current()
		switch {
		case p.ln >= 2 && c == '\\':
			p.next()
		case p.ln == 0 || c == '}':
			level--
			if level == 0 || p.ln == 0 {
				break Loop
			}
		case c == '{':
			level++
		}
		p.next()
	}
	p.end = p.p
	if p.ln != 0 { // Skip final closed brace
		p.next()
	}
	p.Type = PT_STR
	return p.token()
}

func (p *Parser) parseString() string {
	newword := p.Type == PT_SEP || p.Type == PT_EOL || p.Type == PT_STR

	if c := p.current(); newword && c == '{' {
		return p.parseBrace()
	} else if newword && c == '"' {
		p.insidequote = 1
		p.next() // skip
	}

	p.start = p.p

Loop:
	for {
		if p.ln == 0 {
			break Loop
		}
		switch p.current() {
		case '\\':
			if p.ln >= 2 {
				p.next()
			}
		case '$', '[':
			break Loop
		case '"':
			if p.insidequote != 0 {
				p.end = p.p
				p.Type = PT_ESC
				p.next()
				p.insidequote = 0
				return p.token()
			}
		}

		if p.current() == ';' || unicode.IsSpace(p.current()) {
			if p.insidequote == 0 {
				break Loop
			}
		}

		p.next()
	}

	p.end = p.p
	p.Type = PT_ESC
	return p.token() /* unreached */
}

func (p *Parser) parseComment() string {
	for p.ln != 0 && p.current() != '\n' {
		p.next()
	}
	return p.token()
}

func (p *Parser) GetToken() string {
	for {
		if p.ln == 0 {
			if p.Type != PT_EOL && p.Type != PT_EOF {
				p.Type = PT_EOL
			} else {
				p.Type = PT_EOF
			}
			return p.token()
		}

		switch p.current() {
		case ' ', '\t', '\r':
			if p.insidequote != 0 {
				return p.parseString()
			}
			return p.parseSep()
		case '\n', ';':
			if p.insidequote != 0 {
				return p.parseString()
			}
			return p.parseEol()
		case '[':
			return p.parseCommand()
		case '$':
			return p.parseVar()
		case '#':
			if p.Type == PT_EOL {
				p.parseComment()
				continue
			}
			return p.parseString()
		default:
			return p.parseString()
		}
	}
	return p.token() /* unreached */
}
<|endoftext|>


<commit_before>// Copyright 2016 Steven Oud. All rights reserved.
// Use of this source code is governed by a MIT-style license that can be found
// in the LICENSE file.

package mathcat

import (
	"errors"
	"fmt"
	"math"
	"strconv"
)

// Parser holds the lexed tokens, token position, declared variables and stacks
// used throughout the parsing of an expression.
//
// By default, variables always contains the constants defined below. These can
// however be overwritten.
type Parser struct {
	Tokens    Tokens
	Variables map[string]float64

	pos int
	tok *Token

	operands, operators, arity stack
}

var (
	errDivionByZero         = errors.New("Divison by zero")
	errUnmatchedParentheses = errors.New("Unmatched parentheses")
	errMisplacedComma       = errors.New("Misplaced ‘,’")
)

// Some useful predefined variables that can be used in expressions. These
// can be overwritten.
var constants = map[string]float64{
	"pi":  math.Pi,
	"tau": math.Pi * 2,
	"phi": math.Phi,
	"e":   math.E,
}

// New initializes a new Parser instance, useful when you want to run multiple
// expression and/or use variables.
func New() *Parser {
	return &Parser{
		pos:       0,
		Variables: constants,
	}
}

// Eval evaluates an expression and returns its result and any errors found.
//
// Example:
//     res, err := mathcat.Eval("2 * 2 * 2") // 8
func Eval(expr string) (float64, error) {
	tokens, err := Lex(expr)

	// If a lexer error occurred don't parse
	if err != nil {
		return -1, err
	}

	p := New()
	p.Tokens = tokens

	return p.parse()
}

// Run executes an expression on an existing parser instance. Useful for
// variable assignment.
//
// Example:
//     p.Run("a = 555")
//     p.Run("a += 45")
//     res, err := p.Run("a + a") // 1200
func (p *Parser) Run(expr string) (float64, error) {
	tokens, err := Lex(expr)

	if err != nil {
		return -1, err
	}

	p.reset()
	p.Tokens = tokens

	return p.parse()
}

// Exec executes an expression with a given map of variables.
//
// Example:
//     res, err := mathcat.Exec("a + b * b", map[string]float64{
//         "a": 1,
//         "b": 3,
//     }) // 10
func Exec(expr string, vars map[string]float64) (float64, error) {
	tokens, err := Lex(expr)

	if err != nil {
		return -1, err
	}

	p := New()
	p.Tokens = tokens

	for name, val := range vars {
		if !IsValidIdent(name) {
			return -1, fmt.Errorf("Invalid variable name: ‘%s’", name)
		}
		p.Variables[name] = val
	}

	return p.parse()
}

// GetVar gets an existing variable.
//
// Example:
//     p.Run("酷 = -33")
//     if val, err := p.GetVar("酷"); !err {
//         fmt.Printf("%f\n", val) // -33
//     }
func (p *Parser) GetVar(index string) (float64, error) {
	if val, ok := p.Variables[index]; ok {
		return val, nil
	}

	return -1, fmt.Errorf("Undefined variable ‘%s’", index)
}

func (p *Parser) parse() (float64, error) {
	var o1, o2 *operator

	// Initializing current token value
	p.tok = p.Tokens[0]

	for !p.eat().Is(EOL) {
		switch {
		case p.tok.IsLiteral():
			if p.peek().Is(LPAREN) {
				// It's a function call, push to operators stack instead
				p.operators.Push(p.tok)

				// Check ahead if the function call has any argument at all, so
				// we can do accurate tracking of arity
				if p.peekN(2).Is(RPAREN) {
					p.arity.Push(0)
				} else {
					p.arity.Push(1)
				}
				break
			}
			p.operands.Push(p.tok)
		case p.tok.Is(LPAREN):
			p.operators.Push(p.tok)
		case p.tok.Is(COMMA):
			for {
				if p.operators.Empty() {
					return -1, errMisplacedComma
				}

				if p.operators.Top().(*Token).Is(LPAREN) {
					break
				}

				val, err := p.evaluate(p.operators.Pop().(*Token))
				if err != nil {
					return -1, err
				}

				p.operands.Push(val)
			}
			p.arity.Push(p.arity.Pop().(int) + 1)
		case p.tok.IsOperator():
			o1 = operators[p.tok.Type]

			if !p.operators.Empty() {
				if p.operators.Top().(*Token).Is(IDENT) {
					// Special case, if the token on top of the operators stack is
					// a function call, always take precedence above an operator.
					function := p.operators.Pop().(*Token)
					val, err := p.evaluateFunc(function)
					if err != nil {
						return -1, err
					}

					p.operands.Push(val)

					if p.operators.Empty() {
						p.operators.Push(p.tok)
						break
					}
				}

				// If the item on top of the operators stack isn't an
				// operator, it's a function call. We then don't need to check
				// precedence.
				if !p.operators.Top().(*Token).IsOperator() {
					p.operators.Push(p.tok)
					break
				}

				o2 = operators[p.operators.Top().(*Token).Type]

				if o2.hasHigherPrecThan(o1) {
					operator := p.operators.Pop().(*Token)
					val, err := p.evaluateOp(operator)
					if err != nil {
						return -1, err
					}
					p.operands.Push(val)
				}
			}
			p.operators.Push(p.tok)
		case p.tok.Is(RPAREN):
			for {
				if p.operators.Empty() {
					return -1, errUnmatchedParentheses
				}

				top := p.operators.Pop().(*Token)
				if top.Is(LPAREN) {
					break
				}

				val, err := p.evaluate(top)
				if err != nil {
					return -1, err
				}

				p.operands.Push(val)
			}
		}
	}

	// Evaluate remaining operators
	for !p.operators.Empty() {
		top := p.operators.Pop().(*Token)

		if top.Is(LPAREN) {
			return -1, errUnmatchedParentheses
		}

		val, err := p.evaluate(top)
		if err != nil {
			return -1, err
		}

		p.operands.Push(val)
	}

	// If there are no operands, the expression is useless and doesn't do
	// anything, for example `()` or an empty string
	if p.operands.Empty() {
		return 0, nil
	}

	// Single operand left means the expression was evaluated successful
	if len(p.operands) == 1 {
		return p.lookup(p.operands[0])
	}

	// Leftover token on operand stack indicates invalid syntax
	return -1, fmt.Errorf("Unexpected ‘%s’", p.operands.Top())
}

// evaluate gets called when an operator or function call has to be evaluated
// for a result. In case of a function, evaluateFunc is called and in case of
// an operator evaluateOp is called.
func (p *Parser) evaluate(tok *Token) (float64, error) {
	if tok.IsOperator() {
		return p.evaluateOp(tok)
	}

	return p.evaluateFunc(tok)
}

func (p *Parser) evaluateFunc(tok *Token) (float64, error) {
	var (
		function *function
		ok       bool
		i        int
	)

	if function, ok = funcs[tok.Value]; !ok {
		return -1, fmt.Errorf("Undefined function ‘%s’", tok.Value)
	}

	if arity := p.arity.Pop().(int); arity != function.arity {
		return -1, fmt.Errorf("Invalid argument count for ‘%s’ (expected %d, got %d)", tok.Value, function.arity, arity)
	}

	// Start popping off arguments for the function call
	args := make([]float64, function.arity)
	for i = function.arity - 1; i >= 0; i-- {
		if p.operands.Empty() {
			return -1, errMisplacedComma
		}

		arg, err := p.lookup(p.operands.Pop())
		if err != nil {
			return -1, err
		}

		args[i] = arg
	}

	return function.fn(args), nil
}

func (p *Parser) evaluateOp(operator *Token) (float64, error) {
	var (
		result      float64
		left, right float64
		err         error
		lhsToken    interface{}
	)

	if p.operands.Empty() {
		return -1, fmt.Errorf("Unexpected ‘%s’", operator.Type)
	}

	if right, err = p.lookup(p.operands.Pop()); err != nil {
		return -1, err
	}

	// Unary operators have no left hand side
	if op := operators[operator.Type]; !op.unary {
		if p.operands.Empty() {
			return -1, fmt.Errorf("Unexpected ‘%s’", operator.Value)
		}
		// Save the token in case of a assignment variable is used and we need
		// to save the result in a variable
		lhsToken = p.operands.Pop()

		// Don't lookup the left hand side if = is used so we can do initial
		// assignment
		if !operator.Is(EQ) {
			left, err = p.lookup(lhsToken)
			if err != nil {
				return -1, err
			}
		}
	}

	result, err = execute(operator, left, right)
	if err != nil {
		return -1, err
	}

	if operator.IsAssignment() {
		// Save result in variable
		if !lhsToken.(*Token).Is(IDENT) {
			return -1, errors.New("Can't assign to literal")
		}
		p.Variables[lhsToken.(*Token).Value] = result
	}

	return result, nil
}

func execute(operator *Token, lhs, rhs float64) (float64, error) {
	var result float64

	// Both lhs and rhs have to be whole numbers for bitwise operations
	if operator.IsBitwise() && (!IsWholeNumber(lhs) || !IsWholeNumber(rhs)) {
		return -1, fmt.Errorf("Unsupported type (float) for ‘%s’", operator.Type)
	}

	switch operator.Type {
	case ADD, ADD_EQ:
		result = lhs + rhs
	case SUB, SUB_EQ:
		result = lhs - rhs
	case UNARY_MIN:
		result = -rhs
	case DIV, DIV_EQ:
		if rhs == 0 {
			return -1, errDivionByZero
		}
		result = lhs / rhs
	case MUL, MUL_EQ:
		result = lhs * rhs
	case POW, POW_EQ:
		result = math.Pow(lhs, rhs)
	case REM, REM_EQ:
		if rhs == 0 {
			return -1, errDivionByZero
		}
		result = math.Mod(lhs, rhs)
	case AND, AND_EQ:
		result = float64(int64(lhs) & int64(rhs))
	case OR, OR_EQ:
		result = float64(int64(lhs) | int64(rhs))
	case XOR, XOR_EQ:
		result = float64(int64(lhs) ^ int64(rhs))
	case LSH, LSH_EQ:
		result = float64(uint64(lhs) << uint64(rhs))
	case RSH, RSH_EQ:
		result = float64(uint64(lhs) >> uint64(rhs))
	case NOT:
		result = float64(^int64(rhs))
	case EQ:
		result = rhs
	case EQ_EQ:
		result = bool2float(lhs == rhs)
	case BANG_EQ:
		result = bool2float(lhs != rhs)
	case GT:
		result = bool2float(lhs > rhs)
	case GT_EQ:
		result = bool2float(lhs >= rhs)
	case LT:
		result = bool2float(lhs < rhs)
	case LT_EQ:
		result = bool2float(lhs <= rhs)
	default:
		return -1, fmt.Errorf("Invalid operator ‘%s’", operator.Type)
	}

	return result, nil
}

// Look up a literal. If it's an identifier, check the parser's variables map,
// otherwise convert the tokenized string to a float64.
func (p *Parser) lookup(val interface{}) (float64, error) {
	// val can be a token or a float64, if it's a float64 it has been already
	// evaluated and we don't need to do anything
	if v, ok := val.(float64); ok {
		return v, nil
	}

	var (
		tmp uint64
		res float64
		err error
	)

	bases := [...]int{
		HEX:    16,
		BINARY: 2,
		OCTAL:  8,
	}

	tok := val.(*Token)
	switch tok.Type {
	case NUMBER:
		res, err = strconv.ParseFloat(tok.Value, 64)
	case HEX, BINARY, OCTAL:
		// Remove 0x part of literal and convert to uint first
		tmp, err = strconv.ParseUint(tok.Value[2:], bases[tok.Type], 64)

		// Then convert to float
		res = float64(tmp)
	case IDENT:
		res, err = p.GetVar(tok.Value)
		if err != nil {
			return -1, err
		}
		return res, nil
	default:
		return -1, fmt.Errorf("Invalid lookup type ‘%s’", tok.Type)
	}

	if err != nil {
		if numError, ok := err.(*strconv.NumError); ok && numError.Err == strconv.ErrRange {
			return -1, fmt.Errorf("Error parsing ‘%s’: %s", tok.Value, strconv.ErrRange)
		}
		return -1, fmt.Errorf("Error parsing ‘%s’: invalid %s", tok.Value, tok.Type)
	}

	return res, nil
}

func (p *Parser) reset() {
	p.Tokens = nil
	p.pos = 0

	p.operators = nil
	p.operands = nil
	p.arity = nil
}

func (p *Parser) peek() *Token {
	return p.Tokens[p.pos]
}

func (p *Parser) peekN(n int) *Token {
	return p.Tokens[p.pos-1+n]
}

func (p *Parser) eat() *Token {
	p.tok = p.peek()
	p.pos++
	return p.tok
}

// IsWholeNumber checks if a float is a whole number
func IsWholeNumber(n float64) bool {
	return float64(int64(n)) == n
}

func bool2float(b bool) float64 {
	if b {
		return 1
	}
	return 0
}
<commit_msg>Remove incorrect statement in a comment<commit_after>// Copyright 2016 Steven Oud. All rights reserved.
// Use of this source code is governed by a MIT-style license that can be found
// in the LICENSE file.

package mathcat

import (
	"errors"
	"fmt"
	"math"
	"strconv"
)

// Parser holds the lexed tokens, token position, declared variables and stacks
// used throughout the parsing of an expression.
//
// By default, variables always contains the constants defined below. These can
// however be overwritten.
type Parser struct {
	Tokens    Tokens
	Variables map[string]float64

	pos int
	tok *Token

	operands, operators, arity stack
}

var (
	errDivionByZero         = errors.New("Divison by zero")
	errUnmatchedParentheses = errors.New("Unmatched parentheses")
	errMisplacedComma       = errors.New("Misplaced ‘,’")
)

// Some useful predefined variables that can be used in expressions. These
// can be overwritten.
var constants = map[string]float64{
	"pi":  math.Pi,
	"tau": math.Pi * 2,
	"phi": math.Phi,
	"e":   math.E,
}

// New initializes a new Parser instance, useful when you want to run multiple
// expression and/or use variables.
func New() *Parser {
	return &Parser{
		pos:       0,
		Variables: constants,
	}
}

// Eval evaluates an expression and returns its result and any errors found.
//
// Example:
//     res, err := mathcat.Eval("2 * 2 * 2") // 8
func Eval(expr string) (float64, error) {
	tokens, err := Lex(expr)

	// If a lexer error occurred don't parse
	if err != nil {
		return -1, err
	}

	p := New()
	p.Tokens = tokens

	return p.parse()
}

// Run executes an expression on an existing parser instance. Useful for
// variable assignment.
//
// Example:
//     p.Run("a = 555")
//     p.Run("a += 45")
//     res, err := p.Run("a + a") // 1200
func (p *Parser) Run(expr string) (float64, error) {
	tokens, err := Lex(expr)

	if err != nil {
		return -1, err
	}

	p.reset()
	p.Tokens = tokens

	return p.parse()
}

// Exec executes an expression with a given map of variables.
//
// Example:
//     res, err := mathcat.Exec("a + b * b", map[string]float64{
//         "a": 1,
//         "b": 3,
//     }) // 10
func Exec(expr string, vars map[string]float64) (float64, error) {
	tokens, err := Lex(expr)

	if err != nil {
		return -1, err
	}

	p := New()
	p.Tokens = tokens

	for name, val := range vars {
		if !IsValidIdent(name) {
			return -1, fmt.Errorf("Invalid variable name: ‘%s’", name)
		}
		p.Variables[name] = val
	}

	return p.parse()
}

// GetVar gets an existing variable.
//
// Example:
//     p.Run("酷 = -33")
//     if val, err := p.GetVar("酷"); !err {
//         fmt.Printf("%f\n", val) // -33
//     }
func (p *Parser) GetVar(index string) (float64, error) {
	if val, ok := p.Variables[index]; ok {
		return val, nil
	}

	return -1, fmt.Errorf("Undefined variable ‘%s’", index)
}

func (p *Parser) parse() (float64, error) {
	var o1, o2 *operator

	// Initializing current token value
	p.tok = p.Tokens[0]

	for !p.eat().Is(EOL) {
		switch {
		case p.tok.IsLiteral():
			if p.peek().Is(LPAREN) {
				// It's a function call, push to operators stack instead
				p.operators.Push(p.tok)

				// Check ahead if the function call has any argument at all, so
				// we can do accurate tracking of arity
				if p.peekN(2).Is(RPAREN) {
					p.arity.Push(0)
				} else {
					p.arity.Push(1)
				}
				break
			}
			p.operands.Push(p.tok)
		case p.tok.Is(LPAREN):
			p.operators.Push(p.tok)
		case p.tok.Is(COMMA):
			for {
				if p.operators.Empty() {
					return -1, errMisplacedComma
				}

				if p.operators.Top().(*Token).Is(LPAREN) {
					break
				}

				val, err := p.evaluate(p.operators.Pop().(*Token))
				if err != nil {
					return -1, err
				}

				p.operands.Push(val)
			}
			p.arity.Push(p.arity.Pop().(int) + 1)
		case p.tok.IsOperator():
			o1 = operators[p.tok.Type]

			if !p.operators.Empty() {
				if p.operators.Top().(*Token).Is(IDENT) {
					// Special case, if the token on top of the operators stack is
					// a function call, always take precedence above an operator.
					function := p.operators.Pop().(*Token)
					val, err := p.evaluateFunc(function)
					if err != nil {
						return -1, err
					}

					p.operands.Push(val)

					if p.operators.Empty() {
						p.operators.Push(p.tok)
						break
					}
				}

				// If the item on top of the operators stack isn't an
				// operator, it's a function call. We then don't need to check
				// precedence.
				if !p.operators.Top().(*Token).IsOperator() {
					p.operators.Push(p.tok)
					break
				}

				o2 = operators[p.operators.Top().(*Token).Type]

				if o2.hasHigherPrecThan(o1) {
					operator := p.operators.Pop().(*Token)
					val, err := p.evaluateOp(operator)
					if err != nil {
						return -1, err
					}
					p.operands.Push(val)
				}
			}
			p.operators.Push(p.tok)
		case p.tok.Is(RPAREN):
			for {
				if p.operators.Empty() {
					return -1, errUnmatchedParentheses
				}

				top := p.operators.Pop().(*Token)
				if top.Is(LPAREN) {
					break
				}

				val, err := p.evaluate(top)
				if err != nil {
					return -1, err
				}

				p.operands.Push(val)
			}
		}
	}

	// Evaluate remaining operators
	for !p.operators.Empty() {
		top := p.operators.Pop().(*Token)

		if top.Is(LPAREN) {
			return -1, errUnmatchedParentheses
		}

		val, err := p.evaluate(top)
		if err != nil {
			return -1, err
		}

		p.operands.Push(val)
	}

	// If there are no operands, the expression is useless and doesn't do
	// anything, for example `()`
	if p.operands.Empty() {
		return 0, nil
	}

	// Single operand left means the expression was evaluated successful
	if len(p.operands) == 1 {
		return p.lookup(p.operands[0])
	}

	// Leftover token on operand stack indicates invalid syntax
	return -1, fmt.Errorf("Unexpected ‘%s’", p.operands.Top())
}

// evaluate gets called when an operator or function call has to be evaluated
// for a result. In case of a function, evaluateFunc is called and in case of
// an operator evaluateOp is called.
func (p *Parser) evaluate(tok *Token) (float64, error) {
	if tok.IsOperator() {
		return p.evaluateOp(tok)
	}

	return p.evaluateFunc(tok)
}

func (p *Parser) evaluateFunc(tok *Token) (float64, error) {
	var (
		function *function
		ok       bool
		i        int
	)

	if function, ok = funcs[tok.Value]; !ok {
		return -1, fmt.Errorf("Undefined function ‘%s’", tok.Value)
	}

	if arity := p.arity.Pop().(int); arity != function.arity {
		return -1, fmt.Errorf("Invalid argument count for ‘%s’ (expected %d, got %d)", tok.Value, function.arity, arity)
	}

	// Start popping off arguments for the function call
	args := make([]float64, function.arity)
	for i = function.arity - 1; i >= 0; i-- {
		if p.operands.Empty() {
			return -1, errMisplacedComma
		}

		arg, err := p.lookup(p.operands.Pop())
		if err != nil {
			return -1, err
		}

		args[i] = arg
	}

	return function.fn(args), nil
}

func (p *Parser) evaluateOp(operator *Token) (float64, error) {
	var (
		result      float64
		left, right float64
		err         error
		lhsToken    interface{}
	)

	if p.operands.Empty() {
		return -1, fmt.Errorf("Unexpected ‘%s’", operator.Type)
	}

	if right, err = p.lookup(p.operands.Pop()); err != nil {
		return -1, err
	}

	// Unary operators have no left hand side
	if op := operators[operator.Type]; !op.unary {
		if p.operands.Empty() {
			return -1, fmt.Errorf("Unexpected ‘%s’", operator.Value)
		}
		// Save the token in case of a assignment variable is used and we need
		// to save the result in a variable
		lhsToken = p.operands.Pop()

		// Don't lookup the left hand side if = is used so we can do initial
		// assignment
		if !operator.Is(EQ) {
			left, err = p.lookup(lhsToken)
			if err != nil {
				return -1, err
			}
		}
	}

	result, err = execute(operator, left, right)
	if err != nil {
		return -1, err
	}

	if operator.IsAssignment() {
		// Save result in variable
		if !lhsToken.(*Token).Is(IDENT) {
			return -1, errors.New("Can't assign to literal")
		}
		p.Variables[lhsToken.(*Token).Value] = result
	}

	return result, nil
}

func execute(operator *Token, lhs, rhs float64) (float64, error) {
	var result float64

	// Both lhs and rhs have to be whole numbers for bitwise operations
	if operator.IsBitwise() && (!IsWholeNumber(lhs) || !IsWholeNumber(rhs)) {
		return -1, fmt.Errorf("Unsupported type (float) for ‘%s’", operator.Type)
	}

	switch operator.Type {
	case ADD, ADD_EQ:
		result = lhs + rhs
	case SUB, SUB_EQ:
		result = lhs - rhs
	case UNARY_MIN:
		result = -rhs
	case DIV, DIV_EQ:
		if rhs == 0 {
			return -1, errDivionByZero
		}
		result = lhs / rhs
	case MUL, MUL_EQ:
		result = lhs * rhs
	case POW, POW_EQ:
		result = math.Pow(lhs, rhs)
	case REM, REM_EQ:
		if rhs == 0 {
			return -1, errDivionByZero
		}
		result = math.Mod(lhs, rhs)
	case AND, AND_EQ:
		result = float64(int64(lhs) & int64(rhs))
	case OR, OR_EQ:
		result = float64(int64(lhs) | int64(rhs))
	case XOR, XOR_EQ:
		result = float64(int64(lhs) ^ int64(rhs))
	case LSH, LSH_EQ:
		result = float64(uint64(lhs) << uint64(rhs))
	case RSH, RSH_EQ:
		result = float64(uint64(lhs) >> uint64(rhs))
	case NOT:
		result = float64(^int64(rhs))
	case EQ:
		result = rhs
	case EQ_EQ:
		result = bool2float(lhs == rhs)
	case BANG_EQ:
		result = bool2float(lhs != rhs)
	case GT:
		result = bool2float(lhs > rhs)
	case GT_EQ:
		result = bool2float(lhs >= rhs)
	case LT:
		result = bool2float(lhs < rhs)
	case LT_EQ:
		result = bool2float(lhs <= rhs)
	default:
		return -1, fmt.Errorf("Invalid operator ‘%s’", operator.Type)
	}

	return result, nil
}

// Look up a literal. If it's an identifier, check the parser's variables map,
// otherwise convert the tokenized string to a float64.
func (p *Parser) lookup(val interface{}) (float64, error) {
	// val can be a token or a float64, if it's a float64 it has been already
	// evaluated and we don't need to do anything
	if v, ok := val.(float64); ok {
		return v, nil
	}

	var (
		tmp uint64
		res float64
		err error
	)

	bases := [...]int{
		HEX:    16,
		BINARY: 2,
		OCTAL:  8,
	}

	tok := val.(*Token)
	switch tok.Type {
	case NUMBER:
		res, err = strconv.ParseFloat(tok.Value, 64)
	case HEX, BINARY, OCTAL:
		// Remove 0x part of literal and convert to uint first
		tmp, err = strconv.ParseUint(tok.Value[2:], bases[tok.Type], 64)

		// Then convert to float
		res = float64(tmp)
	case IDENT:
		res, err = p.GetVar(tok.Value)
		if err != nil {
			return -1, err
		}
		return res, nil
	default:
		return -1, fmt.Errorf("Invalid lookup type ‘%s’", tok.Type)
	}

	if err != nil {
		if numError, ok := err.(*strconv.NumError); ok && numError.Err == strconv.ErrRange {
			return -1, fmt.Errorf("Error parsing ‘%s’: %s", tok.Value, strconv.ErrRange)
		}
		return -1, fmt.Errorf("Error parsing ‘%s’: invalid %s", tok.Value, tok.Type)
	}

	return res, nil
}

func (p *Parser) reset() {
	p.Tokens = nil
	p.pos = 0

	p.operators = nil
	p.operands = nil
	p.arity = nil
}

func (p *Parser) peek() *Token {
	return p.Tokens[p.pos]
}

func (p *Parser) peekN(n int) *Token {
	return p.Tokens[p.pos-1+n]
}

func (p *Parser) eat() *Token {
	p.tok = p.peek()
	p.pos++
	return p.tok
}

// IsWholeNumber checks if a float is a whole number
func IsWholeNumber(n float64) bool {
	return float64(int64(n)) == n
}

func bool2float(b bool) float64 {
	if b {
		return 1
	}
	return 0
}
<|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 (
	"errors"
	"fmt"
	"io"
	"strings"
	"os"
	"unicode/utf8"
)

// Expected an argument but got none
var ErrExpectedArgument = errors.New("expected option argument")

// Unknown option flag was found
var ErrUnknownFlag = errors.New("unknown flag")

// The builtin help message was printed
var ErrHelp = errors.New("help shown")

// An argument for a boolean value was specified
var ErrNoArgumentForBool = errors.New("bool flags cannot have arguments")

type help struct {
	writer io.Writer
	IsHelp bool `long:"help" short:"h" description:"Show help options"`
}

// A Parser provides command line option parsing. It can contain several
// option groups each with their own set of options.
//
// Example:
//     type Options struct {
//         Verbose []bool `short:"v" long:"verbose" description:"Show verbose debug information"`
//     }
//
//     opts := new(Options)
//
//     parser := flags.NewParser("testapp")
//     parser.AddHelp(os.Stderr)
//
//     parser.AddGroup(flags.NewGroup("Application Options", opts))
//
//     args, err := parser.Parse(os.Args[1:])
//
//     if err != nil {
//         if err != flags.ErrHelp {
//             parser.PrintError(os.Stderr, err)
//         }
//
//         os.Exit(1)
//     }
type Parser struct {
	// The option groups available to the parser
	Groups []*Group

	// The parser application name
	ApplicationName string

	// The usage (e.g. [OPTIONS] <filename>)
	Usage string

	// If true, all arguments after a double dash (--) will be passed
	// as remaining command line arguments. Defaults to false.
	PassDoubleDash bool

	// If true, unknown command line arguments are ignored and passed as
	// remaining command line arguments. Defaults to false.
	IgnoreUnknown bool

	help    *help
	errorAt interface{}
}

// NewParser creates a new parser. The appname is used to display the
// executable name in the builtin help message. An initial set of option groups
// can be specified when constructing a parser, but you can also add additional
// option groups later (see Parser.AddGroup).
func NewParser(appname string, groups ...*Group) *Parser {
	return &Parser{
		ApplicationName: appname,
		Groups:          groups,
		PassDoubleDash:  false,
		IgnoreUnknown:   false,
		Usage:           "[OPTIONS]",
	}
}

// AddGroups adds one or more option groups to the parser. It returns the parser
// itself again so multiple calls can be chained.
func (p *Parser) AddGroups(groups ...*Group) *Parser {
	p.Groups = append(p.Groups, groups...)
	return p
}

func (p *Parser) AddGroup(name string, data interface{}) *Parser {
	p.Groups = append(p.Groups, NewGroup(name, data))
	return p
}

// AddHelp adds a common help option group to the parser. The help option group
// contains only one option, with short name -h and long name --help.
// When either -h or --help appears, a help message listing all the options
// will be written to the specified writer. It returns the parser itself
// again so multiple calls can be chained.
func (p *Parser) AddHelp(writer io.Writer) *Parser {
	if p.help == nil {
		p.help = &help{
			writer: writer,
		}

		p.AddGroup("Help Options", p.help)
	}

	return p
}

func (p *Parser) parseOption(group *Group, args []string, name string, info *Info, canarg bool, argument *string, index int) (error, int) {
	if !info.canArgument() {
		if canarg && argument != nil {
			p.errorAt = info
			return ErrNoArgumentForBool, index
		}

		info.Set(nil)
	} else if canarg && (argument != nil || index < len(args)) {
		if argument == nil {
			argument = &args[index]
			index++
		}

		info.Set(argument)
	} else if info.OptionalArgument {
		info.Set(&info.Default)
	} else {
		p.errorAt = info
		return ErrExpectedArgument, index
	}

	return nil, index
}

func (p *Parser) parseLong(args []string, name string, argument *string, index int) (error, int) {
	for _, grp := range p.Groups {
		if info := grp.LongNames[name]; info != nil {
			return p.parseOption(grp, args, name, info, true, argument, index)
		}
	}

	p.errorAt = fmt.Sprintf("--%v", name)
	return ErrUnknownFlag, index
}

func (p *Parser) getShort(name rune) (*Info, *Group) {
	for _, grp := range p.Groups {
		info := grp.ShortNames[name]

		if info != nil {
			return info, grp
		}
	}

	return nil, nil
}

func (p *Parser) parseShort(args []string, name rune, islast bool, argument *string, index int) (error, int) {
	names := make([]byte, utf8.RuneLen(name))
	utf8.EncodeRune(names, name)

	info, grp := p.getShort(name)

	if info != nil {
		if info.canArgument() && !islast && !info.OptionalArgument {
			p.errorAt = info
			return ErrExpectedArgument, index
		}

		return p.parseOption(grp, args, string(names), info, islast, argument, index)
	}

	p.errorAt = fmt.Sprintf("-%v", string(names))
	return ErrUnknownFlag, index
}

// PrintError prints an error which occurred while parsing command line
// arguments. This is more useful than simply printing the error message
// because context information on where the error occurred will also be
// written. The error is printed to writer (commonly os.Stderr).
func (p *Parser) PrintError(writer io.Writer, err error) {
	s := fmt.Sprintf("Error at `%v': %s\n", p.errorAt, err)
	writer.Write([]byte(s))
}

// 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 ErrHelp is returned
// to indicate that the help was shown. It is up to the caller to exit the
// program if so desired.
func (p *Parser) ParseArgs(args []string) ([]string, error) {
	ret := make([]string, 0, len(args))
	i := 0

	for i < len(args) {
		arg := args[i]
		i++

		// When PassDoubleDash is set and we encounter a --, then
		// simply append all the rest as arguments and break out
		if p.PassDoubleDash && arg == "--" {
			ret = append(ret, args[i:]...)
			break
		}

		// If the argument is not an option, then append it to the rest
		if arg[0] != '-' {
			ret = append(ret, arg)
			continue
		}

		pos := strings.Index(arg, "=")
		var argument *string

		if pos >= 0 {
			rest := arg[pos+1:]
			argument = &rest
			arg = arg[:pos]
		}

		var err error

		if strings.HasPrefix(arg, "--") {
			err, i = p.parseLong(args, arg[2:], argument, i)
		} else {
			short := arg[1:]

			for j, c := range short {
				clen := utf8.RuneLen(c)
				islast := (j+clen == len(short))

				if !islast && argument == nil {
					rr := short[j+clen:]
					next, _ := utf8.DecodeRuneInString(rr)
					info, _ := p.getShort(c)

					if info != nil && info.canArgument() {
						if snext, _ := p.getShort(next); snext == nil {
							// Consider the next stuff as an argument
							argument = &rr
							islast = true
						}
					}
				}

				err, i = p.parseShort(args, c, islast, argument, i)

				if err != nil || islast {
					break
				}
			}
		}

		if err != nil {
			if p.IgnoreUnknown {
				ret = append(ret, arg)
			} else {
				return nil, err
			}
		}
	}

	if p.help != nil && p.help.IsHelp {
		p.ShowHelp(p.help.writer)
		p.errorAt = "--help"

		return ret, ErrHelp
	}

	return ret, nil
}
<commit_msg>Added NewNamedParser<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 (
	"errors"
	"path"
	"fmt"
	"io"
	"strings"
	"os"
	"unicode/utf8"
)

// Expected an argument but got none
var ErrExpectedArgument = errors.New("expected option argument")

// Unknown option flag was found
var ErrUnknownFlag = errors.New("unknown flag")

// The builtin help message was printed
var ErrHelp = errors.New("help shown")

// An argument for a boolean value was specified
var ErrNoArgumentForBool = errors.New("bool flags cannot have arguments")

type help struct {
	writer io.Writer
	IsHelp bool `long:"help" short:"h" description:"Show help options"`
}

// A Parser provides command line option parsing. It can contain several
// option groups each with their own set of options.
//
// Example:
//     type Options struct {
//         Verbose []bool `short:"v" long:"verbose" description:"Show verbose debug information"`
//     }
//
//     opts := new(Options)
//
//     parser := flags.NewParser("testapp")
//     parser.AddHelp(os.Stderr)
//
//     parser.AddGroup(flags.NewGroup("Application Options", opts))
//
//     args, err := parser.Parse(os.Args[1:])
//
//     if err != nil {
//         if err != flags.ErrHelp {
//             parser.PrintError(os.Stderr, err)
//         }
//
//         os.Exit(1)
//     }
type Parser struct {
	// The option groups available to the parser
	Groups []*Group

	// The parser application name
	ApplicationName string

	// The usage (e.g. [OPTIONS] <filename>)
	Usage string

	// If true, all arguments after a double dash (--) will be passed
	// as remaining command line arguments. Defaults to false.
	PassDoubleDash bool

	// If true, unknown command line arguments are ignored and passed as
	// remaining command line arguments. Defaults to false.
	IgnoreUnknown bool

	help    *help
	errorAt interface{}
}

// 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).
func NewParser(groups ...*Group) *Parser {
	return NewNamedParser(path.Base(os.Args[0]), groups...)
}

// NewNamedParser creates a new parser. The appname is used to display the
// executable name in the builtin help message. An initial set of option groups
// can be specified when constructing a parser, but you can also add additional
// option groups later (see Parser.AddGroup).
func NewNamedParser(appname string, groups ...*Group) *Parser {
	return &Parser{
		ApplicationName: appname,
		Groups:          groups,
		PassDoubleDash:  false,
		IgnoreUnknown:   false,
		Usage:           "[OPTIONS]",
	}
}

// AddGroups adds one or more option groups to the parser. It returns the parser
// itself again so multiple calls can be chained.
func (p *Parser) AddGroups(groups ...*Group) *Parser {
	p.Groups = append(p.Groups, groups...)
	return p
}

func (p *Parser) AddGroup(name string, data interface{}) *Parser {
	p.Groups = append(p.Groups, NewGroup(name, data))
	return p
}

// AddHelp adds a common help option group to the parser. The help option group
// contains only one option, with short name -h and long name --help.
// When either -h or --help appears, a help message listing all the options
// will be written to the specified writer. It returns the parser itself
// again so multiple calls can be chained.
func (p *Parser) AddHelp(writer io.Writer) *Parser {
	if p.help == nil {
		p.help = &help{
			writer: writer,
		}

		p.AddGroup("Help Options", p.help)
	}

	return p
}

func (p *Parser) parseOption(group *Group, args []string, name string, info *Info, canarg bool, argument *string, index int) (error, int) {
	if !info.canArgument() {
		if canarg && argument != nil {
			p.errorAt = info
			return ErrNoArgumentForBool, index
		}

		info.Set(nil)
	} else if canarg && (argument != nil || index < len(args)) {
		if argument == nil {
			argument = &args[index]
			index++
		}

		info.Set(argument)
	} else if info.OptionalArgument {
		info.Set(&info.Default)
	} else {
		p.errorAt = info
		return ErrExpectedArgument, index
	}

	return nil, index
}

func (p *Parser) parseLong(args []string, name string, argument *string, index int) (error, int) {
	for _, grp := range p.Groups {
		if info := grp.LongNames[name]; info != nil {
			return p.parseOption(grp, args, name, info, true, argument, index)
		}
	}

	p.errorAt = fmt.Sprintf("--%v", name)
	return ErrUnknownFlag, index
}

func (p *Parser) getShort(name rune) (*Info, *Group) {
	for _, grp := range p.Groups {
		info := grp.ShortNames[name]

		if info != nil {
			return info, grp
		}
	}

	return nil, nil
}

func (p *Parser) parseShort(args []string, name rune, islast bool, argument *string, index int) (error, int) {
	names := make([]byte, utf8.RuneLen(name))
	utf8.EncodeRune(names, name)

	info, grp := p.getShort(name)

	if info != nil {
		if info.canArgument() && !islast && !info.OptionalArgument {
			p.errorAt = info
			return ErrExpectedArgument, index
		}

		return p.parseOption(grp, args, string(names), info, islast, argument, index)
	}

	p.errorAt = fmt.Sprintf("-%v", string(names))
	return ErrUnknownFlag, index
}

// PrintError prints an error which occurred while parsing command line
// arguments. This is more useful than simply printing the error message
// because context information on where the error occurred will also be
// written. The error is printed to writer (commonly os.Stderr).
func (p *Parser) PrintError(writer io.Writer, err error) {
	s := fmt.Sprintf("Error at `%v': %s\n", p.errorAt, err)
	writer.Write([]byte(s))
}

// 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 ErrHelp is returned
// to indicate that the help was shown. It is up to the caller to exit the
// program if so desired.
func (p *Parser) ParseArgs(args []string) ([]string, error) {
	ret := make([]string, 0, len(args))
	i := 0

	for i < len(args) {
		arg := args[i]
		i++

		// When PassDoubleDash is set and we encounter a --, then
		// simply append all the rest as arguments and break out
		if p.PassDoubleDash && arg == "--" {
			ret = append(ret, args[i:]...)
			break
		}

		// If the argument is not an option, then append it to the rest
		if arg[0] != '-' {
			ret = append(ret, arg)
			continue
		}

		pos := strings.Index(arg, "=")
		var argument *string

		if pos >= 0 {
			rest := arg[pos+1:]
			argument = &rest
			arg = arg[:pos]
		}

		var err error

		if strings.HasPrefix(arg, "--") {
			err, i = p.parseLong(args, arg[2:], argument, i)
		} else {
			short := arg[1:]

			for j, c := range short {
				clen := utf8.RuneLen(c)
				islast := (j+clen == len(short))

				if !islast && argument == nil {
					rr := short[j+clen:]
					next, _ := utf8.DecodeRuneInString(rr)
					info, _ := p.getShort(c)

					if info != nil && info.canArgument() {
						if snext, _ := p.getShort(next); snext == nil {
							// Consider the next stuff as an argument
							argument = &rr
							islast = true
						}
					}
				}

				err, i = p.parseShort(args, c, islast, argument, i)

				if err != nil || islast {
					break
				}
			}
		}

		if err != nil {
			if p.IgnoreUnknown {
				ret = append(ret, arg)
			} else {
				return nil, err
			}
		}
	}

	if p.help != nil && p.help.IsHelp {
		p.ShowHelp(p.help.writer)
		p.errorAt = "--help"

		return ret, ErrHelp
	}

	return ret, nil
}
<|endoftext|>


<commit_before>package dxf

import (
	"errors"
	"fmt"
	"github.com/yofu/dxf/color"
	"github.com/yofu/dxf/drawing"
	"github.com/yofu/dxf/entity"
	"github.com/yofu/dxf/header"
	"github.com/yofu/dxf/table"
	"strconv"
	"strings"
)

func SetFloat(data [2]string, f func(float64)) error {
	val, err := strconv.ParseFloat(strings.TrimSpace(data[1]), 64)
	if err != nil {
		return fmt.Errorf("code %s: %s", data[0], err.Error())
	}
	f(val)
	return nil
}

// HEADER
func ParseHeader(d *drawing.Drawing, line int, data [][2]string) error {
	h := d.Sections[drawing.HEADER].(*header.Header)
	var name string
	var err error
	for _, dt := range data {
		switch dt[0] {
		case "9":
			name = dt[1]
		case "1":
			switch name {
			case "$ACADVER":
				h.Version = dt[1]
			}
		case "10":
			switch name {
			case "$INSBASE":
				err = SetFloat(dt, func(val float64) { h.InsBase[0] = val })
			case "$EXTMIN":
				err = SetFloat(dt, func(val float64) { h.ExtMin[0] = val })
			case "$EXTMAX":
				err = SetFloat(dt, func(val float64) { h.ExtMax[0] = val })
			}
		case "20":
			switch name {
			case "$INSBASE":
				err = SetFloat(dt, func(val float64) { h.InsBase[1] = val })
			case "$EXTMIN":
				err = SetFloat(dt, func(val float64) { h.ExtMin[1] = val })
			case "$EXTMAX":
				err = SetFloat(dt, func(val float64) { h.ExtMax[1] = val })
			}
		case "30":
			switch name {
			case "$INSBASE":
				err = SetFloat(dt, func(val float64) { h.InsBase[2] = val })
			case "$EXTMIN":
				err = SetFloat(dt, func(val float64) { h.ExtMin[2] = val })
			case "$EXTMAX":
				err = SetFloat(dt, func(val float64) { h.ExtMax[2] = val })
			}
		}
		if err != nil {
			return err
		}
	}
	return nil
}

// CLASSES
func ParseClasses(d *drawing.Drawing, line int, data [][2]string) error {
	return nil
}

// TABLES
func ParseTables(d *drawing.Drawing, line int, data [][2]string) error {
	parsers := []func(*drawing.Drawing, [][2]string) (table.SymbolTable, error) {
		ParseVport,
		ParseLtype,
		ParseLayer,
		ParseStyle,
		ParseView,
		ParseUCS,
		ParseAppID,
		ParseDimStyle,
		ParseBlockRecord,
	}
	tmpdata := make([][2]string, 0)
	setparser := false
	var parser func(*drawing.Drawing, [][2]string) (table.SymbolTable, error)
	var ind int
	for i, dt := range data {
		if setparser {
			if dt[0] != "2" {
				return fmt.Errorf("line %d: invalid group code: %s", line + 2*i, dt[0])
			}
			ind = int(table.TableTypeValue(strings.ToUpper(dt[1])))
			if ind < 0 {
				return fmt.Errorf("line %d: unknown table type: %s", line + 2*i, dt[1])
			}
			parser = parsers[ind]
			setparser = false
		} else {
			if dt[0] == "0" {
				switch strings.ToUpper(dt[1]) {
				case "TABLE":
					setparser = true
				case "ENDTAB":
					if len(tmpdata) > 0 {
						err := ParseTable(d, tmpdata, ind, parser)
						if err != nil {
							return err
						}
						tmpdata = make([][2]string, 0)
					}
				default:
					tmpdata = append(tmpdata, dt)
				}
			} else {
				tmpdata = append(tmpdata, dt)
			}
		}
	}
	if len(tmpdata) > 0 {
		err := ParseTable(d, tmpdata, ind, parser)
		if err != nil {
			return fmt.Errorf("line %d: %s", line + 2*len(data), err.Error())
		}
		tmpdata = make([][2]string, 0)
	}
	return nil
}

func ParseTable(d *drawing.Drawing, data [][2]string, index int, parser func(*drawing.Drawing, [][2]string)(table.SymbolTable, error)) error {
	t := d.Sections[drawing.TABLES].(table.Tables)[index]
	t.Clear()
	tmpdata := make([][2]string, 0)
	for _, dt := range data {
		switch dt[0] {
		case "0":
			if len(tmpdata) > 0 {
				st, err := parser(d, tmpdata)
				if err != nil {
					return err
				}
				if st != nil {
					t.Add(st)
				}
				tmpdata = make([][2]string, 0)
			}
		default:
			tmpdata = append(tmpdata, dt)
		}
	}
	if len(tmpdata) > 0 {
		st, err := parser(d, tmpdata)
		if err != nil {
			return err
		}
		if st != nil {
			t.Add(st)
		}
		tmpdata = make([][2]string, 0)
	}
	return nil
}

func ParseVport(d *drawing.Drawing, data [][2]string) (table.SymbolTable, error) {
	return nil, nil
}

func ParseLtype(d *drawing.Drawing, data [][2]string) (table.SymbolTable, error) {
	var name, desc string
	var lengths []float64
	ind := 0
	for _, dt := range data {
		switch dt[0] {
		case "2":
			name = dt[1]
		case "3":
			desc = dt[1]
		case "73":
			l, err := strconv.ParseInt(strings.TrimSpace(dt[1]), 10, 64)
			if err != nil {
				return nil, err
			}
			lengths = make([]float64, int(l))
		case "49":
			if ind >= len(lengths) {
				return nil, fmt.Errorf("ltype too long")
			}
			val, err := strconv.ParseFloat(dt[1], 64)
			if err != nil {
				return nil, err
			}
			lengths[ind] = val
			ind++
		}
	}
	return table.NewLineType(name, desc, lengths...), nil
}

func ParseLayer(d *drawing.Drawing, data [][2]string) (table.SymbolTable, error) {
	var name string
	var flag int
	var col color.ColorNumber
	var lt *table.LineType
	var lw int
	for _, dt := range data {
		switch dt[0] {
		case "2":
			name = dt[1]
		case "70":
			val, err := strconv.ParseInt(strings.TrimSpace(dt[1]), 10, 64)
			if err != nil {
				return nil, err
			}
			flag = int(val)
		case "62":
			val, err := strconv.ParseInt(strings.TrimSpace(dt[1]), 10, 64)
			if err != nil {
				return nil, err
			}
			col = color.ColorNumber(val)
		case "6":
			l, err := d.LineType(dt[1])
			if err != nil {
				return nil, err
			}
			lt = l
		case "370":
			val, err := strconv.ParseInt(strings.TrimSpace(dt[1]), 10, 64)
			if err != nil {
				return nil, err
			}
			lw = int(val)
		case "390":
			// plotstyle
		}
	}
	l := table.NewLayer(name, col, lt)
	l.SetFlag(flag)
	l.SetLineWidth(lw)
	return l, nil
}

func ParseStyle(d *drawing.Drawing, data [][2]string) (table.SymbolTable, error) {
	var name, font, bigfont string
	for _, dt := range data {
		switch dt[0] {
		case "2":
			name = dt[1]
		case "3":
			font = dt[1]
		case "4":
			bigfont = dt[1]
		}
	}
	s := table.NewStyle(name)
	s.FontName = font
	s.BigFontName = bigfont
	return s, nil
}

func ParseView(d *drawing.Drawing, data [][2]string) (table.SymbolTable, error) {
	return nil, nil
}

func ParseUCS(d *drawing.Drawing, data [][2]string) (table.SymbolTable, error) {
	return nil, nil
}

func ParseAppID(d *drawing.Drawing, data [][2]string) (table.SymbolTable, error) {
	var name string
	for _, dt := range data {
		switch dt[0] {
		case "2":
			name = dt[1]
		}
	}
	a := table.NewAppID(name)
	return a, nil
}

func ParseDimStyle(d *drawing.Drawing, data [][2]string) (table.SymbolTable, error) {
	var name string
	for _, dt := range data {
		switch dt[0] {
		case "2":
			name = dt[1]
		}
	}
	ds := table.NewDimStyle(name)
	return ds, nil
}

func ParseBlockRecord(d *drawing.Drawing, data [][2]string) (table.SymbolTable, error) {
	return nil, nil
}

// BLOCKS
func ParseBlocks(d *drawing.Drawing, line int, data [][2]string) error {
	return nil
}

// ENTITIES
func ParseEntities(d *drawing.Drawing, line int, data [][2]string) error {
	tmpdata := make([][2]string, 0)
	for i, dt := range data {
		if dt[0] == "0" {
			if len(tmpdata) > 0 {
				e, err := ParseEntity(d, tmpdata)
				if err != nil {
					return fmt.Errorf("line %d: %s", line + 2*i, err.Error())
				}
				d.AddEntity(e)
				tmpdata = make([][2]string, 0)
			}
		}
		tmpdata = append(tmpdata, dt)
	}
	if len(tmpdata) > 0 {
		e, err := ParseEntity(d, tmpdata)
		if err != nil {
			return fmt.Errorf("line %d: %s", line + 2*len(data), err.Error())
		}
		d.AddEntity(e)
		tmpdata = make([][2]string, 0)
	}
	return nil
}

func ParseEntity(d *drawing.Drawing, data [][2]string) (entity.Entity, error) {
	if len(data) < 1 {
		return nil, fmt.Errorf("no data")
	}
	if data[0][0] != "0" {
		return nil, fmt.Errorf("invalid group code: %d", data[0][0])
	}
	f, err := ParseEntityFunc(data[0][1])
	if err != nil {
		return nil, err
	}
	return f(d, data)
}

func ParseEntityFunc(t string) (func(*drawing.Drawing, [][2]string)(entity.Entity, error), error) {
	switch t {
	case "LINE":
		return ParseLine, nil
	// case "3DFACE":
	// 	return Parse3DFace, nil
	// case "LWPOLYLINE":
	// 	return ParseLwPolyline, nil
	// case "CIRCLE":
	// 	return ParseCircle, nil
	// case "POLYLINE":
	// 	return ParsePolyline, nil
	// case "VERTEX":
	// 	return ParseVertex, nil
	// case "POINT":
	// 	return ParsePoint, nil
	// case "TEXT":
	// 	return ParseText, nil
	default:
		return nil, errors.New("unknown entity type")
	}
}

func ParseLine(d *drawing.Drawing, data [][2]string) (entity.Entity, error) {
	l := entity.NewLine()
	var err error
	for _, dt := range data {
		switch dt[0] {
		default:
			continue
		case "8":
			if layer, exists := d.Layers[dt[1]]; exists {
				l.SetLayer(layer)
			} else {
				err = fmt.Errorf("unknown layer: %s", dt[1])
			}
		case "10":
			err = SetFloat(dt, func(val float64) { l.Start[0] = val })
		case "20":
			err = SetFloat(dt, func(val float64) { l.Start[1] = val })
		case "30":
			err = SetFloat(dt, func(val float64) { l.Start[2] = val })
		case "11":
			err = SetFloat(dt, func(val float64) { l.End[0] = val })
		case "21":
			err = SetFloat(dt, func(val float64) { l.End[1] = val })
		case "31":
			err = SetFloat(dt, func(val float64) { l.End[2] = val })
		}
		if err != nil {
			return l, err
		}
	}
	return l, nil
}

// OBJECTS
func ParseObjects(d *drawing.Drawing, line int, data [][2]string) error {
	return nil
}
<commit_msg>implement ParseBlockRecord<commit_after>package dxf

import (
	"errors"
	"fmt"
	"github.com/yofu/dxf/color"
	"github.com/yofu/dxf/drawing"
	"github.com/yofu/dxf/entity"
	"github.com/yofu/dxf/header"
	"github.com/yofu/dxf/table"
	"strconv"
	"strings"
)

func SetFloat(data [2]string, f func(float64)) error {
	val, err := strconv.ParseFloat(strings.TrimSpace(data[1]), 64)
	if err != nil {
		return fmt.Errorf("code %s: %s", data[0], err.Error())
	}
	f(val)
	return nil
}

// HEADER
func ParseHeader(d *drawing.Drawing, line int, data [][2]string) error {
	h := d.Sections[drawing.HEADER].(*header.Header)
	var name string
	var err error
	for _, dt := range data {
		switch dt[0] {
		case "9":
			name = dt[1]
		case "1":
			switch name {
			case "$ACADVER":
				h.Version = dt[1]
			}
		case "10":
			switch name {
			case "$INSBASE":
				err = SetFloat(dt, func(val float64) { h.InsBase[0] = val })
			case "$EXTMIN":
				err = SetFloat(dt, func(val float64) { h.ExtMin[0] = val })
			case "$EXTMAX":
				err = SetFloat(dt, func(val float64) { h.ExtMax[0] = val })
			}
		case "20":
			switch name {
			case "$INSBASE":
				err = SetFloat(dt, func(val float64) { h.InsBase[1] = val })
			case "$EXTMIN":
				err = SetFloat(dt, func(val float64) { h.ExtMin[1] = val })
			case "$EXTMAX":
				err = SetFloat(dt, func(val float64) { h.ExtMax[1] = val })
			}
		case "30":
			switch name {
			case "$INSBASE":
				err = SetFloat(dt, func(val float64) { h.InsBase[2] = val })
			case "$EXTMIN":
				err = SetFloat(dt, func(val float64) { h.ExtMin[2] = val })
			case "$EXTMAX":
				err = SetFloat(dt, func(val float64) { h.ExtMax[2] = val })
			}
		}
		if err != nil {
			return err
		}
	}
	return nil
}

// CLASSES
func ParseClasses(d *drawing.Drawing, line int, data [][2]string) error {
	return nil
}

// TABLES
func ParseTables(d *drawing.Drawing, line int, data [][2]string) error {
	parsers := []func(*drawing.Drawing, [][2]string) (table.SymbolTable, error) {
		ParseVport,
		ParseLtype,
		ParseLayer,
		ParseStyle,
		ParseView,
		ParseUCS,
		ParseAppID,
		ParseDimStyle,
		ParseBlockRecord,
	}
	tmpdata := make([][2]string, 0)
	setparser := false
	var parser func(*drawing.Drawing, [][2]string) (table.SymbolTable, error)
	var ind int
	for i, dt := range data {
		if setparser {
			if dt[0] != "2" {
				return fmt.Errorf("line %d: invalid group code: %s", line + 2*i, dt[0])
			}
			ind = int(table.TableTypeValue(strings.ToUpper(dt[1])))
			if ind < 0 {
				return fmt.Errorf("line %d: unknown table type: %s", line + 2*i, dt[1])
			}
			parser = parsers[ind]
			setparser = false
		} else {
			if dt[0] == "0" {
				switch strings.ToUpper(dt[1]) {
				case "TABLE":
					setparser = true
				case "ENDTAB":
					if len(tmpdata) > 0 {
						err := ParseTable(d, tmpdata, ind, parser)
						if err != nil {
							return err
						}
						tmpdata = make([][2]string, 0)
					}
				default:
					tmpdata = append(tmpdata, dt)
				}
			} else {
				tmpdata = append(tmpdata, dt)
			}
		}
	}
	if len(tmpdata) > 0 {
		err := ParseTable(d, tmpdata, ind, parser)
		if err != nil {
			return fmt.Errorf("line %d: %s", line + 2*len(data), err.Error())
		}
		tmpdata = make([][2]string, 0)
	}
	return nil
}

func ParseTable(d *drawing.Drawing, data [][2]string, index int, parser func(*drawing.Drawing, [][2]string)(table.SymbolTable, error)) error {
	t := d.Sections[drawing.TABLES].(table.Tables)[index]
	t.Clear()
	tmpdata := make([][2]string, 0)
	for _, dt := range data {
		switch dt[0] {
		case "0":
			if len(tmpdata) > 0 {
				st, err := parser(d, tmpdata)
				if err != nil {
					return err
				}
				if st != nil {
					t.Add(st)
				}
				tmpdata = make([][2]string, 0)
			}
		default:
			tmpdata = append(tmpdata, dt)
		}
	}
	if len(tmpdata) > 0 {
		st, err := parser(d, tmpdata)
		if err != nil {
			return err
		}
		if st != nil {
			t.Add(st)
		}
		tmpdata = make([][2]string, 0)
	}
	return nil
}

func ParseVport(d *drawing.Drawing, data [][2]string) (table.SymbolTable, error) {
	return nil, nil
}

func ParseLtype(d *drawing.Drawing, data [][2]string) (table.SymbolTable, error) {
	var name, desc string
	var lengths []float64
	ind := 0
	for _, dt := range data {
		switch dt[0] {
		case "2":
			name = dt[1]
		case "3":
			desc = dt[1]
		case "73":
			l, err := strconv.ParseInt(strings.TrimSpace(dt[1]), 10, 64)
			if err != nil {
				return nil, err
			}
			lengths = make([]float64, int(l))
		case "49":
			if ind >= len(lengths) {
				return nil, fmt.Errorf("ltype too long")
			}
			val, err := strconv.ParseFloat(dt[1], 64)
			if err != nil {
				return nil, err
			}
			lengths[ind] = val
			ind++
		}
	}
	return table.NewLineType(name, desc, lengths...), nil
}

func ParseLayer(d *drawing.Drawing, data [][2]string) (table.SymbolTable, error) {
	var name string
	var flag int
	var col color.ColorNumber
	var lt *table.LineType
	var lw int
	for _, dt := range data {
		switch dt[0] {
		case "2":
			name = dt[1]
		case "70":
			val, err := strconv.ParseInt(strings.TrimSpace(dt[1]), 10, 64)
			if err != nil {
				return nil, err
			}
			flag = int(val)
		case "62":
			val, err := strconv.ParseInt(strings.TrimSpace(dt[1]), 10, 64)
			if err != nil {
				return nil, err
			}
			col = color.ColorNumber(val)
		case "6":
			l, err := d.LineType(dt[1])
			if err != nil {
				return nil, err
			}
			lt = l
		case "370":
			val, err := strconv.ParseInt(strings.TrimSpace(dt[1]), 10, 64)
			if err != nil {
				return nil, err
			}
			lw = int(val)
		case "390":
			// plotstyle
		}
	}
	l := table.NewLayer(name, col, lt)
	l.SetFlag(flag)
	l.SetLineWidth(lw)
	return l, nil
}

func ParseStyle(d *drawing.Drawing, data [][2]string) (table.SymbolTable, error) {
	var name, font, bigfont string
	for _, dt := range data {
		switch dt[0] {
		case "2":
			name = dt[1]
		case "3":
			font = dt[1]
		case "4":
			bigfont = dt[1]
		}
	}
	s := table.NewStyle(name)
	s.FontName = font
	s.BigFontName = bigfont
	return s, nil
}

func ParseView(d *drawing.Drawing, data [][2]string) (table.SymbolTable, error) {
	return nil, nil
}

func ParseUCS(d *drawing.Drawing, data [][2]string) (table.SymbolTable, error) {
	return nil, nil
}

func ParseAppID(d *drawing.Drawing, data [][2]string) (table.SymbolTable, error) {
	var name string
	for _, dt := range data {
		switch dt[0] {
		case "2":
			name = dt[1]
		}
	}
	a := table.NewAppID(name)
	return a, nil
}

func ParseDimStyle(d *drawing.Drawing, data [][2]string) (table.SymbolTable, error) {
	var name string
	for _, dt := range data {
		switch dt[0] {
		case "2":
			name = dt[1]
		}
	}
	ds := table.NewDimStyle(name)
	return ds, nil
}

func ParseBlockRecord(d *drawing.Drawing, data [][2]string) (table.SymbolTable, error) {
	var name string
	for _, dt := range data {
		switch dt[0] {
		case "2":
			name = dt[1]
		}
	}
	b := table.NewBlockRecord(name)
	return b, nil
}

// BLOCKS
func ParseBlocks(d *drawing.Drawing, line int, data [][2]string) error {
	return nil
}

// ENTITIES
func ParseEntities(d *drawing.Drawing, line int, data [][2]string) error {
	tmpdata := make([][2]string, 0)
	for i, dt := range data {
		if dt[0] == "0" {
			if len(tmpdata) > 0 {
				e, err := ParseEntity(d, tmpdata)
				if err != nil {
					return fmt.Errorf("line %d: %s", line + 2*i, err.Error())
				}
				d.AddEntity(e)
				tmpdata = make([][2]string, 0)
			}
		}
		tmpdata = append(tmpdata, dt)
	}
	if len(tmpdata) > 0 {
		e, err := ParseEntity(d, tmpdata)
		if err != nil {
			return fmt.Errorf("line %d: %s", line + 2*len(data), err.Error())
		}
		d.AddEntity(e)
		tmpdata = make([][2]string, 0)
	}
	return nil
}

func ParseEntity(d *drawing.Drawing, data [][2]string) (entity.Entity, error) {
	if len(data) < 1 {
		return nil, fmt.Errorf("no data")
	}
	if data[0][0] != "0" {
		return nil, fmt.Errorf("invalid group code: %d", data[0][0])
	}
	f, err := ParseEntityFunc(data[0][1])
	if err != nil {
		return nil, err
	}
	return f(d, data)
}

func ParseEntityFunc(t string) (func(*drawing.Drawing, [][2]string)(entity.Entity, error), error) {
	switch t {
	case "LINE":
		return ParseLine, nil
	// case "3DFACE":
	// 	return Parse3DFace, nil
	// case "LWPOLYLINE":
	// 	return ParseLwPolyline, nil
	// case "CIRCLE":
	// 	return ParseCircle, nil
	// case "POLYLINE":
	// 	return ParsePolyline, nil
	// case "VERTEX":
	// 	return ParseVertex, nil
	// case "POINT":
	// 	return ParsePoint, nil
	// case "TEXT":
	// 	return ParseText, nil
	default:
		return nil, errors.New("unknown entity type")
	}
}

func ParseLine(d *drawing.Drawing, data [][2]string) (entity.Entity, error) {
	l := entity.NewLine()
	var err error
	for _, dt := range data {
		switch dt[0] {
		default:
			continue
		case "8":
			if layer, exists := d.Layers[dt[1]]; exists {
				l.SetLayer(layer)
			} else {
				err = fmt.Errorf("unknown layer: %s", dt[1])
			}
		case "10":
			err = SetFloat(dt, func(val float64) { l.Start[0] = val })
		case "20":
			err = SetFloat(dt, func(val float64) { l.Start[1] = val })
		case "30":
			err = SetFloat(dt, func(val float64) { l.Start[2] = val })
		case "11":
			err = SetFloat(dt, func(val float64) { l.End[0] = val })
		case "21":
			err = SetFloat(dt, func(val float64) { l.End[1] = val })
		case "31":
			err = SetFloat(dt, func(val float64) { l.End[2] = val })
		}
		if err != nil {
			return l, err
		}
	}
	return l, nil
}

// OBJECTS
func ParseObjects(d *drawing.Drawing, line int, data [][2]string) error {
	return nil
}
<|endoftext|>


<commit_before>package logmunch

import (
	"encoding/json"
	"fmt"
	"strconv"
	"strings"
	"time"
	"unicode"

	"github.com/kr/logfmt"
)

var timeformats []string = []string{
	// Output from Node.js' Winston logger
	"2006-01-02T15:04:05.000000-07:00",

	// RFC3339 / ISO.. timestamp
	time.RFC3339Nano,
	time.RFC3339,
}

// TODO(msiebuhr): Arrays and nil's
func flattenAndStringifyJSON(prefix string, data map[string]interface{}, log *LogLine) {
	for key, value := range data {

		// Compute new key
		if len(prefix) > 0 {
			key = strings.Join([]string{prefix, key}, ".")
		}

		// What to do with values
		switch t := value.(type) {
		case bool:
			if t {
				log.Entries[key] = "true"
			} else {
				log.Entries[key] = "false"
			}
		case float64:
			log.SetNumber(key, t)
		case string:
			log.Entries[key] = t
		case map[string]interface{}:
			flattenAndStringifyJSON(key, t, log)
		case nil:
			log.Entries[key] = ""
		default:
			//fmt.Println("Doesn't know what to do with", t)
			log.Entries[key] = fmt.Sprintf("UNSUPPORTED: %+v", t)
		}
	}
}

func tryParseOutJSON(line string, log *LogLine) bool {
	curlyIndex := strings.IndexRune(line, '{')
	if curlyIndex == -1 {
		return false
	}

	interfaceMap := make(map[string]interface{})
	err := json.Unmarshal([]byte(line[curlyIndex:]), &interfaceMap)

	if err != nil {
		return false
	}

	// Set line prefix and flatten JSON to one level of strings
	log.Name = strings.Trim(line[:curlyIndex], " \t-")
	flattenAndStringifyJSON("", interfaceMap, log)

	return true
}

// Parse out Heroku's LogFmt dyno output
func tryHerokuLogFmt(line string, log *LogLine) bool {
	// Name is everything until ` - - `; logfmt follows after
	dashIndex := strings.Index(line, " - - ")
	if dashIndex == -1 {
		return false
	}

	// After the dashes, there should at least be three (chosen at random) =-signs
	equals := strings.Count(line[dashIndex+5:], "=")

	if equals < 3 {
		return false
	}

	log.Name = line[:dashIndex]
	logfmt.Unmarshal([]byte(line[dashIndex+5:]), log)
	return true
}

// Try parsing NAME NAME KEY=VALUE
func tryPrefixedLogFmt(line string, log *LogLine) bool {
	// Keep track of the last word-break before a word with '=' in it
	lastSpaceBeforeLogFmtWord := 0
	for i, letter := range line {
		if letter == '=' {
			break
		}
		if unicode.IsSpace(letter) {
			lastSpaceBeforeLogFmtWord = i
		}

		// We got to the end without breaking on a = -> There's no = -> no logfmt in here
		if i == len(line)-1 {
			return false
		}
	}
	log.Name = line[:lastSpaceBeforeLogFmtWord]
	logfmt.Unmarshal([]byte(line[lastSpaceBeforeLogFmtWord:]), log)
	return true
}

func tryPlainMessage(line string, log *LogLine) bool {
	// Name is everything until ` - - `; logfmt follows after
	dashIndex := strings.Index(line, " - - ")
	if dashIndex == -1 {
		return false
	}

	hasEquals := strings.Index(line, "=")

	if hasEquals != -1 {
		return false
	}

	log.Name = line[:dashIndex]
	log.Entries["message"] = line[dashIndex+len(" - - "):]
	return true
}

// Check is the line is tick-escaped logfmt
//
// If we see `='` more often than `="`, assume things are generally `'`-quoted
// and swap all `'` for `"`'s and vice versa.
func tryTicEscapedLogFmt(line string, log *LogLine) bool {
	equalTics := strings.Count(line, "='")
	equalQuote := strings.Count(line, "=\"")

	// Break if we find no equals-things
	if equalTics == 0 {
		return false
	}

	if equalTics > equalQuote {
		// Swap ticks and quotes
		line = strings.Map(func(r rune) rune {
			switch r {
			case '\'':
				return '"'
			case '"':
				return '\''
			default:
				return r
			}
		}, line)
	}

	return tryPrefixedLogFmt(line, log)
}

func ParseLogEntries(in <-chan string, out chan<- LogLine) {
	defer close(out)
	for line := range in {
		// Skip empty lines
		if line == "" {
			continue
		}

		logLine := LogLine{
			Entries: make(map[string]string),
		}

		// Some log-lines from Heroku has a leading `d `, which I can't figure out.
		// So out it goes
		if len(line) >= 2 && line[0] == 'd' && line[1] == ' ' {
			line = line[2:]
		}

		// OFFSET ID TIMESTAMP LINE
		// but also
		// TIMESTAMP LINE
		lineParts := strings.Fields(line)

		if len(lineParts) < 1 {
			continue
		}

		// Remove the first element if equal line length
		// https://tools.ietf.org/html/rfc6587#section-3.4.1
		// LOG := LEN(LINE) + LINE
		length, err := strconv.ParseInt(lineParts[0], 10, 32)
		if err == nil && int(length) == (len(line)-len(lineParts[0])) {
			lineParts = lineParts[1:]
		}

		// Parse out PRIVAL
		// https://tools.ietf.org/html/rfc5424#section-6.2.1
		// < + (facility << 3) + severity + > + SYSLOG_VERSION
		if strings.HasPrefix(lineParts[0], "<") && strings.IndexRune(lineParts[0], '>') != -1 {
			prival, err := strconv.ParseInt(lineParts[0][1:strings.IndexRune(lineParts[0], '>')], 10, 32)
			if err == nil {
				logLine.Entries["syslog.severity"] = fmt.Sprintf("%d", prival&0x7)
				logLine.Entries["syslog.facility"] = fmt.Sprintf("%d", prival>>3)

				lineParts = lineParts[1:]
			}
		}

		// Try parsing each element in the line as various timestamps and see
		// what sticks.
		for i, part := range lineParts {
			// Seen in front-end logging system: `timestamp='TIMESTAMP'` if it starts with that - strip it
			if strings.HasPrefix(part, "timestamp='") {
				part = part[11 : len(part)-1] // Strip `timestamp='` and trailing `'`
			}

			for _, timefmt := range timeformats {
				lineTime, err := time.Parse(timefmt, part)

				if err == nil {
					logLine.Time = lineTime
					newLine := make([]string, len(lineParts)-1)
					copy(newLine[:i], lineParts[:i])
					copy(newLine[i:], lineParts[i+1:])
					lineParts = newLine
					break
				}
			}
		}

		if logLine.Time.IsZero() {
			fmt.Printf("Counld not find timestamp in line `%s`.\n", line)
			continue
		}

		restOfLine := strings.Join(lineParts, " ")

		// The somewhat popular `NAME {… JSON …}`
		if ok := tryParseOutJSON(restOfLine, &logLine); ok {
			out <- logLine
			continue
		}

		// Heroku's `d.UUID NAME - - key=val key=val …` format.
		if ok := tryHerokuLogFmt(restOfLine, &logLine); ok {
			out <- logLine
			continue
		}

		// Logentries serialize with a='b' (not a="b")
		if ok := tryTicEscapedLogFmt(restOfLine, &logLine); ok {
			out <- logLine
			continue
		}

		// Some prefix text and=then some=logfmt
		if ok := tryPrefixedLogFmt(restOfLine, &logLine); ok {
			out <- logLine
			continue
		}

		// Give up. ` SOMETHING - - MESSAGE GOES HERE`
		if ok := tryPlainMessage(restOfLine, &logLine); ok {
			out <- logLine
			continue
		}

		// Really really give up.
		logLine.Name = restOfLine
		out <- logLine
	}
}
<commit_msg>Parser: Write error messages to stderr<commit_after>package logmunch

import (
	"encoding/json"
	"fmt"
	"os"
	"strconv"
	"strings"
	"time"
	"unicode"

	"github.com/kr/logfmt"
)

var timeformats []string = []string{
	// Output from Node.js' Winston logger
	"2006-01-02T15:04:05.000000-07:00",

	// RFC3339 / ISO.. timestamp
	time.RFC3339Nano,
	time.RFC3339,
}

// TODO(msiebuhr): Arrays and nil's
func flattenAndStringifyJSON(prefix string, data map[string]interface{}, log *LogLine) {
	for key, value := range data {

		// Compute new key
		if len(prefix) > 0 {
			key = strings.Join([]string{prefix, key}, ".")
		}

		// What to do with values
		switch t := value.(type) {
		case bool:
			if t {
				log.Entries[key] = "true"
			} else {
				log.Entries[key] = "false"
			}
		case float64:
			log.SetNumber(key, t)
		case string:
			log.Entries[key] = t
		case map[string]interface{}:
			flattenAndStringifyJSON(key, t, log)
		case nil:
			log.Entries[key] = ""
		default:
			//fmt.Println("Doesn't know what to do with", t)
			log.Entries[key] = fmt.Sprintf("UNSUPPORTED: %+v", t)
		}
	}
}

func tryParseOutJSON(line string, log *LogLine) bool {
	curlyIndex := strings.IndexRune(line, '{')
	if curlyIndex == -1 {
		return false
	}

	interfaceMap := make(map[string]interface{})
	err := json.Unmarshal([]byte(line[curlyIndex:]), &interfaceMap)

	if err != nil {
		return false
	}

	// Set line prefix and flatten JSON to one level of strings
	log.Name = strings.Trim(line[:curlyIndex], " \t-")
	flattenAndStringifyJSON("", interfaceMap, log)

	return true
}

// Parse out Heroku's LogFmt dyno output
func tryHerokuLogFmt(line string, log *LogLine) bool {
	// Name is everything until ` - - `; logfmt follows after
	dashIndex := strings.Index(line, " - - ")
	if dashIndex == -1 {
		return false
	}

	// After the dashes, there should at least be three (chosen at random) =-signs
	equals := strings.Count(line[dashIndex+5:], "=")

	if equals < 3 {
		return false
	}

	log.Name = line[:dashIndex]
	logfmt.Unmarshal([]byte(line[dashIndex+5:]), log)
	return true
}

// Try parsing NAME NAME KEY=VALUE
func tryPrefixedLogFmt(line string, log *LogLine) bool {
	// Keep track of the last word-break before a word with '=' in it
	lastSpaceBeforeLogFmtWord := 0
	for i, letter := range line {
		if letter == '=' {
			break
		}
		if unicode.IsSpace(letter) {
			lastSpaceBeforeLogFmtWord = i
		}

		// We got to the end without breaking on a = -> There's no = -> no logfmt in here
		if i == len(line)-1 {
			return false
		}
	}
	log.Name = line[:lastSpaceBeforeLogFmtWord]
	logfmt.Unmarshal([]byte(line[lastSpaceBeforeLogFmtWord:]), log)
	return true
}

func tryPlainMessage(line string, log *LogLine) bool {
	// Name is everything until ` - - `; logfmt follows after
	dashIndex := strings.Index(line, " - - ")
	if dashIndex == -1 {
		return false
	}

	hasEquals := strings.Index(line, "=")

	if hasEquals != -1 {
		return false
	}

	log.Name = line[:dashIndex]
	log.Entries["message"] = line[dashIndex+len(" - - "):]
	return true
}

// Check is the line is tick-escaped logfmt
//
// If we see `='` more often than `="`, assume things are generally `'`-quoted
// and swap all `'` for `"`'s and vice versa.
func tryTicEscapedLogFmt(line string, log *LogLine) bool {
	equalTics := strings.Count(line, "='")
	equalQuote := strings.Count(line, "=\"")

	// Break if we find no equals-things
	if equalTics == 0 {
		return false
	}

	if equalTics > equalQuote {
		// Swap ticks and quotes
		line = strings.Map(func(r rune) rune {
			switch r {
			case '\'':
				return '"'
			case '"':
				return '\''
			default:
				return r
			}
		}, line)
	}

	return tryPrefixedLogFmt(line, log)
}

func ParseLogEntries(in <-chan string, out chan<- LogLine) {
	defer close(out)
	for line := range in {
		// Skip empty lines
		if line == "" {
			continue
		}

		logLine := LogLine{
			Entries: make(map[string]string),
		}

		// Some log-lines from Heroku has a leading `d `, which I can't figure out.
		// So out it goes
		if len(line) >= 2 && line[0] == 'd' && line[1] == ' ' {
			line = line[2:]
		}

		// OFFSET ID TIMESTAMP LINE
		// but also
		// TIMESTAMP LINE
		lineParts := strings.Fields(line)

		if len(lineParts) < 1 {
			continue
		}

		// Remove the first element if equal line length
		// https://tools.ietf.org/html/rfc6587#section-3.4.1
		// LOG := LEN(LINE) + LINE
		length, err := strconv.ParseInt(lineParts[0], 10, 32)
		if err == nil && int(length) == (len(line)-len(lineParts[0])) {
			lineParts = lineParts[1:]
		}

		// Parse out PRIVAL
		// https://tools.ietf.org/html/rfc5424#section-6.2.1
		// < + (facility << 3) + severity + > + SYSLOG_VERSION
		if strings.HasPrefix(lineParts[0], "<") && strings.IndexRune(lineParts[0], '>') != -1 {
			prival, err := strconv.ParseInt(lineParts[0][1:strings.IndexRune(lineParts[0], '>')], 10, 32)
			if err == nil {
				logLine.Entries["syslog.severity"] = fmt.Sprintf("%d", prival&0x7)
				logLine.Entries["syslog.facility"] = fmt.Sprintf("%d", prival>>3)

				lineParts = lineParts[1:]
			}
		}

		// Try parsing each element in the line as various timestamps and see
		// what sticks.
		for i, part := range lineParts {
			// Seen in front-end logging system: `timestamp='TIMESTAMP'` if it starts with that - strip it
			if strings.HasPrefix(part, "timestamp='") {
				part = part[11 : len(part)-1] // Strip `timestamp='` and trailing `'`
			}

			for _, timefmt := range timeformats {
				lineTime, err := time.Parse(timefmt, part)

				if err == nil {
					logLine.Time = lineTime
					newLine := make([]string, len(lineParts)-1)
					copy(newLine[:i], lineParts[:i])
					copy(newLine[i:], lineParts[i+1:])
					lineParts = newLine
					break
				}
			}
		}

		if logLine.Time.IsZero() {
			fmt.Fprintf(os.Stderr, "Could not find timestamp in line `%s`.\n", line)
			continue
		}

		restOfLine := strings.Join(lineParts, " ")

		// The somewhat popular `NAME {… JSON …}`
		if ok := tryParseOutJSON(restOfLine, &logLine); ok {
			out <- logLine
			continue
		}

		// Heroku's `d.UUID NAME - - key=val key=val …` format.
		if ok := tryHerokuLogFmt(restOfLine, &logLine); ok {
			out <- logLine
			continue
		}

		// Logentries serialize with a='b' (not a="b")
		if ok := tryTicEscapedLogFmt(restOfLine, &logLine); ok {
			out <- logLine
			continue
		}

		// Some prefix text and=then some=logfmt
		if ok := tryPrefixedLogFmt(restOfLine, &logLine); ok {
			out <- logLine
			continue
		}

		// Give up. ` SOMETHING - - MESSAGE GOES HERE`
		if ok := tryPlainMessage(restOfLine, &logLine); ok {
			out <- logLine
			continue
		}

		// Really really give up.
		logLine.Name = restOfLine
		out <- logLine
	}
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"os/user"
	"strconv"
	"strings"
	"syscall"
	"time"
)

var uidMap = map[string]user.User{}
var headerEndChar = []byte{")"[0]}

const (
	HEADER_MIN_LENGTH = 7               // Minimum length of an audit header
	HEADER_START_POS  = 6               // Position in the audit header that the data starts
	COMPLETE_AFTER    = time.Second * 2 // Log a message after this time or EOE
)

type AuditMessage struct {
	Type uint16 `json:"type"`
	Data string `json:"data"`
	Seq int `json:"-"`
	AuditTime string `json:"-"`
}

type AuditMessageGroup struct {
	Seq           int `json:"sequence"`
	AuditTime     string `json:"timestamp"`
	CompleteAfter time.Time `json:"-"`
	Msgs          []*AuditMessage `json:"messages"`
	UidMap        map[string]string `json:"uid_map"`
}

func NewAuditMessageGroup(am *AuditMessage) *AuditMessageGroup {
	//TODO: allocating 6 msgs per group is lame and we _should_ know ahead of time roughly how many we need
	amg := &AuditMessageGroup{
		Seq:           am.Seq,
		AuditTime:     am.AuditTime,
		CompleteAfter: time.Now().Add(COMPLETE_AFTER),
		Msgs:          make([]*AuditMessage, 6), // 6 msgs per execve is common
		UidMap:        make(map[string]string, 2), // Usually only 2 individual uids per execve
	}

	amg.AddMessage(am)
	return amg
}

func NewAuditMessage(nlm *syscall.NetlinkMessage) *AuditMessage {
	aTime, seq := parseAuditHeader(nlm)
	return &AuditMessage{
		Type: nlm.Header.Type,
		Data: string(nlm.Data),
		Seq: seq,
		AuditTime: aTime,
	}
}

func parseAuditHeader(msg *syscall.NetlinkMessage) (time string, seq int) {
	headerStop := bytes.Index(msg.Data, headerEndChar)
	// If the position the header appears to stop is less than the minimum length of a header, bail out
	if headerStop < HEADER_MIN_LENGTH {
		return
	}

	header := string(msg.Data[:headerStop])
	if header[:HEADER_START_POS] == "audit(" {
		//TODO: out of range check, possibly fully binary?
		sep := strings.IndexByte(header, ":"[0])
		time = header[HEADER_START_POS:sep]
		seq, _ = strconv.Atoi(header[sep + 1:])

		// Remove the header from data
		msg.Data = msg.Data[headerStop+2:]
	}

	return time, seq
}

func (amg *AuditMessageGroup) AddMessage(am *AuditMessage) {
	amg.Msgs = append(amg.Msgs, am)
	//TODO: need to find more message types that won't contain uids, also make these constants
	switch am.Type {
	case 1309, 1307:
		// Don't map uids here
	default:
		amg.mapUids(am)
	}
}

//This takes the map to modify and a key name and adds the username to a new key with "_username"
func (amg *AuditMessageGroup) mapUids(am *AuditMessage) {
	data := am.Data
	start := 0
	end := 0

	for {
		if start = strings.Index(data, "uid="); start < 0 {
			break
		}

		start += 4
		if end = strings.IndexByte(data[start:], " "[0]); end < 0 {
			break
		}

		uid := data[start:start + end]
		// Don't bother re-adding if the existing group already has the mapping
		if _, ok := amg.UidMap[uid]; !ok {
			amg.UidMap[uid] = findUid(data[start:start + end])
		}

		next := start + end + 1
		if (next >= len(data)) {
			break
		}
		data = data[next:]
	}

}

func findUid(uid string) (string) {
	uname := "UNKNOWN_USER"

	//Make sure we have a uid element to work with.
	//Give a default value in case we don't find something.
	if lUser, ok := uidMap[uid]; ok {
		uname = lUser.Username
	} else {
		lUser, err := user.LookupId(uid)
		if err == nil {
			uname = lUser.Username
			uidMap[uid] = *lUser
		} else {
			uidMap[uid] = user.User{Username: uname}
		}
	}

	return uname
}
<commit_msg>Reverting pre-allocated msg space<commit_after>package main

import (
	"bytes"
	"os/user"
	"strconv"
	"strings"
	"syscall"
	"time"
)

var uidMap = map[string]user.User{}
var headerEndChar = []byte{")"[0]}

const (
	HEADER_MIN_LENGTH = 7               // Minimum length of an audit header
	HEADER_START_POS  = 6               // Position in the audit header that the data starts
	COMPLETE_AFTER    = time.Second * 2 // Log a message after this time or EOE
)

type AuditMessage struct {
	Type uint16 `json:"type"`
	Data string `json:"data"`
	Seq int `json:"-"`
	AuditTime string `json:"-"`
}

type AuditMessageGroup struct {
	Seq           int `json:"sequence"`
	AuditTime     string `json:"timestamp"`
	CompleteAfter time.Time `json:"-"`
	Msgs          []*AuditMessage `json:"messages"`
	UidMap        map[string]string `json:"uid_map"`
}

func NewAuditMessageGroup(am *AuditMessage) *AuditMessageGroup {
	//TODO: allocating 6 msgs per group is lame and we _should_ know ahead of time roughly how many we need
	amg := &AuditMessageGroup{
		Seq:           am.Seq,
		AuditTime:     am.AuditTime,
		CompleteAfter: time.Now().Add(COMPLETE_AFTER),
		UidMap:        make(map[string]string, 2), // Usually only 2 individual uids per execve
	}

	amg.AddMessage(am)
	return amg
}

func NewAuditMessage(nlm *syscall.NetlinkMessage) *AuditMessage {
	aTime, seq := parseAuditHeader(nlm)
	return &AuditMessage{
		Type: nlm.Header.Type,
		Data: string(nlm.Data),
		Seq: seq,
		AuditTime: aTime,
	}
}

func parseAuditHeader(msg *syscall.NetlinkMessage) (time string, seq int) {
	headerStop := bytes.Index(msg.Data, headerEndChar)
	// If the position the header appears to stop is less than the minimum length of a header, bail out
	if headerStop < HEADER_MIN_LENGTH {
		return
	}

	header := string(msg.Data[:headerStop])
	if header[:HEADER_START_POS] == "audit(" {
		//TODO: out of range check, possibly fully binary?
		sep := strings.IndexByte(header, ":"[0])
		time = header[HEADER_START_POS:sep]
		seq, _ = strconv.Atoi(header[sep + 1:])

		// Remove the header from data
		msg.Data = msg.Data[headerStop+2:]
	}

	return time, seq
}

func (amg *AuditMessageGroup) AddMessage(am *AuditMessage) {
	amg.Msgs = append(amg.Msgs, am)
	//TODO: need to find more message types that won't contain uids, also make these constants
	switch am.Type {
	case 1309, 1307:
		// Don't map uids here
	default:
		amg.mapUids(am)
	}
}

//This takes the map to modify and a key name and adds the username to a new key with "_username"
func (amg *AuditMessageGroup) mapUids(am *AuditMessage) {
	data := am.Data
	start := 0
	end := 0

	for {
		if start = strings.Index(data, "uid="); start < 0 {
			break
		}

		start += 4
		if end = strings.IndexByte(data[start:], " "[0]); end < 0 {
			break
		}

		uid := data[start:start + end]
		// Don't bother re-adding if the existing group already has the mapping
		if _, ok := amg.UidMap[uid]; !ok {
			amg.UidMap[uid] = findUid(data[start:start + end])
		}

		next := start + end + 1
		if (next >= len(data)) {
			break
		}
		data = data[next:]
	}

}

func findUid(uid string) (string) {
	uname := "UNKNOWN_USER"

	//Make sure we have a uid element to work with.
	//Give a default value in case we don't find something.
	if lUser, ok := uidMap[uid]; ok {
		uname = lUser.Username
	} else {
		lUser, err := user.LookupId(uid)
		if err == nil {
			uname = lUser.Username
			uidMap[uid] = *lUser
		} else {
			uidMap[uid] = user.User{Username: uname}
		}
	}

	return uname
}
<|endoftext|>


<commit_before>// Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.

package provider

import (
	"log"
)

const Version = "3.12.0"

func PrintVersion() {
	log.Printf("[INFO] terraform-provider-oci %s\n", Version)
}
<commit_msg>Finalize changelog and release version<commit_after>// Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.

package provider

import (
	"log"
)

const Version = "3.13.0"

func PrintVersion() {
	log.Printf("[INFO] terraform-provider-oci %s\n", Version)
}
<|endoftext|>


<commit_before><commit_msg>add cachegroups<commit_after><|endoftext|>


<commit_before>package geometry

import (
	"github.com/gonum/matrix/mat64"
)

// Plane3 Struct
type Plane3 struct {
	Normal   *mat64.Vector
	Constant float64
}

// NewPlane3 creates a new Plane
func NewPlane3(normal *mat64.Vector, constant float64) *Plane3 {
	p := &Plane3{}
	p.Normal = normal
	p.Constant = constant
	return p
}

// Set Plane from Normal and Constant
func (p *Plane3) Set(normal *mat64.Vector, constant float64) {
	p.Normal = normal
	p.Constant = constant
}

// DistanceToPoint calculates the Distance from the Plane to a given Point
func (p *Plane3) DistanceToPoint(point *mat64.Vector) float64 {
	return Dot(p.Normal, point) + p.Constant
}

// SetComponents sets the Planes components
func (p *Plane3) SetComponents(x, y, z, w float64) {
	p.Normal = mat64.NewVector(3, []float64{x, y, z})
	p.Constant = w
}

// SetFromNormalAndCoplanarPoint sets the Plane from normal vector and onepoint containted by the plane
func (p *Plane3) SetFromNormalAndCoplanarPoint(normal *mat64.Vector, point *mat64.Vector) {
	p.Normal = normal
	p.Constant = -Dot(point, p.Normal)
}
<commit_msg>Project Point<commit_after>package geometry

import (
	"github.com/gonum/matrix/mat64"
)

// Plane3 Struct
type Plane3 struct {
	Normal   *mat64.Vector
	Constant float64
}

// NewPlane3 creates a new Plane
func NewPlane3(normal *mat64.Vector, constant float64) *Plane3 {
	p := &Plane3{}
	p.Normal = normal
	p.Constant = constant
	return p
}

// Set Plane from Normal and Constant
func (p *Plane3) Set(normal *mat64.Vector, constant float64) {
	p.Normal = normal
	p.Constant = constant
}

// DistanceToPoint calculates the Distance from the Plane to a given Point
func (p *Plane3) DistanceToPoint(point *mat64.Vector) float64 {
	return Dot(p.Normal, point) + p.Constant
}

// SetComponents sets the Planes components
func (p *Plane3) SetComponents(x, y, z, w float64) {
	p.Normal = mat64.NewVector(3, []float64{x, y, z})
	p.Constant = w
}

// SetFromNormalAndCoplanarPoint sets the Plane from normal vector and onepoint containted by the plane
func (p *Plane3) SetFromNormalAndCoplanarPoint(normal *mat64.Vector, point *mat64.Vector) {
	p.Normal = normal
	p.Constant = -Dot(point, p.Normal)
}

// ProjectPoint projects a point on the plane
func (p *Plane3) ProjectPoint(point *mat64.Vector) *mat64.Vector {
	projectedPoint := p.Normal
	scale := -p.DistanceToPoint(point)
	projectedPoint.ScaleVec(scale, projectedPoint)
	projectedPoint.AddVec(projectedPoint, point)
	return projectedPoint
}
<|endoftext|>


<commit_before>package teleport

import (
	"github.com/henrylee2cn/goutil/errors"
)

type (
	// PluginContainer plugin container that defines base methods to manage plugins.
	PluginContainer interface {
		Add(plugins ...Plugin) error
		Remove(pluginName string) error
		GetByName(pluginName string) Plugin
		GetAll() []Plugin
		PreConnectPlugin
		PostConnectPlugin
		PreWritePacketPlugin
		PostWritePacketPlugin
		PreReadHeaderPlugin
		PostReadHeaderPlugin
		PreReadBodyPlugin
		PostReadBodyPlugin
	}
	//Plugin represents a plugin.
	Plugin interface {
		Name() string
	}
	PreConnectPlugin interface {
		PreConnect(string, interface{}) error
	}
	PostConnectPlugin interface {
		PostConnect(Conn) error
	}
	PreWritePacketPlugin interface {
		PreWritePacket(Context, interface{}) error
	}
	PostWritePacketPlugin interface {
		PostWritePacket(Context, interface{}) error
	}
	PreReadHeaderPlugin interface {
		PreReadHeader(Context) error
	}
	PostReadHeaderPlugin interface {
		PostReadHeader(Context) error
	}
	PreReadBodyPlugin interface {
		PreReadBody(Context, interface{}) error
	}
	PostReadBodyPlugin interface {
		PostReadBody(Context, interface{}) error
	}
)

func NewPluginContainer() PluginContainer {
	return new(pluginContainer)
}

type pluginContainer struct {
	plugins []Plugin
}

// Add adds a plugin.
func (p *pluginContainer) Add(plugins ...Plugin) error {
	if p.plugins == nil {
		p.plugins = make([]Plugin, 0)
	}
	for _, plugin := range plugins {
		if plugin == nil {
			return errors.New("the plugin cannot be nil!")
		}
		pName := plugin.Name()
		if len(pName) == 0 && p.GetByName(pName) != nil {
			return errors.Errorf("repeat add the plugin: %s", pName)
		}
		p.plugins = append(p.plugins, plugin)
	}
	return nil
}

// Remove removes a plugin by it's name.
func (p *pluginContainer) Remove(pluginName string) error {
	if p.plugins == nil {
		return errors.New("no plugins are registed yet!")
	}
	if len(pluginName) == 0 {
		//return error: cannot delete an unamed plugin
		return errors.New("plugin with an empty name cannot be removed")
	}
	indexToRemove := -1
	for i, plugin := range p.plugins {
		if plugin.Name() == pluginName {
			indexToRemove = i
			break
		}
	}
	if indexToRemove == -1 {
		return errors.New("cannot remove a plugin which esn't exists")
	}
	p.plugins = append(p.plugins[:indexToRemove], p.plugins[indexToRemove+1:]...)
	return nil
}

// GetByName returns a plugin instance by it's name
func (p *pluginContainer) GetByName(pluginName string) Plugin {
	if p.plugins == nil {
		return nil
	}
	for _, plugin := range p.plugins {
		if plugin.Name() == pluginName {
			return plugin
		}
	}
	return nil
}

// GetAll returns all activated plugins
func (p *pluginContainer) GetAll() []Plugin {
	return p.plugins
}

func (p *pluginContainer) PreConnect(nodePath string, rcvr interface{}) error {
	var errs []error
	for _, plugin := range p.plugins {
		if _plugin, ok := plugin.(PreConnectPlugin); ok {
			err := _plugin.PreConnect(nodePath, rcvr)
			if err != nil {
				errs = append(errs, errors.Errorf("PreConnectPlugin(%s): %s", plugin.Name(), err.Error()))
			}
		}
	}
	return errors.Merge(errs...)
}

func (p *pluginContainer) PostConnect(conn Conn) error {
	for _, plugin := range p.plugins {
		if _plugin, ok := plugin.(PostConnectPlugin); ok {
			if err := _plugin.PostConnect(conn); err != nil {
				conn.Close()
				return errors.Errorf("PostConnectPlugin(%s): %s", plugin.Name(), err.Error())
			}
		}
	}
	return nil
}

func (p *pluginContainer) PreWritePacket(ctx Context, body interface{}) error {
	for _, plugin := range p.plugins {
		if _plugin, ok := plugin.(PreWritePacketPlugin); ok {
			if err := _plugin.PreWritePacket(ctx, body); err != nil {
				return errors.Errorf("PreWritePacketPlugin(%s): %s", plugin.Name(), err.Error())
			}
		}
	}
	return nil
}

func (p *pluginContainer) PostWritePacket(ctx Context, body interface{}) error {
	for _, plugin := range p.plugins {
		if _plugin, ok := plugin.(PostWritePacketPlugin); ok {
			if err := _plugin.PostWritePacket(ctx, body); err != nil {
				return errors.Errorf("PostWritePacketPlugin(%s): %s", plugin.Name(), err.Error())
			}
		}
	}
	return nil
}

func (p *pluginContainer) PreReadHeader(ctx Context) error {
	for _, plugin := range p.plugins {
		if _plugin, ok := plugin.(PreReadHeaderPlugin); ok {
			if err := _plugin.PreReadHeader(ctx); err != nil {
				return errors.Errorf("PreReadHeaderPlugin(%s): %s", plugin.Name(), err.Error())
			}
		}
	}
	return nil
}

func (p *pluginContainer) PostReadHeader(ctx Context) error {
	for _, plugin := range p.plugins {
		if _plugin, ok := plugin.(PostReadHeaderPlugin); ok {
			if err := _plugin.PostReadHeader(ctx); err != nil {
				return errors.Errorf("PostReadHeaderPlugin(%s): %s", plugin.Name(), err.Error())
			}
		}
	}
	return nil
}

func (p *pluginContainer) PreReadBody(ctx Context, body interface{}) error {
	for _, plugin := range p.plugins {
		if _plugin, ok := plugin.(PreReadBodyPlugin); ok {
			if err := _plugin.PreReadBody(ctx, body); err != nil {
				return errors.Errorf("PreReadBodyPlugin(%s): %s", plugin.Name(), err.Error())
			}
		}
	}
	return nil
}

func (p *pluginContainer) PostReadBody(ctx Context, body interface{}) error {
	for _, plugin := range p.plugins {
		if _plugin, ok := plugin.(PostReadBodyPlugin); ok {
			if err := _plugin.PostReadBody(ctx, body); err != nil {
				return errors.Errorf("PostReadBodyPlugin(%s): %s", plugin.Name(), err.Error())
			}
		}
	}
	return nil
}
<commit_msg>optimize plugin<commit_after>package teleport

import (
	"github.com/henrylee2cn/goutil/errors"
)

type (
	//Plugin represents a plugin.
	Plugin interface {
		Name() string
	}
	PreConnectPlugin interface {
		PreConnect(string, interface{}) error
	}
	PostConnectPlugin interface {
		PostConnect(Conn) error
	}
	PreWritePacketPlugin interface {
		PreWritePacket(Context, interface{}) error
	}
	PostWritePacketPlugin interface {
		PostWritePacket(Context, interface{}) error
	}
	PreReadHeaderPlugin interface {
		PreReadHeader(Context) error
	}
	PostReadHeaderPlugin interface {
		PostReadHeader(Context) error
	}
	PreReadBodyPlugin interface {
		PreReadBody(Context, interface{}) error
	}
	PostReadBodyPlugin interface {
		PostReadBody(Context, interface{}) error
	}
	// PluginContainer plugin container that defines base methods to manage plugins.
	PluginContainer interface {
		Add(plugins ...Plugin) error
		Remove(pluginName string) error
		GetByName(pluginName string) Plugin
		GetAll() []Plugin

		PreConnectPlugin
		PostConnectPlugin
		PreWritePacketPlugin
		PostWritePacketPlugin
		PreReadHeaderPlugin
		PostReadHeaderPlugin
		PreReadBodyPlugin
		PostReadBodyPlugin
	}
)

func NewPluginContainer() PluginContainer {
	return new(pluginContainer)
}

type pluginContainer struct {
	plugins []Plugin
}

// Add adds a plugin.
func (p *pluginContainer) Add(plugins ...Plugin) error {
	if p.plugins == nil {
		p.plugins = make([]Plugin, 0)
	}
	for _, plugin := range plugins {
		if plugin == nil {
			return errors.New("the plugin cannot be nil!")
		}
		pName := plugin.Name()
		if len(pName) == 0 && p.GetByName(pName) != nil {
			return errors.Errorf("repeat add the plugin: %s", pName)
		}
		p.plugins = append(p.plugins, plugin)
	}
	return nil
}

// Remove removes a plugin by it's name.
func (p *pluginContainer) Remove(pluginName string) error {
	if p.plugins == nil {
		return errors.New("no plugins are registed yet!")
	}
	if len(pluginName) == 0 {
		//return error: cannot delete an unamed plugin
		return errors.New("plugin with an empty name cannot be removed")
	}
	indexToRemove := -1
	for i, plugin := range p.plugins {
		if plugin.Name() == pluginName {
			indexToRemove = i
			break
		}
	}
	if indexToRemove == -1 {
		return errors.New("cannot remove a plugin which esn't exists")
	}
	p.plugins = append(p.plugins[:indexToRemove], p.plugins[indexToRemove+1:]...)
	return nil
}

// GetByName returns a plugin instance by it's name
func (p *pluginContainer) GetByName(pluginName string) Plugin {
	if p.plugins == nil {
		return nil
	}
	for _, plugin := range p.plugins {
		if plugin.Name() == pluginName {
			return plugin
		}
	}
	return nil
}

// GetAll returns all activated plugins
func (p *pluginContainer) GetAll() []Plugin {
	return p.plugins
}

func (p *pluginContainer) PreConnect(nodePath string, rcvr interface{}) error {
	var errs []error
	for _, plugin := range p.plugins {
		if _plugin, ok := plugin.(PreConnectPlugin); ok {
			err := _plugin.PreConnect(nodePath, rcvr)
			if err != nil {
				errs = append(errs, errors.Errorf("PreConnectPlugin(%s): %s", plugin.Name(), err.Error()))
			}
		}
	}
	return errors.Merge(errs...)
}

func (p *pluginContainer) PostConnect(conn Conn) error {
	for _, plugin := range p.plugins {
		if _plugin, ok := plugin.(PostConnectPlugin); ok {
			if err := _plugin.PostConnect(conn); err != nil {
				conn.Close()
				return errors.Errorf("PostConnectPlugin(%s): %s", plugin.Name(), err.Error())
			}
		}
	}
	return nil
}

func (p *pluginContainer) PreWritePacket(ctx Context, body interface{}) error {
	for _, plugin := range p.plugins {
		if _plugin, ok := plugin.(PreWritePacketPlugin); ok {
			if err := _plugin.PreWritePacket(ctx, body); err != nil {
				return errors.Errorf("PreWritePacketPlugin(%s): %s", plugin.Name(), err.Error())
			}
		}
	}
	return nil
}

func (p *pluginContainer) PostWritePacket(ctx Context, body interface{}) error {
	for _, plugin := range p.plugins {
		if _plugin, ok := plugin.(PostWritePacketPlugin); ok {
			if err := _plugin.PostWritePacket(ctx, body); err != nil {
				return errors.Errorf("PostWritePacketPlugin(%s): %s", plugin.Name(), err.Error())
			}
		}
	}
	return nil
}

func (p *pluginContainer) PreReadHeader(ctx Context) error {
	for _, plugin := range p.plugins {
		if _plugin, ok := plugin.(PreReadHeaderPlugin); ok {
			if err := _plugin.PreReadHeader(ctx); err != nil {
				return errors.Errorf("PreReadHeaderPlugin(%s): %s", plugin.Name(), err.Error())
			}
		}
	}
	return nil
}

func (p *pluginContainer) PostReadHeader(ctx Context) error {
	for _, plugin := range p.plugins {
		if _plugin, ok := plugin.(PostReadHeaderPlugin); ok {
			if err := _plugin.PostReadHeader(ctx); err != nil {
				return errors.Errorf("PostReadHeaderPlugin(%s): %s", plugin.Name(), err.Error())
			}
		}
	}
	return nil
}

func (p *pluginContainer) PreReadBody(ctx Context, body interface{}) error {
	for _, plugin := range p.plugins {
		if _plugin, ok := plugin.(PreReadBodyPlugin); ok {
			if err := _plugin.PreReadBody(ctx, body); err != nil {
				return errors.Errorf("PreReadBodyPlugin(%s): %s", plugin.Name(), err.Error())
			}
		}
	}
	return nil
}

func (p *pluginContainer) PostReadBody(ctx Context, body interface{}) error {
	for _, plugin := range p.plugins {
		if _plugin, ok := plugin.(PostReadBodyPlugin); ok {
			if err := _plugin.PostReadBody(ctx, body); err != nil {
				return errors.Errorf("PostReadBodyPlugin(%s): %s", plugin.Name(), err.Error())
			}
		}
	}
	return nil
}
<|endoftext|>