func newGlobal(pkg, name string, typ reflect.Type, value reflect.Value) Global {
	if st, ok := typ.(runtime.ScriggoType); ok {
		typ = st.GoType()
	}
	return Global{
		Pkg:   pkg,
		Name:  name,
		Type:  typ,
		Value: value,
	}
}
newGlobal returns a new Global value. If typ is a Scriggo type, then typ is
converted to a gc compiled type before creating the Global value.
package compiler
import (
	"fmt"
	"reflect"
	"github.com/open2b/scriggo/ast"
	"github.com/open2b/scriggo/internal/runtime"
)
func (em *emitter) changeRegister(k bool, src, dst int8, srcType reflect.Type, dstType reflect.Type) {
	em._changeRegister(k, src, dst, srcType, dstType, false)
}
func (em *emitter) changeRegisterConvertFormat(k bool, src, dst int8, srcType reflect.Type, dstType reflect.Type) {
	em._changeRegister(k, src, dst, srcType, dstType, true)
}
func (em *emitter) _changeRegister(k bool, src, dst int8, srcType reflect.Type, dstType reflect.Type, mdToHTML bool) {
	if dst < 0 {
		if st, ok := srcType.(runtime.ScriggoType); ok {
			srcType = st.GoType()
		}
		em.fb.emitTypify(k, srcType, src, dst)
		return
	}
	srcKind := srcType.Kind()
	dstKind := dstType.Kind()
	if dstKind == reflect.Interface && srcKind == reflect.Interface {
		em.fb.emitMove(k, src, dst, srcKind)
		return
	}
	if dstKind == reflect.Interface {
		em.fb.emitTypify(k, srcType, src, dst)
		return
	}
	if dstKind != srcKind || mdToHTML {
		if k {
			em.fb.enterScope()
			tmp := em.fb.newRegister(srcKind)
			em.fb.emitMove(true, src, tmp, srcKind)
			em.fb.emitConvert(tmp, dstType, dst, srcKind)
			em.fb.exitScope()
		} else {
			em.fb.emitConvert(src, dstType, dst, srcKind)
		}
		return
	}
	if k || src != dst {
		em.fb.emitMove(k, src, dst, srcKind)
	}
}
func (em *emitter) comparisonWithZeroInteger(cond *ast.BinaryOperator) ast.Expression {
	var expr, constant ast.Expression
	if ti2 := em.ti(cond.Expr2); ti2 != nil && ti2.IsConstant() {
		constant = cond.Expr2
		expr = cond.Expr1
	} else if ti1 := em.ti(cond.Expr1); ti1 != nil && ti1.IsConstant() {
		constant = cond.Expr1
		expr = cond.Expr2
	}
	if expr == nil {
		return nil
	}
	exprTi := em.ti(expr)
	if exprTi == nil {
		return nil
	}
	if exprTi.Type == nil {
		return nil
	}
	if k := exprTi.Type.Kind(); k < reflect.Int || k > reflect.Uintptr {
		return nil
	}
	if ti := em.ti(constant); ti != nil && ti.HasValue() {
		if i64, ok := ti.value.(int64); ok && i64 != 0 {
			return nil
		}
	}
	return expr
}
func (em *emitter) compositeLiteralLen(node *ast.CompositeLiteral) int {
	size := 0
	for _, kv := range node.KeyValues {
		if kv.Key != nil {
			key := int(em.ti(kv.Key).Constant.int64())
			if key > size {
				size = key
			}
		}
		size++
	}
	return size
}
func stackDifference(a, b runtime.StackShift) runtime.StackShift {
	return runtime.StackShift{
		a[0] - b[0],
		a[1] - b[1],
		a[2] - b[2],
		a[3] - b[3],
	}
}
func isDefault(clause *ast.Case) bool {
	return clause.Expressions == nil
}
func (em *emitter) isPredeclNil(expr ast.Expression) bool {
	return em.ti(expr).Nil()
}
func (em *emitter) builtinCallName(expr ast.Expression) string {
	if call, ok := expr.(*ast.Call); ok && em.ti(call.Func).IsBuiltinFunction() {
		return call.Func.(*ast.Identifier).Name
	}
	return ""
}
func (em *emitter) numOut(call *ast.Call) (int, bool) {
	if ti := em.ti(call.Func); ti != nil && ti.Type != nil {
		if ti.Type.Kind() == reflect.Func {
			return ti.Type.NumOut(), true
		}
	}
	return 0, false
}
func (em *emitter) isSpecialCall(args []ast.Expression) bool {
	if len(args) != 1 {
		return false
	}
	g, gIsCall := args[0].(*ast.Call)
	if !gIsCall {
		return false
	}
	_, ok := em.numOut(g)
	return ok
}
func kindToType(k reflect.Kind) registerType {
	switch k {
	case reflect.Bool:
		return intRegister
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		return intRegister
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
		return intRegister
	case reflect.Float32, reflect.Float64:
		return floatRegister
	case reflect.String:
		return stringRegister
	default:
		return generalRegister
	}
}