<commit_before>package runtime

import (
	"bytes"
	"errors"
	"fmt"
	"math"
)

var (
	ErrValNotAnObject = errors.New("value is not an object")
)

type funcVM struct {
	proto *GoblinFunc
	pc    int
	vars  map[string]Val
	stack []Val
	sp    int
	this  Val
	args  []Val
}

func newFuncVM(proto *GoblinFunc) *funcVM {
	return &funcVM{
		proto,
		0,
		make(map[string]Val, proto.expVars),
		make([]Val, 0, proto.stackSz),
		0,
		nil,
		nil,
	}
}

func (ø *funcVM) push(v Val) {
	// Stack has to grow as needed, StackSz doesn't take into account the loops
	if ø.sp == len(ø.stack) {
		if ø.sp == cap(ø.stack) {
			fmt.Printf("DEBUG expanding stack of func %s, current size: %d\n", ø.proto.name, len(ø.stack))
		}
		ø.stack = append(ø.stack, v)
	} else {
		ø.stack[ø.sp] = v
	}
	ø.sp++
}

func (ø *funcVM) pop() Val {
	ø.sp--
	v := ø.stack[ø.sp]
	ø.stack[ø.sp] = Nil // free this reference for gc
	return v
}

func (ø *funcVM) getVal(flg Flag, ix uint64) Val {
	switch flg {
	case FLG_K:
		return ø.proto.kTable[ix]
	case FLG_V:
		// If not found, will return Nil, so the value is always fine
		v, _ := ø.proto.ctx.getVar(ø.proto.kTable[ix].String())
		return v
	case FLG_N:
		return Nil
	case FLG_T:
		return ø.this
	case FLG_F:
		return ø.proto.ctx.Protos[ix]
	case FLG_AA:
		return ø.args[ix]
	}
	panic(fmt.Sprintf("Func.getVal() - invalid flag value %d", flg))
}

func (ø *funcVM) dump() string {
	buf := bytes.NewBuffer(nil)
	fmt.Fprintf(buf, "\n> %s\n", ø.proto.dump())
	// Constants
	fmt.Fprintf(buf, "  Constants:\n")
	for i, v := range ø.proto.kTable {
		fmt.Fprintf(buf, "    [%3d] %s\n", i, v.dump())
	}
	// Variables
	fmt.Fprintf(buf, "\n  Variables:\n")
	for k, v := range ø.vars {
		fmt.Fprintf(buf, "    %s = %s\n", k, v.dump())
	}
	// Stack
	fmt.Fprintf(buf, "\n  Stack:\n")
	i := int(math.Max(0, float64(ø.sp-5)))
	for i <= ø.sp {
		if i == ø.sp {
			fmt.Fprint(buf, "sp->")
		} else {
			fmt.Fprint(buf, "    ")
		}
		v := Val(Nil)
		if i < len(ø.stack) {
			v = ø.stack[i]
		}
		fmt.Fprintf(buf, "[%3d] %s\n", i, v.dump())
		i++
	}
	// Instructions
	fmt.Fprintf(buf, "\n  Instructions:\n")
	i = int(math.Max(0, float64(ø.pc-3)))
	for i <= ø.pc+3 {
		if i == ø.pc {
			fmt.Fprintf(buf, "pc->")
		} else {
			fmt.Fprintf(buf, "    ")
		}
		if i < len(ø.proto.code) {
			fmt.Fprintf(buf, "[%3d] %s\n", i, ø.proto.code[i])
		} else {
			break
		}
		i++
	}
	fmt.Fprintln(buf)
	return buf.String()
}

func (ø *funcVM) run(args ...Val) Val {
	// Expected args are defined in constant table spots 0 to ExpArgs - 1.
	for j, l := 0, len(args); j < ø.proto.expArgs; j++ {
		if j < l {
			ø.vars[ø.proto.kTable[j].String()] = args[j]
		} else {
			ø.vars[ø.proto.kTable[j].String()] = Nil
		}
	}
	// Keep the args array
	ø.args = args

	// Execute the instructions
	for {
		// Get the instruction to process
		i := ø.proto.code[ø.pc]<commit_msg>add instr info for Ks, vars and Fns in DUMP<commit_after>package runtime

import (
	"bytes"
	"errors"
	"fmt"
	"io"
	"math"
)

var (
	ErrValNotAnObject = errors.New("value is not an object")
)

type funcVM struct {
	proto *GoblinFunc
	pc    int
	vars  map[string]Val
	stack []Val
	sp    int
	this  Val
	args  []Val
}

func newFuncVM(proto *GoblinFunc) *funcVM {
	return &funcVM{
		proto,
		0,
		make(map[string]Val, proto.expVars),
		make([]Val, 0, proto.stackSz),
		0,
		nil,
		nil,
	}
}

func (ø *funcVM) push(v Val) {
	// Stack has to grow as needed, StackSz doesn't take into account the loops
	if ø.sp == len(ø.stack) {
		if ø.sp == cap(ø.stack) {
			fmt.Printf("DEBUG expanding stack of func %s, current size: %d\n", ø.proto.name, len(ø.stack))
		}
		ø.stack = append(ø.stack, v)
	} else {
		ø.stack[ø.sp] = v
	}
	ø.sp++
}

func (ø *funcVM) pop() Val {
	ø.sp--
	v := ø.stack[ø.sp]
	ø.stack[ø.sp] = Nil // free this reference for gc
	return v
}

func (ø *funcVM) getVal(flg Flag, ix uint64) Val {
	switch flg {
	case FLG_K:
		return ø.proto.kTable[ix]
	case FLG_V:
		// If not found, will return Nil, so the value is always fine
		v, _ := ø.proto.ctx.getVar(ø.proto.kTable[ix].String())
		return v
	case FLG_N:
		return Nil
	case FLG_T:
		return ø.this
	case FLG_F:
		return ø.proto.ctx.Protos[ix]
	case FLG_AA:
		return ø.args[ix]
	}
	panic(fmt.Sprintf("Func.getVal() - invalid flag value %d", flg))
}

func (ø *funcVM) dumpInstrInfo(w io.Writer, i Instr) {
	switch i.Flag() {
	case FLG_K:
		fmt.Fprintf(w, " ; %s", ø.proto.kTable[i.Index()].dump())
	case FLG_V:
		fmt.Fprintf(w, " ; var %s", ø.proto.kTable[i.Index()])
	case FLG_N:
		fmt.Fprintf(w, " ; %s", Nil.dump())
	case FLG_T:
		fmt.Fprint(w, " ; [this]")
	case FLG_F:
		fmt.Fprintf(w, " ; %s", ø.proto.ctx.Protos[i.Index()].dump())
	case FLG_AA:
		fmt.Fprintf(w, " ; args[%d]", i.Index())
	}
}

func (ø *funcVM) dump() string {
	buf := bytes.NewBuffer(nil)
	fmt.Fprintf(buf, "\n> %s\n", ø.proto.dump())
	// Constants
	fmt.Fprintf(buf, "  Constants:\n")
	for i, v := range ø.proto.kTable {
		fmt.Fprintf(buf, "    [%3d] %s\n", i, v.dump())
	}
	// Variables
	fmt.Fprintf(buf, "\n  Variables:\n")
	for k, v := range ø.vars {
		fmt.Fprintf(buf, "    %s = %s\n", k, v.dump())
	}
	// Stack
	fmt.Fprintf(buf, "\n  Stack:\n")
	i := int(math.Max(0, float64(ø.sp-5)))
	for i <= ø.sp {
		if i == ø.sp {
			fmt.Fprint(buf, "sp->")
		} else {
			fmt.Fprint(buf, "    ")
		}
		v := Val(Nil)
		if i < len(ø.stack) {
			v = ø.stack[i]
		}
		fmt.Fprintf(buf, "[%3d] %s\n", i, v.dump())
		i++
	}
	// Instructions
	fmt.Fprintf(buf, "\n  Instructions:\n")
	i = int(math.Max(0, float64(ø.pc-10)))
	for i <= ø.pc+10 {
		if i == ø.pc {
			fmt.Fprintf(buf, "pc->")
		} else {
			fmt.Fprintf(buf, "    ")
		}
		if i < len(ø.proto.code) {
			fmt.Fprintf(buf, "[%3d] %s", i, ø.proto.code[i])
			ø.dumpInstrInfo(buf, ø.proto.code[i])
			fmt.Fprintln(buf)
		} else {
			break
		}
		i++
	}
	fmt.Fprintln(buf)
	return buf.String()
}

func (ø *funcVM) run(args ...Val) Val {
	// Expected args are defined in constant table spots 0 to ExpArgs - 1.
	for j, l := 0, len(args); j < ø.proto.expArgs; j++ {
		if j < l {
			ø.vars[ø.proto.kTable[j].String()] = args[j]
		} else {
			ø.vars[ø.proto.kTable[j].String()] = Nil
		}
	}
	// Keep the args array
	ø.args = args

	// Execute the instructions
	for {
		// Get the instruction to process
		i := ø.proto.code[ø.pc]
{'fraction_non_alphanumeric': 0.19034637588197562, 'fraction_numerical': 0.006735086593970494, 'mean_word_length': 2.8076923076923075, 'pattern_counts': {'":': 0, '<': 15, '<?xml version=': 0, '>': 9, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3346582', 'n_tokens_mistral': 2993, 'n_tokens_neox': 2779, 'n_words': 671}