<commit_before>package main

import (
	"encoding/csv"
	"fmt"
	"math/rand"
	"os"
	"time"

	"github.com/dob/marketsim/shared/datatypes"
	"github.com/dob/marketsim/shared/utils"
)

const NUMBER_OF_ORDERS_IN_SIMULATION = 100000
const STOCK_SEED_FILE_LOC = "data/seed/nasdaq_stocks.csv"

// START SIMULATION

// Populate the market with some fake data
func stubMarketStocks(m *dt.Market)    {
	stocks := loadStocksFromSeedFile()
	for _, stock := range stocks {
		m.Stocks[stock.Symbol] = stock
	}
}

func loadStocksFromSeedFile() []*dt.Stock {
	stocks := make([]*dt.Stock, 0)

	csvFile, _ := os.Open(STOCK_SEED_FILE_LOC)
	defer csvFile.Close()

	reader := csv.NewReader(csvFile)
	reader.FieldsPerRecord = -1

	rawCSVData, _ := reader.ReadAll()

	for _, each := range rawCSVData {
		sym, name := each[0], each[1]
		fmt.Printf("adding %v: %v\n", sym, name)
		stocks = append(stocks, &dt.Stock{dt.StockSymbol(sym), name, dt.StartingPrice})
	}

	return stocks
}

// Initialize the market
func initializeMarketWithStocks() (*dt.Market, error) {
	var market *dt.Market = dt.NewMarket()
	stubMarketStocks(market)

	return market, nil
}

//Randomly generate n orders and sleep for 0-2 seconds in between
func generateOrders(n int, m *dt.Market, orderChannel chan *dt.Order) {
	// Randomly sleep between orders
	rand.Seed(time.Now().UnixNano())

	for i := 0; i < n; i++ {
		// Create a new order for a random stock with a random price
		symbols := m.Symbols()

		// Generate the order params
		symbol := symbols[rand.Intn(len(symbols))]
		buySellType := dt.OrderBuySellVal(rand.Intn(2) + 1) // Will be either buy or sell (1 or 2)
		orderType := dt.LimitOrderType                      // Right now we're only seeding orders as limit types to set prices

		var price float64

		priceForSymbol := m.GetPriceForSymbol(symbol)

		if orderType == dt.LimitOrderType {
			if (priceForSymbol.Bid == dt.StartingPrice.Bid) || (priceForSymbol.Offer == dt.StartingPrice.Offer) {
				// Go pretty random unless we have both bid and ask
				price = float64(rand.Intn(100)) + rand.Float64()
			} else {
				// Randomly choose positive or negative price fluctuation
				// within 5% of the current price
				priceDelta := float64(priceForSymbol.MidPrice()*0.05) * rand.Float64()

				if rand.Intn(2) == 0 {
					price = priceForSymbol.Bid + priceDelta
				} else {
					price = priceForSymbol.Bid - priceDelta
				}
			}
		}

		price = utils.RoundToPlaces(price, 2)
		shares := (rand.Intn(10) + 1) * 100 // Start with 100x share lots

		order := dt.Order{symbol, buySellType, orderType, shares, price, dt.OrderStatusOpen}

		orderChannel <- &order

		// Do we want to sleep for an interval between orders?
		//time.Sleep(time.Duration(rand.Intn(5)) * time.Millisecond)
	}
	close(orderChannel)
}

// Simulate the start of trading
func startTrading(m *dt.Market) {
	marketActivity := make(chan *dt.Order)

	go generateOrders(NUMBER_OF_ORDERS_IN_SIMULATION, m, marketActivity)
	for ord := range marketActivity {
		m.ReceiveOrder(ord)
	}
}

func main() {
	market, _ := initializeMarketWithStocks()
	fmt.Println(market)
	startTrading(market)
	fmt.Println(market)
}
<commit_msg>Changing formatting of marketsim<commit_after>package main

import (
	"encoding/csv"
	"fmt"
	"math/rand"
	"os"
	"time"

	"github.com/dob/marketsim/shared/datatypes"
	"github.com/dob/marketsim/shared/utils"
)

const NUMBER_OF_ORDERS_IN_SIMULATION = 100000
const STOCK_SEED_FILE_LOC = "data/seed/nasdaq_stocks.csv"

// START SIMULATION

// Populate the market with some fake data
func stubMarketStocks(m *dt.Market) {
	stocks := loadStocksFromSeedFile()
	for _, stock := range stocks {
		m.Stocks[stock.Symbol] = stock
	}
}

func loadStocksFromSeedFile() []*dt.Stock {
	stocks := make([]*dt.Stock, 0)

	csvFile, _ := os.Open(STOCK_SEED_FILE_LOC)
	defer csvFile.Close()

	reader := csv.NewReader(csvFile)
	reader.FieldsPerRecord = -1

	rawCSVData, _ := reader.ReadAll()

	for _, each := range rawCSVData {
		sym, name := each[0], each[1]
		fmt.Printf("adding %v: %v\n", sym, name)
		stocks = append(stocks, &dt.Stock{dt.StockSymbol(sym), name, dt.StartingPrice})
	}

	return stocks
}

// Initialize the market
func initializeMarketWithStocks() (*dt.Market, error) {
	var market *dt.Market = dt.NewMarket()
	stubMarketStocks(market)

	return market, nil
}

//Randomly generate n orders and sleep for 0-2 seconds in between
func generateOrders(n int, m *dt.Market, orderChannel chan *dt.Order) {
	// Randomly sleep between orders
	rand.Seed(time.Now().UnixNano())

	for i := 0; i < n; i++ {
		// Create a new order for a random stock with a random price
		symbols := m.Symbols()

		// Generate the order params
		symbol := symbols[rand.Intn(len(symbols))]
		buySellType := dt.OrderBuySellVal(rand.Intn(2) + 1) // Will be either buy or sell (1 or 2)
		orderType := dt.LimitOrderType                      // Right now we're only seeding orders as limit types to set prices

		var price float64

		priceForSymbol := m.GetPriceForSymbol(symbol)

		if orderType == dt.LimitOrderType {
			if (priceForSymbol.Bid == dt.StartingPrice.Bid) || (priceForSymbol.Offer == dt.StartingPrice.Offer) {
				// Go pretty random unless we have both bid and ask
				price = float64(rand.Intn(100)) + rand.Float64()
			} else {
				// Randomly choose positive or negative price fluctuation
				// within 5% of the current price
				priceDelta := float64(priceForSymbol.MidPrice()*0.05) * rand.Float64()

				if rand.Intn(2) == 0 {
					price = priceForSymbol.Bid + priceDelta
				} else {
					price = priceForSymbol.Bid - priceDelta
				}
			}
		}

		price = utils.RoundToPlaces(price, 2)
		shares := (rand.Intn(10) + 1) * 100 // Start with 100x share lots

		order := dt.Order{symbol, buySellType, orderType, shares, price, dt.OrderStatusOpen}

		orderChannel <- &order

		// Do we want to sleep for an interval between orders?
		//time.Sleep(time.Duration(rand.Intn(5)) * time.Millisecond)
	}
	close(orderChannel)
}

// Simulate the start of trading
func startTrading(m *dt.Market) {
	marketActivity := make(chan *dt.Order)

	go generateOrders(NUMBER_OF_ORDERS_IN_SIMULATION, m, marketActivity)
	for ord := range marketActivity {
		m.ReceiveOrder(ord)
	}
}

func main() {
	market, _ := initializeMarketWithStocks()
	fmt.Println(market)
	startTrading(market)
	fmt.Println(market)
}
<|endoftext|>


<commit_before>// +build linux

package gopsutil

import (
	"syscall"
)

func VirtualMemory() (*VirtualMemoryStat, error) {
	sysinfo := &syscall.Sysinfo_t{}

	if err := syscall.Sysinfo(sysinfo); err != nil {
		return nil, err
	}

	ret := &VirtualMemoryStat{
		Total:   uint64(sysinfo.Totalram),
		Free:    uint64(sysinfo.Freeram),
		Shared:  uint64(sysinfo.Sharedram),
		Buffers: uint64(sysinfo.Bufferram),
	}

	ret.Used = ret.Total - ret.Free

	// TODO: platform independent
	ret.Available = ret.Free + ret.Buffers + ret.Cached

	ret.Used = ret.Total - ret.Free
	ret.UsedPercent = float64(ret.Total-ret.Available) / float64(ret.Total) * 100.0

	/*
		kern := buffers + cached
		ret.ActualFree = ret.Free + kern
		ret.ActualUsed = ret.Used - kern
	*/

	return ret, nil
}

func SwapMemory() (*SwapMemoryStat, error) {
	sysinfo := &syscall.Sysinfo_t{}

	if err := syscall.Sysinfo(sysinfo); err != nil {
		return nil, err
	}
	ret := &SwapMemoryStat{
		Total: uint64(sysinfo.Totalswap),
		Free:  uint64(sysinfo.Freeswap),
	}
	ret.Used = ret.Total - ret.Free
	ret.UsedPercent = float64(ret.Total-ret.Free) / float64(ret.Total) * 100.0

	return ret, nil
}
<commit_msg>remove duped line.<commit_after>// +build linux

package gopsutil

import (
	"syscall"
)

func VirtualMemory() (*VirtualMemoryStat, error) {
	sysinfo := &syscall.Sysinfo_t{}

	if err := syscall.Sysinfo(sysinfo); err != nil {
		return nil, err
	}

	ret := &VirtualMemoryStat{
		Total:   uint64(sysinfo.Totalram),
		Free:    uint64(sysinfo.Freeram),
		Shared:  uint64(sysinfo.Sharedram),
		Buffers: uint64(sysinfo.Bufferram),
	}

	// TODO: platform independent
	ret.Available = ret.Free + ret.Buffers + ret.Cached

	ret.Used = ret.Total - ret.Free
	ret.UsedPercent = float64(ret.Total-ret.Available) / float64(ret.Total) * 100.0

	/*
		kern := buffers + cached
		ret.ActualFree = ret.Free + kern
		ret.ActualUsed = ret.Used - kern
	*/

	return ret, nil
}

func SwapMemory() (*SwapMemoryStat, error) {
	sysinfo := &syscall.Sysinfo_t{}

	if err := syscall.Sysinfo(sysinfo); err != nil {
		return nil, err
	}
	ret := &SwapMemoryStat{
		Total: uint64(sysinfo.Totalswap),
		Free:  uint64(sysinfo.Freeswap),
	}
	ret.Used = ret.Total - ret.Free
	ret.UsedPercent = float64(ret.Total-ret.Free) / float64(ret.Total) * 100.0

	return ret, nil
}
<|endoftext|>


<commit_before>package main

import (
	log "code.google.com/p/log4go"
	"sync"
	"time"
)

type RoomOptions struct {
	ChannelSize int
	ProtoSize   int
	BatchNum    int
	SignalTime  time.Duration
}

type Room struct {
	id      int32
	rLock   sync.RWMutex
	proto   Ring
	signal  chan int
	chs     map[*Channel]struct{} // map room id with channels
	sigTime time.Duration
	options RoomOptions
}

// NewRoom new a room struct, store channel room info.
func NewRoom(id int32, options RoomOptions) (r *Room) {
	r = new(Room)
	r.id = id
	r.options = options
	r.proto.Init(options.ProtoSize)
	r.signal = make(chan int, signalNum)
	r.chs = make(map[*Channel]struct{}, options.ChannelSize)
	go r.push()
	return
}

// Put put channel into the room.
func (r *Room) Put(ch *Channel) {
	r.rLock.Lock()
	r.chs[ch] = struct{}{}
	r.rLock.Unlock()
	return
}

// Del delete channel from the room.
func (r *Room) Del(ch *Channel) {
	r.rLock.Lock()
	delete(r.chs, ch)
	r.rLock.Unlock()
}

// push merge proto and push msgs in batch.
func (r *Room) push() {
	var (
		s, n       int
		exit, done bool
		err        error
		p          *Proto
		ch         *Channel
		least      time.Duration
		last       = time.Now()
		vers       = make([]int32, r.options.BatchNum)
		operations = make([]int32, r.options.BatchNum)
		msgs       = make([][]byte, r.options.BatchNum)
	)
	if Debug {
		log.Debug("start room: %d goroutine", r.id)
	}
	for {
		if least = r.options.SignalTime - time.Now().Sub(last); least > 0 {
			select {
			case s = <-r.signal:
				if exit = (s != protoReady); exit {
					done = true
					break
				}
				// merge msgs
				if n == 0 {
					last = time.Now()
				}
				for {
					if n >= r.options.BatchNum {
						// msgs full
						done = true
						break
					}
					if p, err = r.proto.Get(); err != nil {
						// must be empty error
						break
					}
					vers[n] = int32(p.Ver)
					operations[n] = p.Operation
					msgs[n] = p.Body
					n++
					r.proto.GetAdv()
				}
			case <-time.After(least):
				done = true
				exit = false
			}
		} else {
			done = true
		}
		if done {
			if n > 0 {
				r.rLock.RLock()
				for ch, _ = range r.chs {
					// ignore error
					ch.PushMsgs(vers[:n], operations[:n], msgs[:n])
				}
				r.rLock.RUnlock()
				n = 0
			}
			done = false
			last = time.Now()
		}
		if exit {
			break
		}
	}
	if Debug {
		log.Debug("room: %d goroutine exit", r.id)
	}
}

// PushMsg push msg to the room.
func (r *Room) PushMsg(ver int16, operation int32, msg []byte) (err error) {
	var proto *Proto
	r.rLock.Lock()
	if proto, err = r.proto.Set(); err == nil {
		proto.Ver = ver
		proto.Operation = operation
		proto.Body = msg
		r.proto.SetAdv()
	}
	r.rLock.Unlock()
	select {
	case r.signal <- protoReady:
	default:
	}
	return
}

// Online get online number.
func (r *Room) Online() (o int) {
	r.rLock.RLock()
	o = len(r.chs)
	r.rLock.RUnlock()
	return
}

// Close close the room.
func (r *Room) Close() {
	var ch *Channel
	// if chan full, wait
	r.signal <- protoFinish
	r.rLock.RLock()
	for ch, _ = range r.chs {
		ch.Close()
	}
	r.rLock.RUnlock()
}
<commit_msg>timer GC<commit_after>package main

import (
	log "code.google.com/p/log4go"
	"sync"
	"time"
)

type RoomOptions struct {
	ChannelSize int
	ProtoSize   int
	BatchNum    int
	SignalTime  time.Duration
}

type Room struct {
	id      int32
	rLock   sync.RWMutex
	proto   Ring
	signal  chan int
	chs     map[*Channel]struct{} // map room id with channels
	timer   *time.Timer
	sigTime time.Duration
	options RoomOptions
}

// NewRoom new a room struct, store channel room info.
func NewRoom(id int32, options RoomOptions) (r *Room) {
	r = new(Room)
	r.id = id
	r.options = options
	r.proto.Init(options.ProtoSize)
	r.signal = make(chan int, signalNum)
	r.chs = make(map[*Channel]struct{}, options.ChannelSize)
	r.timer = time.NewTimer(options.SignalTime)
	go r.push()
	return
}

// Put put channel into the room.
func (r *Room) Put(ch *Channel) {
	r.rLock.Lock()
	r.chs[ch] = struct{}{}
	r.rLock.Unlock()
	return
}

// Del delete channel from the room.
func (r *Room) Del(ch *Channel) {
	r.rLock.Lock()
	delete(r.chs, ch)
	r.rLock.Unlock()
}

// push merge proto and push msgs in batch.
func (r *Room) push() {
	var (
		s, n       int
		exit, done bool
		err        error
		p          *Proto
		ch         *Channel
		least      time.Duration
		last       = time.Now()
		vers       = make([]int32, r.options.BatchNum)
		operations = make([]int32, r.options.BatchNum)
		msgs       = make([][]byte, r.options.BatchNum)
	)
	if Debug {
		log.Debug("start room: %d goroutine", r.id)
	}
	for {
		if least = r.options.SignalTime - time.Now().Sub(last); least > 0 {
			r.timer.Reset(least)
			select {
			case s = <-r.signal:
				if exit = (s != protoReady); exit {
					done = true
					break
				}
				// merge msgs
				if n == 0 {
					last = time.Now()
				}
				for {
					if n >= r.options.BatchNum {
						// msgs full
						done = true
						break
					}
					if p, err = r.proto.Get(); err != nil {
						// must be empty error
						break
					}
					vers[n] = int32(p.Ver)
					operations[n] = p.Operation
					msgs[n] = p.Body
					n++
					r.proto.GetAdv()
				}
			case <-r.timer.C:
				done = true
				exit = false
			}
		} else {
			done = true
		}
		if done {
			if n > 0 {
				r.rLock.RLock()
				for ch, _ = range r.chs {
					// ignore error
					ch.PushMsgs(vers[:n], operations[:n], msgs[:n])
				}
				r.rLock.RUnlock()
				n = 0
			}
			done = false
			last = time.Now()
		}
		if exit {
			break
		}
	}
	r.timer.Stop()
	if Debug {
		log.Debug("room: %d goroutine exit", r.id)
	}
}

// PushMsg push msg to the room.
func (r *Room) PushMsg(ver int16, operation int32, msg []byte) (err error) {
	var proto *Proto
	r.rLock.Lock()
	if proto, err = r.proto.Set(); err == nil {
		proto.Ver = ver
		proto.Operation = operation
		proto.Body = msg
		r.proto.SetAdv()
	}
	r.rLock.Unlock()
	select {
	case r.signal <- protoReady:
	default:
	}
	return
}

// Online get online number.
func (r *Room) Online() (o int) {
	r.rLock.RLock()
	o = len(r.chs)
	r.rLock.RUnlock()
	return
}

// Close close the room.
func (r *Room) Close() {
	var ch *Channel
	// if chan full, wait
	r.signal <- protoFinish
	r.rLock.RLock()
	for ch, _ = range r.chs {
		ch.Close()
	}
	r.rLock.RUnlock()
}
<|endoftext|>


<commit_before>// Copyright 2016 Google Inc. All Rights Reserved.
// This file is available under the Apache license.

package vm

import (
	"fmt"
	"regexp/syntax"
)

// checker holds data for a semantic checker
type checker struct {
	errors ErrorList

	// symtab contains the current scope search path
	symtab SymbolTable
}

// Check performs a semantic check of the ast node, and returns a boolean
// indicating OK; if ok is not true, then error is a list of errors found.
func Check(node node) error {
	c := &checker{}
	Walk(c, node)
	if len(c.errors) > 0 {
		return c.errors
	}
	return nil
}

func (c *checker) VisitBefore(node node) Visitor {
	switch n := node.(type) {

	case *stmtlistNode:
		c.symtab.EnterScope(nil)
		n.s = c.symtab.CurrentScope()

	case *caprefNode:
		if sym, ok := c.symtab.Lookup(n.name, CaprefSymbol); ok {
			n.sym = sym
		} else {
			c.errors.Add(n.Pos(), fmt.Sprintf("Capture group `$%s' was not defined by a regular expression in this or outer scopes.\n\tTry using `(?P<%s>...)' to name the capture group.", n.name, n.name))
			return nil
		}

	case *declNode:
		if sym, ok := c.symtab.Lookup(n.name, IDSymbol); ok {
			c.errors.Add(n.Pos(), fmt.Sprintf("Declaration of `%s' shadows the previous at %s", n.name, sym.loc))
			return nil
		}
		n.sym = c.symtab.Add(n.name, IDSymbol, &n.pos)

	case *defNode:
		n.sym = c.symtab.Add(n.name, DefSymbol, &n.pos)
		(*n.sym).binding = n

	case *decoNode:
		if sym, ok := c.symtab.Lookup(n.name, DefSymbol); ok {
			if sym.binding == nil {
				c.errors.Add(n.Pos(), fmt.Sprintf("Internal error: Decorator %q not bound to its definition.", n.name))
				return nil
			}
			n.def = sym.binding.(*defNode)
		} else {
			c.errors.Add(n.Pos(), fmt.Sprintf("Decorator `%s' not defined.\n\tTry adding a definition `def %s {}' earlier in the program.", n.name, n.name))
			return nil
		}

	case *idNode:
		if sym, ok := c.symtab.Lookup(n.name, IDSymbol); ok {
			n.sym = sym
		} else {
			c.errors.Add(n.Pos(), fmt.Sprintf("Identifier `%s' not declared.\n\tTry adding `counter %s' to the top of the program.", n.name, n.name))
			return nil
		}

	case *regexNode:
		if re, err := syntax.Parse(n.pattern, syntax.Perl); err != nil {
			c.errors.Add(n.Pos(), fmt.Sprintf(err.Error()))
			return nil
		} else {
			n.re_ast = re
			// We can reserve storage for these capturing groups, storing them in
			// the current scope, so that future CAPTUREGROUPs can retrieve their
			// value.  At parse time, we can warn about nonexistent names.
			for i := 1; i <= re.MaxCap(); i++ {
				sym := c.symtab.Add(fmt.Sprintf("%d", i),
					CaprefSymbol, n.Pos())
				sym.binding = n
				sym.addr = i - 1
			}
			for i, capref := range re.CapNames() {
				if capref != "" {
					sym := c.symtab.Add(capref, CaprefSymbol, n.Pos())
					sym.binding = n
					sym.addr = i
				}
			}
		}
	}
	return c
}

func (c *checker) VisitAfter(node node) {
	switch n := node.(type) {
	case *stmtlistNode:
		c.symtab.ExitScope()

	case *binaryExprNode:
		var rType Type
		Tl := n.lhs.Type()
		Tr := n.rhs.Type()
		switch n.op {
		// case DIV, MOD, MUL, MINUS, PLUS, POW:
		// 	// Numeric
		// case SHL, SHR:
		// 	//  integer
		// case LT, GT, LE, GE, EQ, NE:
		// 	// comparable
		// case AND, OR, XOR, NOT:
		// case ADD_ASSIGN, ASSIGN:
		default:
			if Tl != Tr {
				c.errors.Add(n.Pos(), fmt.Sprintf("Type mismatch between lhs (%s) and rhs (%s) for op %s", Tl, Tr, n.op))
			}
			rType = Tl
		}
		n.typ = rType

	case *unaryExprNode:
		n.typ = n.expr.Type()
	}
}
<commit_msg>Adds comments describing the type rules for binary expressions.<commit_after>// Copyright 2016 Google Inc. All Rights Reserved.
// This file is available under the Apache license.

package vm

import (
	"fmt"
	"regexp/syntax"
)

// checker holds data for a semantic checker
type checker struct {
	errors ErrorList

	// symtab contains the current scope search path
	symtab SymbolTable
}

// Check performs a semantic check of the ast node, and returns a boolean
// indicating OK; if ok is not true, then error is a list of errors found.
func Check(node node) error {
	c := &checker{}
	Walk(c, node)
	if len(c.errors) > 0 {
		return c.errors
	}
	return nil
}

func (c *checker) VisitBefore(node node) Visitor {
	switch n := node.(type) {

	case *stmtlistNode:
		c.symtab.EnterScope(nil)
		n.s = c.symtab.CurrentScope()

	case *caprefNode:
		if sym, ok := c.symtab.Lookup(n.name, CaprefSymbol); ok {
			n.sym = sym
		} else {
			c.errors.Add(n.Pos(), fmt.Sprintf("Capture group `$%s' was not defined by a regular expression in this or outer scopes.\n\tTry using `(?P<%s>...)' to name the capture group.", n.name, n.name))
			return nil
		}

	case *declNode:
		if sym, ok := c.symtab.Lookup(n.name, IDSymbol); ok {
			c.errors.Add(n.Pos(), fmt.Sprintf("Declaration of `%s' shadows the previous at %s", n.name, sym.loc))
			return nil
		}
		n.sym = c.symtab.Add(n.name, IDSymbol, &n.pos)

	case *defNode:
		n.sym = c.symtab.Add(n.name, DefSymbol, &n.pos)
		(*n.sym).binding = n

	case *decoNode:
		if sym, ok := c.symtab.Lookup(n.name, DefSymbol); ok {
			if sym.binding == nil {
				c.errors.Add(n.Pos(), fmt.Sprintf("Internal error: Decorator %q not bound to its definition.", n.name))
				return nil
			}
			n.def = sym.binding.(*defNode)
		} else {
			c.errors.Add(n.Pos(), fmt.Sprintf("Decorator `%s' not defined.\n\tTry adding a definition `def %s {}' earlier in the program.", n.name, n.name))
			return nil
		}

	case *idNode:
		if sym, ok := c.symtab.Lookup(n.name, IDSymbol); ok {
			n.sym = sym
		} else {
			c.errors.Add(n.Pos(), fmt.Sprintf("Identifier `%s' not declared.\n\tTry adding `counter %s' to the top of the program.", n.name, n.name))
			return nil
		}

	case *regexNode:
		if re, err := syntax.Parse(n.pattern, syntax.Perl); err != nil {
			c.errors.Add(n.Pos(), fmt.Sprintf(err.Error()))
			return nil
		} else {
			n.re_ast = re
			// We can reserve storage for these capturing groups, storing them in
			// the current scope, so that future CAPTUREGROUPs can retrieve their
			// value.  At parse time, we can warn about nonexistent names.
			for i := 1; i <= re.MaxCap(); i++ {
				sym := c.symtab.Add(fmt.Sprintf("%d", i),
					CaprefSymbol, n.Pos())
				sym.binding = n
				sym.addr = i - 1
			}
			for i, capref := range re.CapNames() {
				if capref != "" {
					sym := c.symtab.Add(capref, CaprefSymbol, n.Pos())
					sym.binding = n
					sym.addr = i
				}
			}
		}
	}
	return c
}

func (c *checker) VisitAfter(node node) {
	switch n := node.(type) {
	case *stmtlistNode:
		c.symtab.ExitScope()

	case *binaryExprNode:
		var rType Type
		Tl := n.lhs.Type()
		Tr := n.rhs.Type()
		switch n.op {
		//case DIV, MOD, MUL, MINUS, PLUS, POW:
		// Numeric
		// O ⊢ e1 : Tl, O ⊢ e2 : Tr
		// Tl <= Tr , Tr <= Tl
		// ⇒ O ⊢ e : lub(Tl, Tr)
		// case SHL, SHR, AND, OR, XOR, NOT:
		// 	//  integer
		// O ⊢ e1 :Int, O ⊢ e2 : Int
		// ⇒ O ⊢ e : Int
		// case LT, GT, LE, GE, EQ, NE:
		// 	// comparable
		// O ⊢ e1 : Tl, O ⊢ e2 : Tr
		// Tl <= Tr , Tr <= Tl
		// ⇒ O ⊢ e : lub(Tl, Tr)
		// case ADD_ASSIGN, ASSIGN:
		// O ⊢ e1 : Tl, O ⊢ e2 : Tr
		// Tl <= Tr
		// ⇒ O ⊢ e : Tl
		default:
			if Tl != Tr {
				c.errors.Add(n.Pos(), fmt.Sprintf("Type mismatch between lhs (%s) and rhs (%s) for op %s", Tl, Tr, n.op))
			}
			rType = Tl
		}
		n.typ = rType

	case *unaryExprNode:
		n.typ = n.expr.Type()
	}
}
<|endoftext|>


<commit_before>// Copyright 2011 Google Inc. All Rights Reserved.
// This file is available under the Apache license.

package vm

import (
	"regexp"
	"testing"
	"time"

	"github.com/google/mtail/metrics"
	"github.com/kylelemons/godebug/pretty"
)

var instructions = []struct {
	name          string
	i             instr
	re            []*regexp.Regexp
	str           []string
	reversedStack []interface{} // stack is inverted to be pushed onto vm stack

	expectedStack  []interface{}
	expectedThread thread
}{
	// Composite literals require too many explicit conversions.
	{"inc",
		instr{inc, nil},
		[]*regexp.Regexp{},
		[]string{},
		[]interface{}{0},
		[]interface{}{},
		thread{pc: 0, matches: map[int][]string{}},
	},
	{"inc by int",
		instr{inc, 2},
		[]*regexp.Regexp{},
		[]string{},
		[]interface{}{0, 1}, // first is metric 0 "foo", second is the inc val.
		[]interface{}{},
		thread{pc: 0, matches: map[int][]string{}},
	},
	{"inc by string",
		instr{inc, 2},
		[]*regexp.Regexp{},
		[]string{},
		[]interface{}{0, "1"}, // first is metric 0 "foo", second is the inc val.
		[]interface{}{},
		thread{pc: 0, matches: map[int][]string{}},
	},
	{"set int",
		instr{set, 2},
		[]*regexp.Regexp{},
		[]string{},
		[]interface{}{1, 2}, // set metric 1 "bar"
		[]interface{}{},
		thread{pc: 0, matches: map[int][]string{}},
	},
	{"set str",
		instr{set, 2},
		[]*regexp.Regexp{},
		[]string{},
		[]interface{}{1, "2"},
		[]interface{}{},
		thread{pc: 0, matches: map[int][]string{}},
	},
	{"match",
		instr{match, 0},
		[]*regexp.Regexp{regexp.MustCompile("a*b")},
		[]string{},
		[]interface{}{},
		[]interface{}{},
		thread{match: true, pc: 0, matches: map[int][]string{0: {"aaaab"}}},
	},
	{"cmp lt",
		instr{cmp, -1},
		[]*regexp.Regexp{},
		[]string{},
		[]interface{}{1, "2"},
		[]interface{}{},
		thread{pc: 0, match: true, matches: map[int][]string{}}},
	{"cmp eq",
		instr{cmp, 0},
		[]*regexp.Regexp{},
		[]string{},
		[]interface{}{"2", "2"},
		[]interface{}{},
		thread{pc: 0, match: true, matches: map[int][]string{}}},
	{"cmp gt",
		instr{cmp, 1},
		[]*regexp.Regexp{},
		[]string{},
		[]interface{}{2, 1},
		[]interface{}{},
		thread{pc: 0, match: true, matches: map[int][]string{}}},
	{"cmp le",
		instr{cmp, 1},
		[]*regexp.Regexp{},
		[]string{},
		[]interface{}{2, "2"},
		[]interface{}{},
		thread{pc: 0, match: false, matches: map[int][]string{}}},
	{"cmp ne",
		instr{cmp, 0},
		[]*regexp.Regexp{},
		[]string{},
		[]interface{}{"1", "2"},
		[]interface{}{},
		thread{pc: 0, match: false, matches: map[int][]string{}}},
	{"cmp ge",
		instr{cmp, -1},
		[]*regexp.Regexp{},
		[]string{},
		[]interface{}{2, 2},
		[]interface{}{},
		thread{pc: 0, match: false, matches: map[int][]string{}}},
	{"jnm",
		instr{jnm, 37},
		[]*regexp.Regexp{},
		[]string{},
		[]interface{}{},
		[]interface{}{},
		thread{pc: 37, matches: map[int][]string{}}},
	{"jm",
		instr{jm, 37},
		[]*regexp.Regexp{},
		[]string{},
		[]interface{}{},
		[]interface{}{},
		thread{pc: 0, matches: map[int][]string{}}},
	{"jmp",
		instr{jmp, 37},
		[]*regexp.Regexp{},
		[]string{},
		[]interface{}{},
		[]interface{}{},
		thread{pc: 37, matches: map[int][]string{}}},
	{"strptime",
		instr{strptime, 0},
		[]*regexp.Regexp{},
		[]string{},
		[]interface{}{"2012/01/18 06:25:00", "2006/01/02 15:04:05"},
		[]interface{}{},
		thread{pc: 0, time: time.Date(2012, 1, 18, 6, 25, 0, 0, time.UTC),
			matches: map[int][]string{}}},
	{"add",
		instr{add, 0},
		[]*regexp.Regexp{},
		[]string{},
		[]interface{}{2, 1},
		[]interface{}{int64(3)},
		thread{pc: 0, matches: map[int][]string{}}},
	{"sub",
		instr{sub, 0},
		[]*regexp.Regexp{},
		[]string{},
		[]interface{}{2, 1},
		[]interface{}{int64(1)},
		thread{pc: 0, matches: map[int][]string{}}},
	{"mul",
		instr{sub, 0},
		[]*regexp.Regexp{},
		[]string{},
		[]interface{}{2, 1},
		[]interface{}{int64(1)},
		thread{pc: 0, matches: map[int][]string{}}},
	{"div",
		instr{sub, 0},
		[]*regexp.Regexp{},
		[]string{},
		[]interface{}{4, 2},
		[]interface{}{int64(2)},
		thread{pc: 0, matches: map[int][]string{}}},
	{"mod",
		instr{mod, 0},
		[]*regexp.Regexp{},
		[]string{},
		[]interface{}{4, 2},
		[]interface{}{int64(0)},
		thread{pc: 0, matches: map[int][]string{}}},
	{"mod",
		instr{mod, 0},
		[]*regexp.Regexp{},
		[]string{},
		[]interface{}{3, 2},
		[]interface{}{int64(1)},
		thread{pc: 0, matches: map[int][]string{}}},
	{"tolower",
		instr{tolower, 0},
		[]*regexp.Regexp{},
		[]string{},
		[]interface{}{"mIxeDCasE"},
		[]interface{}{"mixedcase"},
		thread{pc: 0, matches: map[int][]string{}}},
	{"length",
		instr{length, 0},
		[]*regexp.Regexp{},
		[]string{},
		[]interface{}{"1234"},
		[]interface{}{4},
		thread{pc: 0, matches: map[int][]string{}}},
	{"length 0",
		instr{length, 0},
		[]*regexp.Regexp{},
		[]string{},
		[]interface{}{""},
		[]interface{}{0},
		thread{pc: 0, matches: map[int][]string{}}},
	{"shl",
		instr{shl, 0},
		[]*regexp.Regexp{},
		[]string{},
		[]interface{}{2, 1},
		[]interface{}{int64(4)},
		thread{pc: 0, matches: map[int][]string{}}},
	{"shr",
		instr{shr, 0},
		[]*regexp.Regexp{},
		[]string{},
		[]interface{}{2, 1},
		[]interface{}{int64(1)},
		thread{pc: 0, matches: map[int][]string{}}},
	{"and",
		instr{and, 0},
		[]*regexp.Regexp{},
		[]string{},
		[]interface{}{2, 1},
		[]interface{}{int64(0)},
		thread{pc: 0, matches: map[int][]string{}}},
	{"or",
		instr{or, 0},
		[]*regexp.Regexp{},
		[]string{},
		[]interface{}{2, 1},
		[]interface{}{int64(3)},
		thread{pc: 0, matches: map[int][]string{}}},
	{"xor",
		instr{xor, 0},
		[]*regexp.Regexp{},
		[]string{},
		[]interface{}{2, 1},
		[]interface{}{int64(3)},
		thread{pc: 0, matches: map[int][]string{}}},
	{"xor 2",
		instr{xor, 0},
		[]*regexp.Regexp{},
		[]string{},
		[]interface{}{2, 3},
		[]interface{}{int64(1)},
		thread{pc: 0, matches: map[int][]string{}}},
	{"xor 3",
		instr{xor, 0},
		[]*regexp.Regexp{},
		[]string{},
		[]interface{}{-1, 3},
		[]interface{}{int64(^3)},
		thread{pc: 0, matches: map[int][]string{}}},
	{"not",
		instr{not, 0},
		[]*regexp.Regexp{},
		[]string{},
		[]interface{}{0},
		[]interface{}{int64(-1)},
		thread{pc: 0, matches: map[int][]string{}}},
	{"pow",
		instr{pow, 0},
		[]*regexp.Regexp{},
		[]string{},
		[]interface{}{2, 2},
		[]interface{}{int64(4)},
		thread{pc: 0, matches: map[int][]string{}}},
	{"strtol",
		instr{strtol, 2},
		[]*regexp.Regexp{},
		[]string{},
		[]interface{}{"ff", 16},
		[]interface{}{int64(255)},
		thread{pc: 0, matches: map[int][]string{}}},
	{"settime",
		instr{settime, 0},
		[]*regexp.Regexp{},
		[]string{},
		[]interface{}{int64(0)},
		[]interface{}{},
		thread{pc: 0, time: time.Unix(0, 0).UTC(), matches: map[int][]string{}}},
	{"push int",
		instr{push, 1},
		[]*regexp.Regexp{},
		[]string{},
		[]interface{}{},
		[]interface{}{1},
		thread{pc: 0, matches: map[int][]string{}}},
	{"push float",
		instr{push, 1.0},
		[]*regexp.Regexp{},
		[]string{},
		[]interface{}{},
		[]interface{}{1.0},
		thread{pc: 0, matches: map[int][]string{}}},
	{"setmatched false",
		instr{setmatched, false},
		[]*regexp.Regexp{},
		[]string{},
		[]interface{}{},
		[]interface{}{},
		thread{matched: false, pc: 0, matches: map[int][]string{}}},
	{"setmatched true",
		instr{setmatched, true},
		[]*regexp.Regexp{},
		[]string{},
		[]interface{}{},
		[]interface{}{},
		thread{matched: true, pc: 0, matches: map[int][]string{}}},
	{"otherwise",
		instr{otherwise, nil},
		[]*regexp.Regexp{},
		[]string{},
		[]interface{}{},
		[]interface{}{},
		thread{match: true, pc: 0, matches: map[int][]string{}}},
}

// TestInstrs tests that each instruction behaves as expected through one
// instruction cycle.
func TestInstrs(t *testing.T) {
	for _, tc := range instructions {
		var m []*metrics.Metric
		m = append(m,
			metrics.NewMetric("foo", "test", metrics.Counter),
			metrics.NewMetric("bar", "test", metrics.Counter))

		v := New(tc.name, tc.re, tc.str, m, []instr{tc.i}, true)
		v.t = new(thread)
		v.t.stack = make([]interface{}, 0)
		for _, item := range tc.reversedStack {
			v.t.Push(item)
		}
		v.t.matches = make(map[int][]string, 0)
		v.input = "aaaab"
		v.execute(v.t, tc.i)
		if v.terminate {
			t.Fatalf("Execution failed, see info log.")
		}

		diff := pretty.Compare(tc.expectedStack, v.t.stack)
		if len(diff) > 0 {
			t.Errorf("%s: unexpected virtual machine stack state.\n%s", tc.name, diff)
		}
		// patch in the thread stack because otherwise the test table is huge
		tc.expectedThread.stack = tc.expectedStack

		if diff = pretty.Compare(v.t, &tc.expectedThread); len(diff) > 0 {
			t.Errorf("%s: unexpected virtual machine thread state.\n%s", tc.name, diff)
		}
	}
}
<commit_msg>Fix typos in the vm_test that were testing the wrong instructions.<commit_after>// Copyright 2011 Google Inc. All Rights Reserved.
// This file is available under the Apache license.

package vm

import (
	"regexp"
	"testing"
	"time"

	"github.com/google/mtail/metrics"
	"github.com/kylelemons/godebug/pretty"
)

var instructions = []struct {
	name          string
	i             instr
	re            []*regexp.Regexp
	str           []string
	reversedStack []interface{} // stack is inverted to be pushed onto vm stack

	expectedStack  []interface{}
	expectedThread thread
}{
	// Composite literals require too many explicit conversions.
	{"inc",
		instr{inc, nil},
		[]*regexp.Regexp{},
		[]string{},
		[]interface{}{0},
		[]interface{}{},
		thread{pc: 0, matches: map[int][]string{}},
	},
	{"inc by int",
		instr{inc, 2},
		[]*regexp.Regexp{},
		[]string{},
		[]interface{}{0, 1}, // first is metric 0 "foo", second is the inc val.
		[]interface{}{},
		thread{pc: 0, matches: map[int][]string{}},
	},
	{"inc by string",
		instr{inc, 2},
		[]*regexp.Regexp{},
		[]string{},
		[]interface{}{0, "1"}, // first is metric 0 "foo", second is the inc val.
		[]interface{}{},
		thread{pc: 0, matches: map[int][]string{}},
	},
	{"set int",
		instr{set, 2},
		[]*regexp.Regexp{},
		[]string{},
		[]interface{}{1, 2}, // set metric 1 "bar"
		[]interface{}{},
		thread{pc: 0, matches: map[int][]string{}},
	},
	{"set str",
		instr{set, 2},
		[]*regexp.Regexp{},
		[]string{},
		[]interface{}{1, "2"},
		[]interface{}{},
		thread{pc: 0, matches: map[int][]string{}},
	},
	{"match",
		instr{match, 0},
		[]*regexp.Regexp{regexp.MustCompile("a*b")},
		[]string{},
		[]interface{}{},
		[]interface{}{},
		thread{match: true, pc: 0, matches: map[int][]string{0: {"aaaab"}}},
	},
	{"cmp lt",
		instr{cmp, -1},
		[]*regexp.Regexp{},
		[]string{},
		[]interface{}{1, "2"},
		[]interface{}{},
		thread{pc: 0, match: true, matches: map[int][]string{}}},
	{"cmp eq",
		instr{cmp, 0},
		[]*regexp.Regexp{},
		[]string{},
		[]interface{}{"2", "2"},
		[]interface{}{},
		thread{pc: 0, match: true, matches: map[int][]string{}}},
	{"cmp gt",
		instr{cmp, 1},
		[]*regexp.Regexp{},
		[]string{},
		[]interface{}{2, 1},
		[]interface{}{},
		thread{pc: 0, match: true, matches: map[int][]string{}}},
	{"cmp le",
		instr{cmp, 1},
		[]*regexp.Regexp{},
		[]string{},
		[]interface{}{2, "2"},
		[]interface{}{},
		thread{pc: 0, match: false, matches: map[int][]string{}}},
	{"cmp ne",
		instr{cmp, 0},
		[]*regexp.Regexp{},
		[]string{},
		[]interface{}{"1", "2"},
		[]interface{}{},
		thread{pc: 0, match: false, matches: map[int][]string{}}},
	{"cmp ge",
		instr{cmp, -1},
		[]*regexp.Regexp{},
		[]string{},
		[]interface{}{2, 2},
		[]interface{}{},
		thread{pc: 0, match: false, matches: map[int][]string{}}},
	{"jnm",
		instr{jnm, 37},
		[]*regexp.Regexp{},
		[]string{},
		[]interface{}{},
		[]interface{}{},
		thread{pc: 37, matches: map[int][]string{}}},
	{"jm",
		instr{jm, 37},
		[]*regexp.Regexp{},
		[]string{},
		[]interface{}{},
		[]interface{}{},
		thread{pc: 0, matches: map[int][]string{}}},
	{"jmp",
		instr{jmp, 37},
		[]*regexp.Regexp{},
		[]string{},
		[]interface{}{},
		[]interface{}{},
		thread{pc: 37, matches: map[int][]string{}}},
	{"strptime",
		instr{strptime, 0},
		[]*regexp.Regexp{},
		[]string{},
		[]interface{}{"2012/01/18 06:25:00", "2006/01/02 15:04:05"},
		[]interface{}{},
		thread{pc: 0, time: time.Date(2012, 1, 18, 6, 25, 0, 0, time.UTC),
			matches: map[int][]string{}}},
	{"add",
		instr{add, 0},
		[]*regexp.Regexp{},
		[]string{},
		[]interface{}{2, 1},
		[]interface{}{int64(3)},
		thread{pc: 0, matches: map[int][]string{}}},
	{"sub",
		instr{sub, 0},
		[]*regexp.Regexp{},
		[]string{},
		[]interface{}{2, 1},
		[]interface{}{int64(1)},
		thread{pc: 0, matches: map[int][]string{}}},
	{"mul",
		instr{mul, 0},
		[]*regexp.Regexp{},
		[]string{},
		[]interface{}{2, 1},
		[]interface{}{int64(2)},
		thread{pc: 0, matches: map[int][]string{}}},
	{"div",
		instr{div, 0},
		[]*regexp.Regexp{},
		[]string{},
		[]interface{}{4, 2},
		[]interface{}{int64(2)},
		thread{pc: 0, matches: map[int][]string{}}},
	{"mod",
		instr{mod, 0},
		[]*regexp.Regexp{},
		[]string{},
		[]interface{}{4, 2},
		[]interface{}{int64(0)},
		thread{pc: 0, matches: map[int][]string{}}},
	{"mod",
		instr{mod, 0},
		[]*regexp.Regexp{},
		[]string{},
		[]interface{}{3, 2},
		[]interface{}{int64(1)},
		thread{pc: 0, matches: map[int][]string{}}},
	{"tolower",
		instr{tolower, 0},
		[]*regexp.Regexp{},
		[]string{},
		[]interface{}{"mIxeDCasE"},
		[]interface{}{"mixedcase"},
		thread{pc: 0, matches: map[int][]string{}}},
	{"length",
		instr{length, 0},
		[]*regexp.Regexp{},
		[]string{},
		[]interface{}{"1234"},
		[]interface{}{4},
		thread{pc: 0, matches: map[int][]string{}}},
	{"length 0",
		instr{length, 0},
		[]*regexp.Regexp{},
		[]string{},
		[]interface{}{""},
		[]interface{}{0},
		thread{pc: 0, matches: map[int][]string{}}},
	{"shl",
		instr{shl, 0},
		[]*regexp.Regexp{},
		[]string{},
		[]interface{}{2, 1},
		[]interface{}{int64(4)},
		thread{pc: 0, matches: map[int][]string{}}},
	{"shr",
		instr{shr, 0},
		[]*regexp.Regexp{},
		[]string{},
		[]interface{}{2, 1},
		[]interface{}{int64(1)},
		thread{pc: 0, matches: map[int][]string{}}},
	{"and",
		instr{and, 0},
		[]*regexp.Regexp{},
		[]string{},
		[]interface{}{2, 1},
		[]interface{}{int64(0)},
		thread{pc: 0, matches: map[int][]string{}}},
	{"or",
		instr{or, 0},
		[]*regexp.Regexp{},
		[]string{},
		[]interface{}{2, 1},
		[]interface{}{int64(3)},
		thread{pc: 0, matches: map[int][]string{}}},
	{"xor",
		instr{xor, 0},
		[]*regexp.Regexp{},
		[]string{},
		[]interface{}{2, 1},
		[]interface{}{int64(3)},
		thread{pc: 0, matches: map[int][]string{}}},
	{"xor 2",
		instr{xor, 0},
		[]*regexp.Regexp{},
		[]string{},
		[]interface{}{2, 3},
		[]interface{}{int64(1)},
		thread{pc: 0, matches: map[int][]string{}}},
	{"xor 3",
		instr{xor, 0},
		[]*regexp.Regexp{},
		[]string{},
		[]interface{}{-1, 3},
		[]interface{}{int64(^3)},
		thread{pc: 0, matches: map[int][]string{}}},
	{"not",
		instr{not, 0},
		[]*regexp.Regexp{},
		[]string{},
		[]interface{}{0},
		[]interface{}{int64(-1)},
		thread{pc: 0, matches: map[int][]string{}}},
	{"pow",
		instr{pow, 0},
		[]*regexp.Regexp{},
		[]string{},
		[]interface{}{2, 2},
		[]interface{}{int64(4)},
		thread{pc: 0, matches: map[int][]string{}}},
	{"strtol",
		instr{strtol, 2},
		[]*regexp.Regexp{},
		[]string{},
		[]interface{}{"ff", 16},
		[]interface{}{int64(255)},
		thread{pc: 0, matches: map[int][]string{}}},
	{"settime",
		instr{settime, 0},
		[]*regexp.Regexp{},
		[]string{},
		[]interface{}{int64(0)},
		[]interface{}{},
		thread{pc: 0, time: time.Unix(0, 0).UTC(), matches: map[int][]string{}}},
	{"push int",
		instr{push, 1},
		[]*regexp.Regexp{},
		[]string{},
		[]interface{}{},
		[]interface{}{1},
		thread{pc: 0, matches: map[int][]string{}}},
	{"push float",
		instr{push, 1.0},
		[]*regexp.Regexp{},
		[]string{},
		[]interface{}{},
		[]interface{}{1.0},
		thread{pc: 0, matches: map[int][]string{}}},
	{"setmatched false",
		instr{setmatched, false},
		[]*regexp.Regexp{},
		[]string{},
		[]interface{}{},
		[]interface{}{},
		thread{matched: false, pc: 0, matches: map[int][]string{}}},
	{"setmatched true",
		instr{setmatched, true},
		[]*regexp.Regexp{},
		[]string{},
		[]interface{}{},
		[]interface{}{},
		thread{matched: true, pc: 0, matches: map[int][]string{}}},
	{"otherwise",
		instr{otherwise, nil},
		[]*regexp.Regexp{},
		[]string{},
		[]interface{}{},
		[]interface{}{},
		thread{match: true, pc: 0, matches: map[int][]string{}}},
}

// TestInstrs tests that each instruction behaves as expected through one
// instruction cycle.
func TestInstrs(t *testing.T) {
	for _, tc := range instructions {
		var m []*metrics.Metric
		m = append(m,
			metrics.NewMetric("foo", "test", metrics.Counter),
			metrics.NewMetric("bar", "test", metrics.Counter))

		v := New(tc.name, tc.re, tc.str, m, []instr{tc.i}, true)
		v.t = new(thread)
		v.t.stack = make([]interface{}, 0)
		for _, item := range tc.reversedStack {
			v.t.Push(item)
		}
		v.t.matches = make(map[int][]string, 0)
		v.input = "aaaab"
		v.execute(v.t, tc.i)
		if v.terminate {
			t.Fatalf("Execution failed, see info log.")
		}

		diff := pretty.Compare(tc.expectedStack, v.t.stack)
		if len(diff) > 0 {
			t.Errorf("%s: unexpected virtual machine stack state.\n%s", tc.name, diff)
		}
		// patch in the thread stack because otherwise the test table is huge
		tc.expectedThread.stack = tc.expectedStack

		if diff = pretty.Compare(v.t, &tc.expectedThread); len(diff) > 0 {
			t.Errorf("%s: unexpected virtual machine thread state.\n%s", tc.name, diff)
		}
	}
}
<|endoftext|>


<commit_before>// $G $D/$F.go && $L $F.$A && ./$A.out

// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Test close(c), receive of closed channel.
//
// TODO(rsc): Doesn't check behavior of close(c) when there
// are blocked senders/receivers.

package main

type Chan interface {
	Send(int)
	Nbsend(int) bool
	Recv() (int)
	Nbrecv() (int, bool)
	Recv2() (int, bool)
	Nbrecv2() (int, bool, bool)
	Close()
	Impl() string
}

// direct channel operations when possible
type XChan chan int

func (c XChan) Send(x int) {
	c <- x
}

func (c XChan) Nbsend(x int) bool {
	select {
	case c <- x:
		return true
	default:
		return false
	}
	panic("nbsend")
}

func (c XChan) Recv() int {
	return <-c
}

func (c XChan) Nbrecv() (int, bool) {
	select {
	case x := <-c:
		return x, true
	default:
		return 0, false
	}
	panic("nbrecv")
}

func (c XChan) Recv2() (int, bool) {
	x, ok := <-c
	return x, ok
}

func (c XChan) Nbrecv2() (int, bool, bool) {
	select {
	case x, ok := <-c:
		return x, ok, true
	default:
		return 0, false, false
	}
	panic("nbrecv2")
}

func (c XChan) Close() {
	close(c)
}

func (c XChan) Impl() string {
	return "(<- operator)"
}

// indirect operations via select
type SChan chan int

func (c SChan) Send(x int) {
	select {
	case c <- x:
	}
}

func (c SChan) Nbsend(x int) bool {
	select {
	default:
		return false
	case c <- x:
		return true
	}
	panic("nbsend")
}

func (c SChan) Recv() int {
	select {
	case x := <-c:
		return x
	}
	panic("recv")
}

func (c SChan) Nbrecv() (int, bool) {
	select {
	default:
		return 0, false
	case x := <-c:
		return x, true
	}
	panic("nbrecv")
}

func (c SChan) Recv2() (int, bool) {
	select {
	case x, ok := <-c:
		return x, ok
	}
	panic("recv")
}

func (c SChan) Nbrecv2() (int, bool, bool) {
	select {
	default:
		return 0, false, false
	case x, ok := <-c:
		return x, ok, true
	}
	panic("nbrecv")
}

func (c SChan) Close() {
	close(c)
}

func (c SChan) Impl() string {
	return "(select)"
}

// indirect operations via larger selects
var dummy = make(chan bool)

type SSChan chan int

func (c SSChan) Send(x int) {
	select {
	case c <- x:
	case <-dummy:
	}
}

func (c SSChan) Nbsend(x int) bool {
	select {
	default:
		return false
	case <-dummy:
	case c <- x:
		return true
	}
	panic("nbsend")
}

func (c SSChan) Recv() int {
	select {
	case <-dummy:
	case x := <-c:
		return x
	}
	panic("recv")
}

func (c SSChan) Nbrecv() (int, bool) {
	select {
	case <-dummy:
	default:
		return 0, false
	case x := <-c:
		return x, true
	}
	panic("nbrecv")
}

func (c SSChan) Recv2() (int, bool) {
	select {
	case <-dummy:
	case x, ok := <-c:
		return x, ok
	}
	panic("recv")
}

func (c SSChan) Nbrecv2() (int, bool, bool) {
	select {
	case <-dummy:
	default:
		return 0, false, false
	case x, ok := <-c:
		return x, ok, true
	}
	panic("nbrecv")
}

func (c SSChan) Close() {
	close(c)
}

func (c SSChan) Impl() string {
	return "(select)"
}

func shouldPanic(f func()) {
	defer func() {
		if recover() == nil {
			panic("did not panic")
		}
	}()
	f()
}

func test1(c Chan) {
	for i := 0; i < 3; i++ {
		// recv a close signal (a zero value)
		if x := c.Recv(); x != 0 {
			println("test1: recv on closed:", x, c.Impl())
		}
		if x, ok := c.Recv2(); x != 0 || ok {
			println("test1: recv2 on closed:", x, ok, c.Impl())
		}

		// should work with select: received a value without blocking, so selected == true.
		x, selected := c.Nbrecv()
		if x != 0 || !selected {
			println("test1: recv on closed nb:", x, selected, c.Impl())
		}
		x, ok, selected := c.Nbrecv2()
		if x != 0 || ok || !selected {
			println("test1: recv2 on closed nb:", x, ok, selected, c.Impl())
		}
	}

	// send should work with ,ok too: sent a value without blocking, so ok == true.
	shouldPanic(func() { c.Nbsend(1) })

	// the value should have been discarded.
	if x := c.Recv(); x != 0 {
		println("test1: recv on closed got non-zero after send on closed:", x, c.Impl())
	}

	// similarly Send.
	shouldPanic(func() { c.Send(2) })
	if x := c.Recv(); x != 0 {
		println("test1: recv on closed got non-zero after send on closed:", x, c.Impl())
	}
}

func testasync1(c Chan) {
	// should be able to get the last value via Recv
	if x := c.Recv(); x != 1 {
		println("testasync1: Recv did not get 1:", x, c.Impl())
	}

	test1(c)
}

func testasync2(c Chan) {
	// should be able to get the last value via Recv2
	if x, ok := c.Recv2(); x != 1 || !ok {
		println("testasync1: Recv did not get 1, true:", x, ok, c.Impl())
	}

	test1(c)
}

func testasync3(c Chan) {
	// should be able to get the last value via Nbrecv
	if x, selected := c.Nbrecv(); x != 1 || !selected {
		println("testasync2: Nbrecv did not get 1, true:", x, selected, c.Impl())
	}

	test1(c)
}

func testasync4(c Chan) {
	// should be able to get the last value via Nbrecv2
	if x, ok, selected := c.Nbrecv2(); x != 1 || !ok || !selected {
		println("testasync2: Nbrecv did not get 1, true, true:", x, ok, selected, c.Impl())
	}
	test1(c)
}

func closedsync() chan int {
	c := make(chan int)
	close(c)
	return c
}

func closedasync() chan int {
	c := make(chan int, 2)
	c <- 1
	close(c)
	return c
}

var mks = []func(chan int) Chan {
	func(c chan int) Chan { return XChan(c) },
	func(c chan int) Chan { return SChan(c) },
	func(c chan int) Chan { return SSChan(c) },
}

var testcloseds = []func(Chan) {
	testasync1,
	testasync2,
	testasync3,
	testasync4,
}

func main() {
	for _, mk := range mks {
		test1(mk(closedsync()))
	}

	for _, testclosed := range testcloseds {
		for _, mk := range mks {
			testclosed(mk(closedasync()))
		}
	}

	var ch chan int
	shouldPanic(func() {
		close(ch)
	})

	ch = make(chan int)
	close(ch)
	shouldPanic(func() {
		close(ch)
	})
}
<commit_msg>test: make closedchan.go exit with failure if something fails<commit_after>// $G $D/$F.go && $L $F.$A && ./$A.out

// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Test close(c), receive of closed channel.
//
// TODO(rsc): Doesn't check behavior of close(c) when there
// are blocked senders/receivers.

package main

import "os"

var failed bool

type Chan interface {
	Send(int)
	Nbsend(int) bool
	Recv() (int)
	Nbrecv() (int, bool)
	Recv2() (int, bool)
	Nbrecv2() (int, bool, bool)
	Close()
	Impl() string
}

// direct channel operations when possible
type XChan chan int

func (c XChan) Send(x int) {
	c <- x
}

func (c XChan) Nbsend(x int) bool {
	select {
	case c <- x:
		return true
	default:
		return false
	}
	panic("nbsend")
}

func (c XChan) Recv() int {
	return <-c
}

func (c XChan) Nbrecv() (int, bool) {
	select {
	case x := <-c:
		return x, true
	default:
		return 0, false
	}
	panic("nbrecv")
}

func (c XChan) Recv2() (int, bool) {
	x, ok := <-c
	return x, ok
}

func (c XChan) Nbrecv2() (int, bool, bool) {
	select {
	case x, ok := <-c:
		return x, ok, true
	default:
		return 0, false, false
	}
	panic("nbrecv2")
}

func (c XChan) Close() {
	close(c)
}

func (c XChan) Impl() string {
	return "(<- operator)"
}

// indirect operations via select
type SChan chan int

func (c SChan) Send(x int) {
	select {
	case c <- x:
	}
}

func (c SChan) Nbsend(x int) bool {
	select {
	default:
		return false
	case c <- x:
		return true
	}
	panic("nbsend")
}

func (c SChan) Recv() int {
	select {
	case x := <-c:
		return x
	}
	panic("recv")
}

func (c SChan) Nbrecv() (int, bool) {
	select {
	default:
		return 0, false
	case x := <-c:
		return x, true
	}
	panic("nbrecv")
}

func (c SChan) Recv2() (int, bool) {
	select {
	case x, ok := <-c:
		return x, ok
	}
	panic("recv")
}

func (c SChan) Nbrecv2() (int, bool, bool) {
	select {
	default:
		return 0, false, false
	case x, ok := <-c:
		return x, ok, true
	}
	panic("nbrecv")
}

func (c SChan) Close() {
	close(c)
}

func (c SChan) Impl() string {
	return "(select)"
}

// indirect operations via larger selects
var dummy = make(chan bool)

type SSChan chan int

func (c SSChan) Send(x int) {
	select {
	case c <- x:
	case <-dummy:
	}
}

func (c SSChan) Nbsend(x int) bool {
	select {
	default:
		return false
	case <-dummy:
	case c <- x:
		return true
	}
	panic("nbsend")
}

func (c SSChan) Recv() int {
	select {
	case <-dummy:
	case x := <-c:
		return x
	}
	panic("recv")
}

func (c SSChan) Nbrecv() (int, bool) {
	select {
	case <-dummy:
	default:
		return 0, false
	case x := <-c:
		return x, true
	}
	panic("nbrecv")
}

func (c SSChan) Recv2() (int, bool) {
	select {
	case <-dummy:
	case x, ok := <-c:
		return x, ok
	}
	panic("recv")
}

func (c SSChan) Nbrecv2() (int, bool, bool) {
	select {
	case <-dummy:
	default:
		return 0, false, false
	case x, ok := <-c:
		return x, ok, true
	}
	panic("nbrecv")
}

func (c SSChan) Close() {
	close(c)
}

func (c SSChan) Impl() string {
	return "(select)"
}

func shouldPanic(f func()) {
	defer func() {
		if recover() == nil {
			panic("did not panic")
		}
	}()
	f()
}

func test1(c Chan) {
	for i := 0; i < 3; i++ {
		// recv a close signal (a zero value)
		if x := c.Recv(); x != 0 {
			println("test1: recv on closed:", x, c.Impl())
			failed = true
		}
		if x, ok := c.Recv2(); x != 0 || ok {
			println("test1: recv2 on closed:", x, ok, c.Impl())
			failed = true
		}

		// should work with select: received a value without blocking, so selected == true.
		x, selected := c.Nbrecv()
		if x != 0 || !selected {
			println("test1: recv on closed nb:", x, selected, c.Impl())
			failed = true
		}
		x, ok, selected := c.Nbrecv2()
		if x != 0 || ok || !selected {
			println("test1: recv2 on closed nb:", x, ok, selected, c.Impl())
			failed = true
		}
	}

	// send should work with ,ok too: sent a value without blocking, so ok == true.
	shouldPanic(func() { c.Nbsend(1) })

	// the value should have been discarded.
	if x := c.Recv(); x != 0 {
		println("test1: recv on closed got non-zero after send on closed:", x, c.Impl())
		failed = true
	}

	// similarly Send.
	shouldPanic(func() { c.Send(2) })
	if x := c.Recv(); x != 0 {
		println("test1: recv on closed got non-zero after send on closed:", x, c.Impl())
		failed = true
	}
}

func testasync1(c Chan) {
	// should be able to get the last value via Recv
	if x := c.Recv(); x != 1 {
		println("testasync1: Recv did not get 1:", x, c.Impl())
		failed = true
	}

	test1(c)
}

func testasync2(c Chan) {
	// should be able to get the last value via Recv2
	if x, ok := c.Recv2(); x != 1 || !ok {
		println("testasync1: Recv did not get 1, true:", x, ok, c.Impl())
		failed = true
	}

	test1(c)
}

func testasync3(c Chan) {
	// should be able to get the last value via Nbrecv
	if x, selected := c.Nbrecv(); x != 1 || !selected {
		println("testasync2: Nbrecv did not get 1, true:", x, selected, c.Impl())
		failed = true
	}

	test1(c)
}

func testasync4(c Chan) {
	// should be able to get the last value via Nbrecv2
	if x, ok, selected := c.Nbrecv2(); x != 1 || !ok || !selected {
		println("testasync2: Nbrecv did not get 1, true, true:", x, ok, selected, c.Impl())
		failed = true
	}
	test1(c)
}

func closedsync() chan int {
	c := make(chan int)
	close(c)
	return c
}

func closedasync() chan int {
	c := make(chan int, 2)
	c <- 1
	close(c)
	return c
}

var mks = []func(chan int) Chan {
	func(c chan int) Chan { return XChan(c) },
	func(c chan int) Chan { return SChan(c) },
	func(c chan int) Chan { return SSChan(c) },
}

var testcloseds = []func(Chan) {
	testasync1,
	testasync2,
	testasync3,
	testasync4,
}

func main() {
	for _, mk := range mks {
		test1(mk(closedsync()))
	}

	for _, testclosed := range testcloseds {
		for _, mk := range mks {
			testclosed(mk(closedasync()))
		}
	}

	var ch chan int
	shouldPanic(func() {
		close(ch)
	})

	ch = make(chan int)
	close(ch)
	shouldPanic(func() {
		close(ch)
	})

	if failed {
		os.Exit(1)
	}
}
<|endoftext|>


<commit_before>// Copyright 2011 The Go Authors.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package build provides tools for building Go packages.
package build

import (
	"bytes"
	"exec"
	"fmt"
	"os"
	"path/filepath"
	"runtime"
	"strings"
)

// Build produces a build Script for the given package.
func Build(tree *Tree, pkg string, info *DirInfo) (*Script, os.Error) {
	s := &Script{}
	b := &build{
		script: s,
		path:   filepath.Join(tree.SrcDir(), pkg),
	}
	b.obj = b.abs("_obj") + "/"

	goarch := runtime.GOARCH
	if g := os.Getenv("GOARCH"); g != "" {
		goarch = g
	}
	var err os.Error
	b.arch, err = ArchChar(goarch)
	if err != nil {
		return nil, err
	}

	// .go files to be built with gc
	gofiles := b.abss(info.GoFiles...)
	s.addInput(gofiles...)

	var ofiles []string // object files to be linked or packed

	// make build directory
	b.mkdir(b.obj)
	s.addIntermediate(b.obj)

	// cgo
	if len(info.CgoFiles) > 0 {
		cgoFiles := b.abss(info.CgoFiles...)
		s.addInput(cgoFiles...)
		outInter, outGo, outObj := b.cgo(cgoFiles)
		gofiles = append(gofiles, outGo...)
		ofiles = append(ofiles, outObj...)
		s.addIntermediate(outInter...)
		s.addIntermediate(outGo...)
		s.addIntermediate(outObj...)
	}

	// compile
	if len(gofiles) > 0 {
		ofile := b.obj + "_go_." + b.arch
		b.gc(ofile, gofiles...)
		ofiles = append(ofiles, ofile)
		s.addIntermediate(ofile)
	}

	// assemble
	for _, sfile := range info.SFiles {
		ofile := b.obj + sfile[:len(sfile)-1] + b.arch
		sfile = b.abs(sfile)
		s.addInput(sfile)
		b.asm(ofile, sfile)
		ofiles = append(ofiles, ofile)
		s.addIntermediate(sfile, ofile)
	}

	if len(ofiles) == 0 {
		return nil, os.NewError("make: no object files to build")
	}

	// choose target file
	var targ string
	if info.IsCommand() {
		// use the last part of the import path as binary name
		_, bin := filepath.Split(pkg)
		targ = filepath.Join(tree.BinDir(), bin)
	} else {
		targ = filepath.Join(tree.PkgDir(), pkg+".a")
	}

	// make target directory
	targDir, _ := filepath.Split(targ)
	b.mkdir(targDir)

	// link binary or pack object
	if info.IsCommand() {
		b.ld(targ, ofiles...)
	} else {
		b.gopack(targ, ofiles...)
	}
	s.Output = append(s.Output, targ)

	return b.script, nil
}

// A Script describes the build process for a Go package.
// The Input, Intermediate, and Output fields are lists of absolute paths.
type Script struct {
	Cmd          []*Cmd
	Input        []string
	Intermediate []string
	Output       []string
}

func (s *Script) addInput(file ...string) {
	s.Input = append(s.Input, file...)
}

func (s *Script) addIntermediate(file ...string) {
	s.Intermediate = append(s.Intermediate, file...)
}

// Run runs the Script's Cmds in order.
func (s *Script) Run() os.Error {
	for _, c := range s.Cmd {
		if err := c.Run(); err != nil {
			return err
		}
	}
	return nil
}

// Stale returns true if the build's inputs are newer than its outputs.
func (s *Script) Stale() bool {
	var latest int64
	// get latest mtime of outputs
	for _, file := range s.Output {
		fi, err := os.Stat(file)
		if err != nil {
			// any error reading output files means stale
			return true
		}
		if m := fi.Mtime_ns; m > latest {
			latest = m
		}
	}
	for _, file := range s.Input {
		fi, err := os.Stat(file)
		if err != nil || fi.Mtime_ns > latest {
			// any error reading input files means stale
			// (attempt to rebuild to figure out why)
			return true
		}
	}
	return false
}

// Clean removes the Script's Intermediate files.
// It tries to remove every file and returns the first error it encounters.
func (s *Script) Clean() (err os.Error) {
	for i := len(s.Intermediate) - 1; i >= 0; i-- {
		if e := os.Remove(s.Intermediate[i]); err == nil {
			err = e
		}
	}
	return
}

// Clean removes the Script's Intermediate and Output files.
// It tries to remove every file and returns the first error it encounters.
func (s *Script) Nuke() (err os.Error) {
	for i := len(s.Output) - 1; i >= 0; i-- {
		if e := os.Remove(s.Output[i]); err == nil {
			err = e
		}
	}
	if e := s.Clean(); err == nil {
		err = e
	}
	return
}

// A Cmd describes an individual build command.
type Cmd struct {
	Args   []string // command-line
	Stdout string   // write standard output to this file, "" is passthrough
	Dir    string   // working directory
	Input  []string // file paths (dependencies)
	Output []string // file paths
}

func (c *Cmd) String() string {
	return strings.Join(c.Args, " ")
}

// Run executes the Cmd.
func (c *Cmd) Run() os.Error {
	out := new(bytes.Buffer)
	cmd := exec.Command(c.Args[0], c.Args[1:]...)
	cmd.Dir = c.Dir
	cmd.Stdout = out
	cmd.Stderr = out
	if c.Stdout != "" {
		f, err := os.Create(c.Stdout)
		if err != nil {
			return err
		}
		defer f.Close()
		cmd.Stdout = f
	}
	if err := cmd.Run(); err != nil {
		return fmt.Errorf("command %q: %v\n%v", c, err, out)
	}
	return nil
}

// ArchChar returns the architecture character for the given goarch.
// For example, ArchChar("amd64") returns "6".
func ArchChar(goarch string) (string, os.Error) {
	switch goarch {
	case "386":
		return "8", nil
	case "amd64":
		return "6", nil
	case "arm":
		return "5", nil
	}
	return "", os.NewError("unsupported GOARCH " + goarch)
}

type build struct {
	script *Script
	path   string
	obj    string
	arch   string
}

func (b *build) abs(file string) string {
	if filepath.IsAbs(file) {
		return file
	}
	return filepath.Join(b.path, file)
}

func (b *build) abss(file ...string) []string {
	s := make([]string, len(file))
	for i, f := range file {
		s[i] = b.abs(f)
	}
	return s
}

func (b *build) add(c Cmd) {
	b.script.Cmd = append(b.script.Cmd, &c)
}

func (b *build) mkdir(name string) {
	b.add(Cmd{
		Args:   []string{"mkdir", "-p", name},
		Output: []string{name},
	})
}

func (b *build) gc(ofile string, gofiles ...string) {
	gc := b.arch + "g"
	args := append([]string{gc, "-o", ofile}, gcImportArgs...)
	args = append(args, gofiles...)
	b.add(Cmd{
		Args:   args,
		Input:  gofiles,
		Output: []string{ofile},
	})
}

func (b *build) asm(ofile string, sfile string) {
	asm := b.arch + "a"
	b.add(Cmd{
		Args:   []string{asm, "-o", ofile, sfile},
		Input:  []string{sfile},
		Output: []string{ofile},
	})
}

func (b *build) ld(targ string, ofiles ...string) {
	ld := b.arch + "l"
	args := append([]string{ld, "-o", targ}, ldImportArgs...)
	args = append(args, ofiles...)
	b.add(Cmd{
		Args:   args,
		Input:  ofiles,
		Output: []string{targ},
	})
}

func (b *build) gopack(targ string, ofiles ...string) {
	b.add(Cmd{
		Args:   append([]string{"gopack", "grc", targ}, ofiles...),
		Input:  ofiles,
		Output: []string{targ},
	})
}

func (b *build) cc(ofile string, cfiles ...string) {
	cc := b.arch + "c"
	dir := fmt.Sprintf("%s_%s", runtime.GOOS, runtime.GOARCH)
	inc := filepath.Join(runtime.GOROOT(), "pkg", dir)
	args := []string{cc, "-FVw", "-I", inc, "-o", ofile}
	b.add(Cmd{
		Args:   append(args, cfiles...),
		Input:  cfiles,
		Output: []string{ofile},
	})
}

func (b *build) gccCompile(ofile, cfile string) {
	b.add(Cmd{
		Args:   b.gccArgs("-o", ofile, "-c", cfile),
		Input:  []string{cfile},
		Output: []string{ofile},
	})
}

func (b *build) gccLink(ofile string, ofiles ...string) {
	b.add(Cmd{
		Args:   append(b.gccArgs("-o", ofile), ofiles...),
		Input:  ofiles,
		Output: []string{ofile},
	})
}

func (b *build) gccArgs(args ...string) []string {
	// TODO(adg): HOST_CC
	m := "-m32"
	if b.arch == "6" {
		m = "-m64"
	}
	return append([]string{"gcc", m, "-I", b.path, "-g", "-fPIC", "-O2"}, args...)
}

func (b *build) cgo(cgofiles []string) (outInter, outGo, outObj []string) {
	// cgo
	// TODO(adg): CGOPKGPATH
	// TODO(adg): CGO_FLAGS
	gofiles := []string{b.obj + "_cgo_gotypes.go"}
	cfiles := []string{b.obj + "_cgo_main.c", b.obj + "_cgo_export.c"}
	for _, fn := range cgofiles {
		f := b.obj + strings.Replace(fn[:len(fn)-2], "/", "_", -1)
		gofiles = append(gofiles, f+"cgo1.go")
		cfiles = append(cfiles, f+"cgo2.c")
	}
	defunC := b.obj + "_cgo_defun.c"
	output := append([]string{defunC}, cfiles...)
	output = append(output, gofiles...)
	b.add(Cmd{
		Args:   append([]string{"cgo", "--"}, cgofiles...),
		Dir:    b.path,
		Input:  cgofiles,
		Output: output,
	})
	outGo = append(outGo, gofiles...)
	exportH := filepath.Join(b.path, "_cgo_export.h")
	outInter = append(outInter, exportH, defunC, b.obj+"_cgo_flags")
	outInter = append(outInter, cfiles...)

	// cc _cgo_defun.c
	defunObj := b.obj + "_cgo_defun." + b.arch
	b.cc(defunObj, defunC)
	outObj = append(outObj, defunObj)

	// gcc
	linkobj := make([]string, 0, len(cfiles))
	for _, cfile := range cfiles {
		ofile := cfile[:len(cfile)-1] + "o"
		b.gccCompile(ofile, cfile)
		linkobj = append(linkobj, ofile)
		if !strings.HasSuffix(ofile, "_cgo_main.o") {
			outObj = append(outObj, ofile)
		} else {
			outInter = append(outInter, ofile)
		}
	}
	dynObj := b.obj + "_cgo_.o"
	b.gccLink(dynObj, linkobj...)
	outInter = append(outInter, dynObj)

	// cgo -dynimport
	importC := b.obj + "_cgo_import.c"
	b.add(Cmd{
		Args:   []string{"cgo", "-dynimport", dynObj},
		Stdout: importC,
		Input:  []string{dynObj},
		Output: []string{importC},
	})
	outInter = append(outInter, importC)

	// cc _cgo_import.ARCH
	importObj := b.obj + "_cgo_import." + b.arch
	b.cc(importObj, importC)
	outObj = append(outObj, importObj)

	return
}
<commit_msg>go/build: fix build and clean ups<commit_after>// Copyright 2011 The Go Authors.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package build provides tools for building Go packages.
package build

import (
	"bytes"
	"exec"
	"fmt"
	"os"
	"path/filepath"
	"runtime"
	"strings"
)

// Build produces a build Script for the given package.
func Build(tree *Tree, pkg string, info *DirInfo) (*Script, os.Error) {
	s := &Script{}
	b := &build{
		script: s,
		path:   filepath.Join(tree.SrcDir(), pkg),
	}
	b.obj = b.abs("_obj") + "/"

	goarch := runtime.GOARCH
	if g := os.Getenv("GOARCH"); g != "" {
		goarch = g
	}
	var err os.Error
	b.arch, err = ArchChar(goarch)
	if err != nil {
		return nil, err
	}

	// .go files to be built with gc
	gofiles := b.abss(info.GoFiles...)
	s.addInput(gofiles...)

	var ofiles []string // object files to be linked or packed

	// make build directory
	b.mkdir(b.obj)
	s.addIntermediate(b.obj)

	// cgo
	if len(info.CgoFiles) > 0 {
		cgoFiles := b.abss(info.CgoFiles...)
		s.addInput(cgoFiles...)
		outGo, outObj := b.cgo(cgoFiles)
		gofiles = append(gofiles, outGo...)
		ofiles = append(ofiles, outObj...)
		s.addIntermediate(outGo...)
		s.addIntermediate(outObj...)
	}

	// compile
	if len(gofiles) > 0 {
		ofile := b.obj + "_go_." + b.arch
		b.gc(ofile, gofiles...)
		ofiles = append(ofiles, ofile)
		s.addIntermediate(ofile)
	}

	// assemble
	for _, sfile := range info.SFiles {
		ofile := b.obj + sfile[:len(sfile)-1] + b.arch
		sfile = b.abs(sfile)
		s.addInput(sfile)
		b.asm(ofile, sfile)
		ofiles = append(ofiles, ofile)
		s.addIntermediate(ofile)
	}

	if len(ofiles) == 0 {
		return nil, os.NewError("make: no object files to build")
	}

	// choose target file
	var targ string
	if info.IsCommand() {
		// use the last part of the import path as binary name
		_, bin := filepath.Split(pkg)
		targ = filepath.Join(tree.BinDir(), bin)
	} else {
		targ = filepath.Join(tree.PkgDir(), pkg+".a")
	}

	// make target directory
	targDir, _ := filepath.Split(targ)
	b.mkdir(targDir)

	// link binary or pack object
	if info.IsCommand() {
		b.ld(targ, ofiles...)
	} else {
		b.gopack(targ, ofiles...)
	}
	s.Output = append(s.Output, targ)

	return b.script, nil
}

// A Script describes the build process for a Go package.
// The Input, Intermediate, and Output fields are lists of absolute paths.
type Script struct {
	Cmd          []*Cmd
	Input        []string
	Intermediate []string
	Output       []string
}

func (s *Script) addInput(file ...string) {
	s.Input = append(s.Input, file...)
}

func (s *Script) addIntermediate(file ...string) {
	s.Intermediate = append(s.Intermediate, file...)
}

// Run runs the Script's Cmds in order.
func (s *Script) Run() os.Error {
	for _, c := range s.Cmd {
		if err := c.Run(); err != nil {
			return err
		}
	}
	return nil
}

// Stale returns true if the build's inputs are newer than its outputs.
func (s *Script) Stale() bool {
	var latest int64
	// get latest mtime of outputs
	for _, file := range s.Output {
		fi, err := os.Stat(file)
		if err != nil {
			// any error reading output files means stale
			return true
		}
		if m := fi.Mtime_ns; m > latest {
			latest = m
		}
	}
	for _, file := range s.Input {
		fi, err := os.Stat(file)
		if err != nil || fi.Mtime_ns > latest {
			// any error reading input files means stale
			// (attempt to rebuild to figure out why)
			return true
		}
	}
	return false
}

// Clean removes the Script's Intermediate files.
// It tries to remove every file and returns the first error it encounters.
func (s *Script) Clean() (err os.Error) {
	// Reverse order so that directories get removed after the files they contain.
	for i := len(s.Intermediate) - 1; i >= 0; i-- {
		if e := os.Remove(s.Intermediate[i]); err == nil {
			err = e
		}
	}
	return
}

// Clean removes the Script's Intermediate and Output files.
// It tries to remove every file and returns the first error it encounters.
func (s *Script) Nuke() (err os.Error) {
	// Reverse order so that directories get removed after the files they contain.
	for i := len(s.Output) - 1; i >= 0; i-- {
		if e := os.Remove(s.Output[i]); err == nil {
			err = e
		}
	}
	if e := s.Clean(); err == nil {
		err = e
	}
	return
}

// A Cmd describes an individual build command.
type Cmd struct {
	Args   []string // command-line
	Stdout string   // write standard output to this file, "" is passthrough
	Dir    string   // working directory
	Input  []string // file paths (dependencies)
	Output []string // file paths
}

func (c *Cmd) String() string {
	return strings.Join(c.Args, " ")
}

// Run executes the Cmd.
func (c *Cmd) Run() os.Error {
	out := new(bytes.Buffer)
	cmd := exec.Command(c.Args[0], c.Args[1:]...)
	cmd.Dir = c.Dir
	cmd.Stdout = out
	cmd.Stderr = out
	if c.Stdout != "" {
		f, err := os.Create(c.Stdout)
		if err != nil {
			return err
		}
		defer f.Close()
		cmd.Stdout = f
	}
	if err := cmd.Run(); err != nil {
		return fmt.Errorf("command %q: %v\n%v", c, err, out)
	}
	return nil
}

// ArchChar returns the architecture character for the given goarch.
// For example, ArchChar("amd64") returns "6".
func ArchChar(goarch string) (string, os.Error) {
	switch goarch {
	case "386":
		return "8", nil
	case "amd64":
		return "6", nil
	case "arm":
		return "5", nil
	}
	return "", os.NewError("unsupported GOARCH " + goarch)
}

type build struct {
	script *Script
	path   string
	obj    string
	arch   string
}

func (b *build) abs(file string) string {
	if filepath.IsAbs(file) {
		return file
	}
	return filepath.Join(b.path, file)
}

func (b *build) abss(file ...string) []string {
	s := make([]string, len(file))
	for i, f := range file {
		s[i] = b.abs(f)
	}
	return s
}

func (b *build) add(c Cmd) {
	b.script.Cmd = append(b.script.Cmd, &c)
}

func (b *build) mkdir(name string) {
	b.add(Cmd{
		Args:   []string{"mkdir", "-p", name},
		Output: []string{name},
	})
}

func (b *build) gc(ofile string, gofiles ...string) {
	gc := b.arch + "g"
	args := append([]string{gc, "-o", ofile}, gcImportArgs...)
	args = append(args, gofiles...)
	b.add(Cmd{
		Args:   args,
		Input:  gofiles,
		Output: []string{ofile},
	})
}

func (b *build) asm(ofile string, sfile string) {
	asm := b.arch + "a"
	b.add(Cmd{
		Args:   []string{asm, "-o", ofile, sfile},
		Input:  []string{sfile},
		Output: []string{ofile},
	})
}

func (b *build) ld(targ string, ofiles ...string) {
	ld := b.arch + "l"
	args := append([]string{ld, "-o", targ}, ldImportArgs...)
	args = append(args, ofiles...)
	b.add(Cmd{
		Args:   args,
		Input:  ofiles,
		Output: []string{targ},
	})
}

func (b *build) gopack(targ string, ofiles ...string) {
	b.add(Cmd{
		Args:   append([]string{"gopack", "grc", targ}, ofiles...),
		Input:  ofiles,
		Output: []string{targ},
	})
}

func (b *build) cc(ofile string, cfiles ...string) {
	cc := b.arch + "c"
	dir := fmt.Sprintf("%s_%s", runtime.GOOS, runtime.GOARCH)
	inc := filepath.Join(runtime.GOROOT(), "pkg", dir)
	args := []string{cc, "-FVw", "-I", inc, "-o", ofile}
	b.add(Cmd{
		Args:   append(args, cfiles...),
		Input:  cfiles,
		Output: []string{ofile},
	})
}

func (b *build) gccCompile(ofile, cfile string) {
	b.add(Cmd{
		Args:   b.gccArgs("-o", ofile, "-c", cfile),
		Input:  []string{cfile},
		Output: []string{ofile},
	})
}

func (b *build) gccLink(ofile string, ofiles ...string) {
	b.add(Cmd{
		Args:   append(b.gccArgs("-o", ofile), ofiles...),
		Input:  ofiles,
		Output: []string{ofile},
	})
}

func (b *build) gccArgs(args ...string) []string {
	// TODO(adg): HOST_CC
	m := "-m32"
	if b.arch == "6" {
		m = "-m64"
	}
	return append([]string{"gcc", m, "-I", b.path, "-g", "-fPIC", "-O2"}, args...)
}

func (b *build) cgo(cgofiles []string) (outGo, outObj []string) {
	// cgo
	// TODO(adg): CGOPKGPATH
	// TODO(adg): CGO_FLAGS
	gofiles := []string{b.obj + "_cgo_gotypes.go"}
	cfiles := []string{b.obj + "_cgo_main.c", b.obj + "_cgo_export.c"}
	for _, fn := range cgofiles {
		f := b.obj + strings.Replace(fn[:len(fn)-2], "/", "_", -1)
		gofiles = append(gofiles, f+"cgo1.go")
		cfiles = append(cfiles, f+"cgo2.c")
	}
	defunC := b.obj + "_cgo_defun.c"
	output := append([]string{defunC}, cfiles...)
	output = append(output, gofiles...)
	b.add(Cmd{
		Args:   append([]string{"cgo", "--"}, cgofiles...),
		Dir:    b.path,
		Input:  cgofiles,
		Output: output,
	})
	outGo = append(outGo, gofiles...)
	exportH := filepath.Join(b.path, "_cgo_export.h")
	b.script.addIntermediate(defunC, exportH, b.obj+"_cgo_flags")
	b.script.addIntermediate(cfiles...)

	// cc _cgo_defun.c
	defunObj := b.obj + "_cgo_defun." + b.arch
	b.cc(defunObj, defunC)
	outObj = append(outObj, defunObj)

	// gcc
	linkobj := make([]string, 0, len(cfiles))
	for _, cfile := range cfiles {
		ofile := cfile[:len(cfile)-1] + "o"
		b.gccCompile(ofile, cfile)
		linkobj = append(linkobj, ofile)
		if !strings.HasSuffix(ofile, "_cgo_main.o") {
			outObj = append(outObj, ofile)
		} else {
			b.script.addIntermediate(ofile)
		}
	}
	dynObj := b.obj + "_cgo_.o"
	b.gccLink(dynObj, linkobj...)
	b.script.addIntermediate(dynObj)

	// cgo -dynimport
	importC := b.obj + "_cgo_import.c"
	b.add(Cmd{
		Args:   []string{"cgo", "-dynimport", dynObj},
		Stdout: importC,
		Input:  []string{dynObj},
		Output: []string{importC},
	})
	b.script.addIntermediate(importC)

	// cc _cgo_import.ARCH
	importObj := b.obj + "_cgo_import." + b.arch
	b.cc(importObj, importC)
	outObj = append(outObj, importObj)

	return
}
<|endoftext|>


<commit_before>// Copyright 2011 The Go Authors.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package build provides tools for building Go packages.
package build

import (
	"bytes"
	"exec"
	"fmt"
	"os"
	"path/filepath"
	"regexp"
	"runtime"
	"strings"
)

// Build produces a build Script for the given package.
func Build(tree *Tree, pkg string, info *DirInfo) (*Script, os.Error) {
	s := &Script{}
	b := &build{
		script: s,
		path:   filepath.Join(tree.SrcDir(), pkg),
	}
	b.obj = b.abs("_obj") + string(filepath.Separator)

	b.goarch = runtime.GOARCH
	if g := os.Getenv("GOARCH"); g != "" {
		b.goarch = g
	}
	var err os.Error
	b.arch, err = ArchChar(b.goarch)
	if err != nil {
		return nil, err
	}

	// add import object files to list of Inputs
	for _, pkg := range info.Imports {
		t, p, err := FindTree(pkg)
		if err != nil && err != ErrNotFound {
			// FindTree should always be able to suggest an import
			// path and tree. The path must be malformed
			// (for example, an absolute or relative path).
			return nil, os.NewError("build: invalid import: " + pkg)
		}
		s.addInput(filepath.Join(t.PkgDir(), p+".a"))
	}

	// .go files to be built with gc
	gofiles := b.abss(info.GoFiles...)
	s.addInput(gofiles...)

	var ofiles []string // object files to be linked or packed

	// make build directory
	b.mkdir(b.obj)
	s.addIntermediate(b.obj)

	// cgo
	if len(info.CgoFiles) > 0 {
		cgoFiles := b.abss(info.CgoFiles...)
		s.addInput(cgoFiles...)
		outGo, outObj := b.cgo(cgoFiles)
		gofiles = append(gofiles, outGo...)
		ofiles = append(ofiles, outObj...)
		s.addIntermediate(outGo...)
		s.addIntermediate(outObj...)
	}

	// compile
	if len(gofiles) > 0 {
		ofile := b.obj + "_go_." + b.arch
		b.gc(ofile, gofiles...)
		ofiles = append(ofiles, ofile)
		s.addIntermediate(ofile)
	}

	// assemble
	for _, sfile := range info.SFiles {
		ofile := b.obj + sfile[:len(sfile)-1] + b.arch
		sfile = b.abs(sfile)
		s.addInput(sfile)
		b.asm(ofile, sfile)
		ofiles = append(ofiles, ofile)
		s.addIntermediate(ofile)
	}

	if len(ofiles) == 0 {
		return nil, os.NewError("make: no object files to build")
	}

	// choose target file
	var targ string
	if info.IsCommand() {
		// use the last part of the import path as binary name
		_, bin := filepath.Split(pkg)
		if runtime.GOOS == "windows" {
			bin += ".exe"
		}
		targ = filepath.Join(tree.BinDir(), bin)
	} else {
		targ = filepath.Join(tree.PkgDir(), pkg+".a")
	}

	// make target directory
	targDir, _ := filepath.Split(targ)
	b.mkdir(targDir)

	// link binary or pack object
	if info.IsCommand() {
		b.ld(targ, ofiles...)
	} else {
		b.gopack(targ, ofiles...)
	}
	s.Output = append(s.Output, targ)

	return b.script, nil
}

// A Script describes the build process for a Go package.
// The Input, Intermediate, and Output fields are lists of absolute paths.
type Script struct {
	Cmd          []*Cmd
	Input        []string
	Intermediate []string
	Output       []string
}

func (s *Script) addInput(file ...string) {
	s.Input = append(s.Input, file...)
}

func (s *Script) addIntermediate(file ...string) {
	s.Intermediate = append(s.Intermediate, file...)
}

// Run runs the Script's Cmds in order.
func (s *Script) Run() os.Error {
	for _, c := range s.Cmd {
		if err := c.Run(); err != nil {
			return err
		}
	}
	return nil
}

// Stale returns true if the build's inputs are newer than its outputs.
func (s *Script) Stale() bool {
	var latest int64
	// get latest mtime of outputs
	for _, file := range s.Output {
		fi, err := os.Stat(file)
		if err != nil {
			// any error reading output files means stale
			return true
		}
		if m := fi.Mtime_ns; m > latest {
			latest = m
		}
	}
	for _, file := range s.Input {
		fi, err := os.Stat(file)
		if err != nil || fi.Mtime_ns > latest {
			// any error reading input files means stale
			// (attempt to rebuild to figure out why)
			return true
		}
	}
	return false
}

// Clean removes the Script's Intermediate files.
// It tries to remove every file and returns the first error it encounters.
func (s *Script) Clean() (err os.Error) {
	// Reverse order so that directories get removed after the files they contain.
	for i := len(s.Intermediate) - 1; i >= 0; i-- {
		if e := os.Remove(s.Intermediate[i]); err == nil {
			err = e
		}
	}
	return
}

// Clean removes the Script's Intermediate and Output files.
// It tries to remove every file and returns the first error it encounters.
func (s *Script) Nuke() (err os.Error) {
	// Reverse order so that directories get removed after the files they contain.
	for i := len(s.Output) - 1; i >= 0; i-- {
		if e := os.Remove(s.Output[i]); err == nil {
			err = e
		}
	}
	if e := s.Clean(); err == nil {
		err = e
	}
	return
}

// A Cmd describes an individual build command.
type Cmd struct {
	Args   []string // command-line
	Stdout string   // write standard output to this file, "" is passthrough
	Dir    string   // working directory
	Env    []string // environment
	Input  []string // file paths (dependencies)
	Output []string // file paths
}

func (c *Cmd) String() string {
	return strings.Join(c.Args, " ")
}

// Run executes the Cmd.
func (c *Cmd) Run() os.Error {
	if c.Args[0] == "mkdir" {
		for _, p := range c.Output {
			if err := os.MkdirAll(p, 0777); err != nil {
				return fmt.Errorf("command %q: %v", c, err)
			}
		}
		return nil
	}
	out := new(bytes.Buffer)
	cmd := exec.Command(c.Args[0], c.Args[1:]...)
	cmd.Dir = c.Dir
	cmd.Env = c.Env
	cmd.Stdout = out
	cmd.Stderr = out
	if c.Stdout != "" {
		f, err := os.Create(c.Stdout)
		if err != nil {
			return err
		}
		defer f.Close()
		cmd.Stdout = f
	}
	if err := cmd.Run(); err != nil {
		return fmt.Errorf("command %q: %v\n%v", c, err, out)
	}
	return nil
}

// ArchChar returns the architecture character for the given goarch.
// For example, ArchChar("amd64") returns "6".
func ArchChar(goarch string) (string, os.Error) {
	switch goarch {
	case "386":
		return "8", nil
	case "amd64":
		return "6", nil
	case "arm":
		return "5", nil
	}
	return "", os.NewError("unsupported GOARCH " + goarch)
}

type build struct {
	script *Script
	path   string
	obj    string
	goarch string
	arch   string
}

func (b *build) abs(file string) string {
	if filepath.IsAbs(file) {
		return file
	}
	return filepath.Join(b.path, file)
}

func (b *build) abss(file ...string) []string {
	s := make([]string, len(file))
	for i, f := range file {
		s[i] = b.abs(f)
	}
	return s
}

func (b *build) add(c Cmd) {
	b.script.Cmd = append(b.script.Cmd, &c)
}

func (b *build) mkdir(name string) {
	b.add(Cmd{
		Args:   []string{"mkdir", "-p", name},
		Output: []string{name},
	})
}

func (b *build) gc(ofile string, gofiles ...string) {
	gc := b.arch + "g"
	args := append([]string{gc, "-o", ofile}, gcImportArgs...)
	args = append(args, gofiles...)
	b.add(Cmd{
		Args:   args,
		Input:  gofiles,
		Output: []string{ofile},
	})
}

func (b *build) asm(ofile string, sfile string) {
	asm := b.arch + "a"
	b.add(Cmd{
		Args:   []string{asm, "-o", ofile, sfile},
		Input:  []string{sfile},
		Output: []string{ofile},
	})
}

func (b *build) ld(targ string, ofiles ...string) {
	ld := b.arch + "l"
	args := append([]string{ld, "-o", targ}, ldImportArgs...)
	args = append(args, ofiles...)
	b.add(Cmd{
		Args:   args,
		Input:  ofiles,
		Output: []string{targ},
	})
}

func (b *build) gopack(targ string, ofiles ...string) {
	b.add(Cmd{
		Args:   append([]string{"gopack", "grc", targ}, ofiles...),
		Input:  ofiles,
		Output: []string{targ},
	})
}

func (b *build) cc(ofile string, cfiles ...string) {
	cc := b.arch + "c"
	dir := fmt.Sprintf("%s_%s", runtime.GOOS, runtime.GOARCH)
	inc := filepath.Join(runtime.GOROOT(), "pkg", dir)
	args := []string{cc, "-FVw", "-I", inc, "-o", ofile}
	b.add(Cmd{
		Args:   append(args, cfiles...),
		Input:  cfiles,
		Output: []string{ofile},
	})
}

func (b *build) gccCompile(ofile, cfile string) {
	b.add(Cmd{
		Args:   b.gccArgs("-o", ofile, "-c", cfile),
		Input:  []string{cfile},
		Output: []string{ofile},
	})
}

func (b *build) gccLink(ofile string, ofiles ...string) {
	b.add(Cmd{
		Args:   append(b.gccArgs("-o", ofile), ofiles...),
		Input:  ofiles,
		Output: []string{ofile},
	})
}

func (b *build) gccArgs(args ...string) []string {
	// TODO(adg): HOST_CC
	a := []string{"gcc", "-I", b.path, "-g", "-fPIC", "-O2"}
	switch b.arch {
	case "8":
		a = append(a, "-m32")
	case "6":
		a = append(a, "-m64")
	}
	return append(a, args...)
}

var cgoRe = regexp.MustCompile(`[/\\:]`)

func (b *build) cgo(cgofiles []string) (outGo, outObj []string) {
	// cgo
	// TODO(adg): CGOPKGPATH
	// TODO(adg): CGO_FLAGS
	gofiles := []string{b.obj + "_cgo_gotypes.go"}
	cfiles := []string{b.obj + "_cgo_main.c", b.obj + "_cgo_export.c"}
	for _, fn := range cgofiles {
		f := b.obj + cgoRe.ReplaceAllString(fn[:len(fn)-2], "_")
		gofiles = append(gofiles, f+"cgo1.go")
		cfiles = append(cfiles, f+"cgo2.c")
	}
	defunC := b.obj + "_cgo_defun.c"
	output := append([]string{defunC}, cfiles...)
	output = append(output, gofiles...)
	b.add(Cmd{
		Args:   append([]string{"cgo", "--"}, cgofiles...),
		Dir:    b.path,
		Env:    append(os.Environ(), "GOARCH="+b.goarch),
		Input:  cgofiles,
		Output: output,
	})
	outGo = append(outGo, gofiles...)
	exportH := filepath.Join(b.path, "_cgo_export.h")
	b.script.addIntermediate(defunC, exportH, b.obj+"_cgo_flags")
	b.script.addIntermediate(cfiles...)

	// cc _cgo_defun.c
	defunObj := b.obj + "_cgo_defun." + b.arch
	b.cc(defunObj, defunC)
	outObj = append(outObj, defunObj)

	// gcc
	linkobj := make([]string, 0, len(cfiles))
	for _, cfile := range cfiles {
		ofile := cfile[:len(cfile)-1] + "o"
		b.gccCompile(ofile, cfile)
		linkobj = append(linkobj, ofile)
		if !strings.HasSuffix(ofile, "_cgo_main.o") {
			outObj = append(outObj, ofile)
		} else {
			b.script.addIntermediate(ofile)
		}
	}
	dynObj := b.obj + "_cgo_.o"
	b.gccLink(dynObj, linkobj...)
	b.script.addIntermediate(dynObj)

	// cgo -dynimport
	importC := b.obj + "_cgo_import.c"
	b.add(Cmd{
		Args:   []string{"cgo", "-dynimport", dynObj},
		Stdout: importC,
		Input:  []string{dynObj},
		Output: []string{importC},
	})
	b.script.addIntermediate(importC)

	// cc _cgo_import.ARCH
	importObj := b.obj + "_cgo_import." + b.arch
	b.cc(importObj, importC)
	outObj = append(outObj, importObj)

	return
}
<commit_msg>go/build: make Nuke comment say what it does<commit_after>// Copyright 2011 The Go Authors.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package build provides tools for building Go packages.
package build

import (
	"bytes"
	"exec"
	"fmt"
	"os"
	"path/filepath"
	"regexp"
	"runtime"
	"strings"
)

// Build produces a build Script for the given package.
func Build(tree *Tree, pkg string, info *DirInfo) (*Script, os.Error) {
	s := &Script{}
	b := &build{
		script: s,
		path:   filepath.Join(tree.SrcDir(), pkg),
	}
	b.obj = b.abs("_obj") + string(filepath.Separator)

	b.goarch = runtime.GOARCH
	if g := os.Getenv("GOARCH"); g != "" {
		b.goarch = g
	}
	var err os.Error
	b.arch, err = ArchChar(b.goarch)
	if err != nil {
		return nil, err
	}

	// add import object files to list of Inputs
	for _, pkg := range info.Imports {
		t, p, err := FindTree(pkg)
		if err != nil && err != ErrNotFound {
			// FindTree should always be able to suggest an import
			// path and tree. The path must be malformed
			// (for example, an absolute or relative path).
			return nil, os.NewError("build: invalid import: " + pkg)
		}
		s.addInput(filepath.Join(t.PkgDir(), p+".a"))
	}

	// .go files to be built with gc
	gofiles := b.abss(info.GoFiles...)
	s.addInput(gofiles...)

	var ofiles []string // object files to be linked or packed

	// make build directory
	b.mkdir(b.obj)
	s.addIntermediate(b.obj)

	// cgo
	if len(info.CgoFiles) > 0 {
		cgoFiles := b.abss(info.CgoFiles...)
		s.addInput(cgoFiles...)
		outGo, outObj := b.cgo(cgoFiles)
		gofiles = append(gofiles, outGo...)
		ofiles = append(ofiles, outObj...)
		s.addIntermediate(outGo...)
		s.addIntermediate(outObj...)
	}

	// compile
	if len(gofiles) > 0 {
		ofile := b.obj + "_go_." + b.arch
		b.gc(ofile, gofiles...)
		ofiles = append(ofiles, ofile)
		s.addIntermediate(ofile)
	}

	// assemble
	for _, sfile := range info.SFiles {
		ofile := b.obj + sfile[:len(sfile)-1] + b.arch
		sfile = b.abs(sfile)
		s.addInput(sfile)
		b.asm(ofile, sfile)
		ofiles = append(ofiles, ofile)
		s.addIntermediate(ofile)
	}

	if len(ofiles) == 0 {
		return nil, os.NewError("make: no object files to build")
	}

	// choose target file
	var targ string
	if info.IsCommand() {
		// use the last part of the import path as binary name
		_, bin := filepath.Split(pkg)
		if runtime.GOOS == "windows" {
			bin += ".exe"
		}
		targ = filepath.Join(tree.BinDir(), bin)
	} else {
		targ = filepath.Join(tree.PkgDir(), pkg+".a")
	}

	// make target directory
	targDir, _ := filepath.Split(targ)
	b.mkdir(targDir)

	// link binary or pack object
	if info.IsCommand() {
		b.ld(targ, ofiles...)
	} else {
		b.gopack(targ, ofiles...)
	}
	s.Output = append(s.Output, targ)

	return b.script, nil
}

// A Script describes the build process for a Go package.
// The Input, Intermediate, and Output fields are lists of absolute paths.
type Script struct {
	Cmd          []*Cmd
	Input        []string
	Intermediate []string
	Output       []string
}

func (s *Script) addInput(file ...string) {
	s.Input = append(s.Input, file...)
}

func (s *Script) addIntermediate(file ...string) {
	s.Intermediate = append(s.Intermediate, file...)
}

// Run runs the Script's Cmds in order.
func (s *Script) Run() os.Error {
	for _, c := range s.Cmd {
		if err := c.Run(); err != nil {
			return err
		}
	}
	return nil
}

// Stale returns true if the build's inputs are newer than its outputs.
func (s *Script) Stale() bool {
	var latest int64
	// get latest mtime of outputs
	for _, file := range s.Output {
		fi, err := os.Stat(file)
		if err != nil {
			// any error reading output files means stale
			return true
		}
		if m := fi.Mtime_ns; m > latest {
			latest = m
		}
	}
	for _, file := range s.Input {
		fi, err := os.Stat(file)
		if err != nil || fi.Mtime_ns > latest {
			// any error reading input files means stale
			// (attempt to rebuild to figure out why)
			return true
		}
	}
	return false
}

// Clean removes the Script's Intermediate files.
// It tries to remove every file and returns the first error it encounters.
func (s *Script) Clean() (err os.Error) {
	// Reverse order so that directories get removed after the files they contain.
	for i := len(s.Intermediate) - 1; i >= 0; i-- {
		if e := os.Remove(s.Intermediate[i]); err == nil {
			err = e
		}
	}
	return
}

// Nuke removes the Script's Intermediate and Output files.
// It tries to remove every file and returns the first error it encounters.
func (s *Script) Nuke() (err os.Error) {
	// Reverse order so that directories get removed after the files they contain.
	for i := len(s.Output) - 1; i >= 0; i-- {
		if e := os.Remove(s.Output[i]); err == nil {
			err = e
		}
	}
	if e := s.Clean(); err == nil {
		err = e
	}
	return
}

// A Cmd describes an individual build command.
type Cmd struct {
	Args   []string // command-line
	Stdout string   // write standard output to this file, "" is passthrough
	Dir    string   // working directory
	Env    []string // environment
	Input  []string // file paths (dependencies)
	Output []string // file paths
}

func (c *Cmd) String() string {
	return strings.Join(c.Args, " ")
}

// Run executes the Cmd.
func (c *Cmd) Run() os.Error {
	if c.Args[0] == "mkdir" {
		for _, p := range c.Output {
			if err := os.MkdirAll(p, 0777); err != nil {
				return fmt.Errorf("command %q: %v", c, err)
			}
		}
		return nil
	}
	out := new(bytes.Buffer)
	cmd := exec.Command(c.Args[0], c.Args[1:]...)
	cmd.Dir = c.Dir
	cmd.Env = c.Env
	cmd.Stdout = out
	cmd.Stderr = out
	if c.Stdout != "" {
		f, err := os.Create(c.Stdout)
		if err != nil {
			return err
		}
		defer f.Close()
		cmd.Stdout = f
	}
	if err := cmd.Run(); err != nil {
		return fmt.Errorf("command %q: %v\n%v", c, err, out)
	}
	return nil
}

// ArchChar returns the architecture character for the given goarch.
// For example, ArchChar("amd64") returns "6".
func ArchChar(goarch string) (string, os.Error) {
	switch goarch {
	case "386":
		return "8", nil
	case "amd64":
		return "6", nil
	case "arm":
		return "5", nil
	}
	return "", os.NewError("unsupported GOARCH " + goarch)
}

type build struct {
	script *Script
	path   string
	obj    string
	goarch string
	arch   string
}

func (b *build) abs(file string) string {
	if filepath.IsAbs(file) {
		return file
	}
	return filepath.Join(b.path, file)
}

func (b *build) abss(file ...string) []string {
	s := make([]string, len(file))
	for i, f := range file {
		s[i] = b.abs(f)
	}
	return s
}

func (b *build) add(c Cmd) {
	b.script.Cmd = append(b.script.Cmd, &c)
}

func (b *build) mkdir(name string) {
	b.add(Cmd{
		Args:   []string{"mkdir", "-p", name},
		Output: []string{name},
	})
}

func (b *build) gc(ofile string, gofiles ...string) {
	gc := b.arch + "g"
	args := append([]string{gc, "-o", ofile}, gcImportArgs...)
	args = append(args, gofiles...)
	b.add(Cmd{
		Args:   args,
		Input:  gofiles,
		Output: []string{ofile},
	})
}

func (b *build) asm(ofile string, sfile string) {
	asm := b.arch + "a"
	b.add(Cmd{
		Args:   []string{asm, "-o", ofile, sfile},
		Input:  []string{sfile},
		Output: []string{ofile},
	})
}

func (b *build) ld(targ string, ofiles ...string) {
	ld := b.arch + "l"
	args := append([]string{ld, "-o", targ}, ldImportArgs...)
	args = append(args, ofiles...)
	b.add(Cmd{
		Args:   args,
		Input:  ofiles,
		Output: []string{targ},
	})
}

func (b *build) gopack(targ string, ofiles ...string) {
	b.add(Cmd{
		Args:   append([]string{"gopack", "grc", targ}, ofiles...),
		Input:  ofiles,
		Output: []string{targ},
	})
}

func (b *build) cc(ofile string, cfiles ...string) {
	cc := b.arch + "c"
	dir := fmt.Sprintf("%s_%s", runtime.GOOS, runtime.GOARCH)
	inc := filepath.Join(runtime.GOROOT(), "pkg", dir)
	args := []string{cc, "-FVw", "-I", inc, "-o", ofile}
	b.add(Cmd{
		Args:   append(args, cfiles...),
		Input:  cfiles,
		Output: []string{ofile},
	})
}

func (b *build) gccCompile(ofile, cfile string) {
	b.add(Cmd{
		Args:   b.gccArgs("-o", ofile, "-c", cfile),
		Input:  []string{cfile},
		Output: []string{ofile},
	})
}

func (b *build) gccLink(ofile string, ofiles ...string) {
	b.add(Cmd{
		Args:   append(b.gccArgs("-o", ofile), ofiles...),
		Input:  ofiles,
		Output: []string{ofile},
	})
}

func (b *build) gccArgs(args ...string) []string {
	// TODO(adg): HOST_CC
	a := []string{"gcc", "-I", b.path, "-g", "-fPIC", "-O2"}
	switch b.arch {
	case "8":
		a = append(a, "-m32")
	case "6":
		a = append(a, "-m64")
	}
	return append(a, args...)
}

var cgoRe = regexp.MustCompile(`[/\\:]`)

func (b *build) cgo(cgofiles []string) (outGo, outObj []string) {
	// cgo
	// TODO(adg): CGOPKGPATH
	// TODO(adg): CGO_FLAGS
	gofiles := []string{b.obj + "_cgo_gotypes.go"}
	cfiles := []string{b.obj + "_cgo_main.c", b.obj + "_cgo_export.c"}
	for _, fn := range cgofiles {
		f := b.obj + cgoRe.ReplaceAllString(fn[:len(fn)-2], "_")
		gofiles = append(gofiles, f+"cgo1.go")
		cfiles = append(cfiles, f+"cgo2.c")
	}
	defunC := b.obj + "_cgo_defun.c"
	output := append([]string{defunC}, cfiles...)
	output = append(output, gofiles...)
	b.add(Cmd{
		Args:   append([]string{"cgo", "--"}, cgofiles...),
		Dir:    b.path,
		Env:    append(os.Environ(), "GOARCH="+b.goarch),
		Input:  cgofiles,
		Output: output,
	})
	outGo = append(outGo, gofiles...)
	exportH := filepath.Join(b.path, "_cgo_export.h")
	b.script.addIntermediate(defunC, exportH, b.obj+"_cgo_flags")
	b.script.addIntermediate(cfiles...)

	// cc _cgo_defun.c
	defunObj := b.obj + "_cgo_defun." + b.arch
	b.cc(defunObj, defunC)
	outObj = append(outObj, defunObj)

	// gcc
	linkobj := make([]string, 0, len(cfiles))
	for _, cfile := range cfiles {
		ofile := cfile[:len(cfile)-1] + "o"
		b.gccCompile(ofile, cfile)
		linkobj = append(linkobj, ofile)
		if !strings.HasSuffix(ofile, "_cgo_main.o") {
			outObj = append(outObj, ofile)
		} else {
			b.script.addIntermediate(ofile)
		}
	}
	dynObj := b.obj + "_cgo_.o"
	b.gccLink(dynObj, linkobj...)
	b.script.addIntermediate(dynObj)

	// cgo -dynimport
	importC := b.obj + "_cgo_import.c"
	b.add(Cmd{
		Args:   []string{"cgo", "-dynimport", dynObj},
		Stdout: importC,
		Input:  []string{dynObj},
		Output: []string{importC},
	})
	b.script.addIntermediate(importC)

	// cc _cgo_import.ARCH
	importObj := b.obj + "_cgo_import." + b.arch
	b.cc(importObj, importC)
	outObj = append(outObj, importObj)

	return
}
<|endoftext|>


<commit_before>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package strings

import (
	"errors"
	"io"
	"unicode/utf8"
)

// A Reader implements the io.Reader, io.Seeker, io.ByteScanner, and
// io.RuneScanner interfaces by reading from a string.
type Reader struct {
	s        string
	i        int // current reading index
	prevRune int // index of previous rune; or < 0
}

// Len returns the number of bytes of the unread portion of the
// string.
func (r *Reader) Len() int {
	if r.i >= len(r.s) {
		return 0
	}
	return len(r.s) - r.i
}

func (r *Reader) Read(b []byte) (n int, err error) {
	if len(b) == 0 {
		return 0, nil
	}
	if r.i >= len(r.s) {
		return 0, io.EOF
	}
	n = copy(b, r.s[r.i:])
	r.i += n
	r.prevRune = -1
	return
}

func (r *Reader) ReadByte() (b byte, err error) {
	if r.i >= len(r.s) {
		return 0, io.EOF
	}
	b = r.s[r.i]
	r.i++
	r.prevRune = -1
	return
}

// UnreadByte moves the reading position back by one byte.
// It is an error to call UnreadByte if nothing has been
// read yet.
func (r *Reader) UnreadByte() error {
	if r.i <= 0 {
		return errors.New("strings.Reader: at beginning of string")
	}
	r.i--
	r.prevRune = -1
	return nil
}

// ReadRune reads and returns the next UTF-8-encoded
// Unicode code point from the buffer.
// If no bytes are available, the error returned is io.EOF.
// If the bytes are an erroneous UTF-8 encoding, it
// consumes one byte and returns U+FFFD, 1.
func (r *Reader) ReadRune() (ch rune, size int, err error) {
	if r.i >= len(r.s) {
		return 0, 0, io.EOF
	}
	r.prevRune = r.i
	if c := r.s[r.i]; c < utf8.RuneSelf {
		r.i++
		return rune(c), 1, nil
	}
	ch, size = utf8.DecodeRuneInString(r.s[r.i:])
	r.i += size
	return
}

// UnreadRune causes the next call to ReadRune to return the same rune
// as the previous call to ReadRune.
// The last method called on r must have been ReadRune.
func (r *Reader) UnreadRune() error {
	if r.prevRune < 0 {
		return errors.New("strings.Reader: previous operation was not ReadRune")
	}
	r.i = r.prevRune
	r.prevRune = -1
	return nil
}

// Seek implements the io.Seeker interface.
func (r *Reader) Seek(offset int64, whence int) (int64, error) {
	var abs int64
	switch whence {
	case 0:
		abs = offset
	case 1:
		abs = int64(r.i) + offset
	case 2:
		abs = int64(len(r.s)) + offset
	default:
		return 0, errors.New("strings: invalid whence")
	}
	if abs < 0 {
		return 0, errors.New("strings: negative position")
	}
	if abs >= 1<<31 {
		return 0, errors.New("strings: position out of range")
	}
	r.i = int(abs)
	return abs, nil
}

// NewReader returns a new Reader reading from s.
// It is similar to bytes.NewBufferString but more efficient and read-only.
func NewReader(s string) *Reader { return &Reader{s, 0, -1} }
<commit_msg>strings: delete method comments implied by interface satisfaction<commit_after>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package strings

import (
	"errors"
	"io"
	"unicode/utf8"
)

// A Reader implements the io.Reader, io.Seeker, io.ByteScanner, and
// io.RuneScanner interfaces by reading from a string.
type Reader struct {
	s        string
	i        int // current reading index
	prevRune int // index of previous rune; or < 0
}

// Len returns the number of bytes of the unread portion of the
// string.
func (r *Reader) Len() int {
	if r.i >= len(r.s) {
		return 0
	}
	return len(r.s) - r.i
}

func (r *Reader) Read(b []byte) (n int, err error) {
	if len(b) == 0 {
		return 0, nil
	}
	if r.i >= len(r.s) {
		return 0, io.EOF
	}
	n = copy(b, r.s[r.i:])
	r.i += n
	r.prevRune = -1
	return
}

func (r *Reader) ReadByte() (b byte, err error) {
	if r.i >= len(r.s) {
		return 0, io.EOF
	}
	b = r.s[r.i]
	r.i++
	r.prevRune = -1
	return
}

func (r *Reader) UnreadByte() error {
	if r.i <= 0 {
		return errors.New("strings.Reader: at beginning of string")
	}
	r.i--
	r.prevRune = -1
	return nil
}

func (r *Reader) ReadRune() (ch rune, size int, err error) {
	if r.i >= len(r.s) {
		return 0, 0, io.EOF
	}
	r.prevRune = r.i
	if c := r.s[r.i]; c < utf8.RuneSelf {
		r.i++
		return rune(c), 1, nil
	}
	ch, size = utf8.DecodeRuneInString(r.s[r.i:])
	r.i += size
	return
}

func (r *Reader) UnreadRune() error {
	if r.prevRune < 0 {
		return errors.New("strings.Reader: previous operation was not ReadRune")
	}
	r.i = r.prevRune
	r.prevRune = -1
	return nil
}

// Seek implements the io.Seeker interface.
func (r *Reader) Seek(offset int64, whence int) (int64, error) {
	var abs int64
	switch whence {
	case 0:
		abs = offset
	case 1:
		abs = int64(r.i) + offset
	case 2:
		abs = int64(len(r.s)) + offset
	default:
		return 0, errors.New("strings: invalid whence")
	}
	if abs < 0 {
		return 0, errors.New("strings: negative position")
	}
	if abs >= 1<<31 {
		return 0, errors.New("strings: position out of range")
	}
	r.i = int(abs)
	return abs, nil
}

// NewReader returns a new Reader reading from s.
// It is similar to bytes.NewBufferString but more efficient and read-only.
func NewReader(s string) *Reader { return &Reader{s, 0, -1} }
<|endoftext|>