func BuiltinPrintf(scope Scope, arguments []Object) Object {
	obj := BuiltinSprintf(scope, arguments)
	if obj.Value.Head != UNDEFINED {
		fmt.Printf(obj.Value.Head[1:len(obj.Value.Head) - 1])
	}
	return obj
}
BuiltinPrintf: The builtin 'printf' function. This function formats
a Go-style format string with a set of arguments and writes the result to
stdout
this function returns the formatted string
package golsp
import (
	"fmt"
	"strings"
	"strconv"
	"time"
	"path/filepath"
	"io/ioutil"
	"os"
	"plugin"
)
var Builtins = Scope{}
func InitializeBuiltins(dirname string, filename string, args []string) {
	identifiers := map[string]Object{
		UNDEFINED: UndefinedObject(),
		DIRNAME: StringObject(dirname),
		FILENAME: StringObject(filename),
		ARGS: ListObject(args),
		"def": BuiltinFunctionObject("def", BuiltinDef),
		"const": BuiltinFunctionObject("const", BuiltinConst),
		"lambda": BuiltinFunctionObject("lambda", BuiltinLambda),
		"require": BuiltinFunctionObject("require", BuiltinRequire),
		"if": BuiltinFunctionObject("if", BuiltinIf),
		"when": BuiltinFunctionObject("when", BuiltinWhen),
		"do": BuiltinFunctionObject("do", BuiltinDo),
		"go": BuiltinFunctionObject("go", BuiltinGo),
		"sleep": BuiltinFunctionObject("sleep", BuiltinSleep),
		"sprintf": BuiltinFunctionObject("sprintf", BuiltinSprintf),
		"printf": BuiltinFunctionObject("printf", BuiltinPrintf),
		"+": BuiltinMathFunction("+"),
		"-": BuiltinMathFunction("-"),
		"*": BuiltinMathFunction("*"),
		"/": BuiltinMathFunction("/"),
		"%": BuiltinMathFunction("%"),
		"==": BuiltinComparisonFunction("=="),
		"!=": BuiltinComparisonFunction("!="),
		">": BuiltinComparisonFunction(">"),
		"<": BuiltinComparisonFunction("<"),
		">=": BuiltinComparisonFunction(">="),
		"<=": BuiltinComparisonFunction("<="),
	}
	Builtins.Identifiers = identifiers
	Builtins.Constants = make(map[string]bool)
	for k, _ := range identifiers { Builtins.Constants[k] = true }
}
func comparePatterns(pattern1 []STNode, pattern2 []STNode) bool {
	if len(pattern1) != len(pattern2) { return false }
	for i, node1 := range pattern1 {
		node2 := pattern2[i]
		if node1.Type != node2.Type { return false }
		if node1.Type == STNodeTypeStringLiteral ||
			node1.Type == STNodeTypeNumberLiteral {
			if node1.Head != node2.Head { return false }
		}
		if node1.Spread != node2.Spread { return false }
		if node1.Type == STNodeTypeList {
			if !comparePatterns(node1.Children, node2.Children) {
				return false
			}
		}
		if node1.Type == STNodeTypeMap {
			if !comparePatterns(node1.Children, node2.Children) {
				return false
			}
			zip1 := make([]STNode, len(node1.Children))
			zip2 := make([]STNode, len(node2.Children))
			for j, z := range node1.Children { zip1[j] = *z.Zip }
			for j, z := range node2.Children { zip2[j] = *z.Zip }
			if !comparePatterns(zip1, zip2) { return false }
		}
	}
	return true
}
func isConstant(scope Scope, identifier string) bool {
	constant, exists := scope.Constants[identifier]
	if exists { return constant }
	if scope.Parent != nil { return isConstant(*scope.Parent, identifier) }
	return false
}
func BuiltinDef(scope Scope, arguments []Object) Object {
	return assign(scope, arguments, false)
}
func BuiltinConst(scope Scope, arguments []Object) Object {
	return assign(scope, arguments, true)
}
func assign(scope Scope, arguments []Object, constant bool) Object {
	if len(arguments) < 2 {
		return UndefinedObject()
	}
	if arguments[0].Type != ObjectTypeBuiltinArgument ||
		arguments[1].Type != ObjectTypeBuiltinArgument {
		return UndefinedObject()
	}
	symbol := arguments[0].Value
	value := arguments[1].Value
	if symbol.Type != STNodeTypeIdentifier &&
		symbol.Type != STNodeTypeExpression {
		return UndefinedObject()
	}
	if symbol.Type == STNodeTypeIdentifier {
		if isConstant(scope, symbol.Head) {
			return UndefinedObject()
		}
		obj := Eval(MakeScope(&scope), value)
		if obj.Type == ObjectTypeFunction { obj.Function.Name = symbol.Head }
		scope.Identifiers[symbol.Head] = obj
		if constant { scope.Constants[symbol.Head] = true }
		return scope.Identifiers[symbol.Head]
	}
	head := symbol.Children[0]
	if head.Type != STNodeTypeIdentifier {
		return UndefinedObject()
	}
	pattern := symbol.Children[1:]
	for i, _ := range pattern {
		patternscope := MakeScope(&scope)
		for pattern[i].Type == STNodeTypeExpression {
			obj := Eval(patternscope, pattern[i])
			if obj.Type == ObjectTypeLiteral {
				pattern[i] = obj.Value
			}
		}
	}
	symbol = head
	if isConstant(scope, symbol.Head) { return UndefinedObject() }
	_, exists := scope.Identifiers[symbol.Head]
	if !exists {
		newscope := MakeScope(&scope)
		scope.Identifiers[symbol.Head] = Object{
			Scope: newscope,
			Type: ObjectTypeFunction,
		}
	}
	patternexists := false
	patternindex := 0
	for index, p := range scope.Identifiers[symbol.Head].Function.FunctionPatterns {
		if comparePatterns(pattern, p) {
			patternexists = true
			patternindex = index
			break
		}
	}
	if patternexists {
		scope.Identifiers[symbol.Head].Function.FunctionBodies[patternindex] = value
		if constant { scope.Constants[symbol.Head] = true }
		return scope.Identifiers[symbol.Head]
	}
	newfn := Function{
		Name: symbol.Head,
		FunctionPatterns: append(scope.Identifiers[symbol.Head].Function.FunctionPatterns, pattern),
		FunctionBodies: append(scope.Identifiers[symbol.Head].Function.FunctionBodies, value),
	}
	scope.Identifiers[symbol.Head] = Object{
		Scope: MakeScope(&scope),
		Type: ObjectTypeFunction,
		Function: newfn,
	}
	if constant { scope.Constants[symbol.Head] = true }
	return scope.Identifiers[symbol.Head]
}
func BuiltinLambda(scope Scope, arguments []Object) Object {
	if len(arguments) < 2 {
		return UndefinedObject()
	}
	if arguments[0].Type != ObjectTypeBuiltinArgument ||
		arguments[1].Type != ObjectTypeBuiltinArgument {
		return UndefinedObject()
	}
	if arguments[0].Value.Type != STNodeTypeExpression {
		return UndefinedObject()
	}
	pattern := arguments[0].Value.Children
	body := arguments[1].Value
	for i, _ := range pattern {
		patternscope := MakeScope(&scope)
		for pattern[i].Type == STNodeTypeExpression {
			obj := Eval(patternscope, pattern[i])
			if obj.Type == ObjectTypeLiteral {
				pattern[i] = obj.Value
			}
		}
	}
	fn := Function{
		FunctionPatterns: [][]STNode{pattern},
		FunctionBodies: []STNode{body},
	}
	return Object{
		Scope: MakeScope(&scope),
		Type: ObjectTypeFunction,
		Function: fn,
	}
}
func BuiltinRequire(scope Scope, args []Object) Object {
	arguments := EvalArgs(scope, args)
	if len(arguments) < 1 {
		return UndefinedObject()
	}
	if arguments[0].Value.Type != STNodeTypeStringLiteral {
		return UndefinedObject()
	}
	dirnode := LookupIdentifier(scope, DIRNAME)
	dirname := dirnode.Value.Head[1:len(dirnode.Value.Head) - 1]
	rawpath := arguments[0].Value.Head[1:len(arguments[0].Value.Head) - 1]
	if strings.HasPrefix(rawpath, "stdlib/") {
		dirname = os.Getenv("GOLSPPATH")
	}
	resolvedpath := filepath.Join(dirname, rawpath)
	if strings.HasSuffix(resolvedpath, ".so") {
		plug, err := plugin.Open(resolvedpath)
		if err != nil { return UndefinedObject() }
		exportssym, err := plug.Lookup("Exports")
		if err != nil { return UndefinedObject() }
		return *exportssym.(*Object)
	}
	file, err := os.Open(resolvedpath)
	if err != nil { return UndefinedObject() }
	data, err := ioutil.ReadAll(file)
	if err != nil { return UndefinedObject() }
	return Run(filepath.Dir(resolvedpath), resolvedpath, []string{}, string(data))
}
func BuiltinMathFunction(op string) Object {
	fn := func (scope Scope, args []Object) Object {
		arguments := EvalArgs(scope, args)
		for _, a := range arguments {
			if a.Value.Type != STNodeTypeNumberLiteral {
				return UndefinedObject()
			}
		}
		result := 0.0
		numbers := make([]float64, len(arguments))
		for i, arg := range arguments {
			numbers[i], _ = strconv.ParseFloat(arg.Value.Head, 64)
		}
		switch op {
		case "+":
			for _, n := range numbers { result += n }
		case "-":
			if len(numbers) > 0 { result += numbers[0] }
			for _, n := range numbers[1:] { result -= n }
		case "*":
			result = 1.0
			for _, n := range numbers { result *= n }
		case "/":
			numerator := 1.0
			if len(numbers) > 0 { numerator *= numbers[0] }
			denominator := 1.0
			for _, n := range numbers[1:] { denominator *= n }
			result = numerator / denominator
		case "%":
			numerator := 1.0
			if len(numbers) > 0 { numerator *= numbers[0] }
			denominator := 1.0
			for _, n := range numbers[1:] { denominator *= n }
			result = float64(int(numerator) % int(denominator))
		}
		return NumberObject(result)
	}
	return BuiltinFunctionObject(op, fn)
}
func formatStr(text string, objects []Object) string {
	args := make([]interface{}, len(objects))
	for i, v := range objects {
		if v.Type == ObjectTypeFunction {
			args[i] = fmt.Sprintf("<function:%v>", v.Function.Name)
			continue
		}
		if v.Type == ObjectTypeList {
			args[i] = fmt.Sprintf("{%v}",
				formatStr(strings.Repeat("%v ", v.Elements.Length), v.Elements.ToSlice()))
			continue
		}
		if v.Type == ObjectTypeMap {
			strs := make([]string, 0, len(v.MapKeys))
			for _, key := range v.MapKeys {
				str := fmt.Sprintf("%v: %v", key.Value.Head,
					formatStr("%v", []Object{v.Map[key.Value.Head]}))
				strs = append(strs, str)
			}
			args[i] = fmt.Sprintf("map(%v)", strings.Join(strs, ", "))
			continue
		}
		if v.Value.Type == STNodeTypeNumberLiteral {
			args[i], _ = ToNumber(v)
		} else if v.Value.Type == STNodeTypeStringLiteral {
			args[i], _ = ToString(v)
		} else {
			args[i] = "<undefined>"
		}
	}
	return fmt.Sprintf(text, args...)
}
func BuiltinSprintf(scope Scope, args []Object) Object {
	arguments := EvalArgs(scope, args)
	if arguments[0].Value.Type != STNodeTypeStringLiteral {
		return UndefinedObject()
	}
	text := arguments[0].Value.Head
	text = text[1:len(text) - 1]
	return StringObject(formatStr(text, arguments[1:]))
}