diff options
| author | Antonio Navarro Perez <antnavper@gmail.com> | 2024-03-20 11:15:48 +0100 |
|---|---|---|
| committer | Antonio Navarro Perez <antnavper@gmail.com> | 2024-03-20 11:15:48 +0100 |
| commit | 649ae829220d6ddd8758d24c3bc2ea7d43e788d6 (patch) | |
| tree | ca5bccce3a8ac04a96fc795b06bc40d08384286d /parser/compiler.go | |
| parent | 5da3a651ba08859ccc1cdf1094603411696c8df2 (diff) | |
feat: Add simple Dump creation and recovery.
Memory Dump functionality that can restore the previous VM state.
It dumps *global* variables, the only ones defining the program state.
The dump depends on the program itself, and on the index system, which right now is defined by the variable order.
Signed-off-by: Antonio Navarro Perez <antnavper@gmail.com>
Diffstat (limited to 'parser/compiler.go')
| -rw-r--r-- | parser/compiler.go | 93 |
1 files changed, 90 insertions, 3 deletions
diff --git a/parser/compiler.go b/parser/compiler.go index 4594ab9..568ed4a 100644 --- a/parser/compiler.go +++ b/parser/compiler.go @@ -4,6 +4,7 @@ import ( "fmt" "log" "os" + "reflect" "strconv" "github.com/mvertes/parscan/lang" @@ -328,18 +329,104 @@ type entry struct { *symbol } +func (e entry) String() string { + if e.symbol != nil { + return fmt.Sprintf("name: %s,local: %t, i: %d, k: %d, t: %s, v: %v", + e.name, + e.symbol.local, + e.symbol.index, + e.symbol.kind, + e.symbol.Type, + e.symbol.value, + ) + } + + return e.name +} + func (c *Compiler) PrintData() { + dict := c.symbolsByIndex() + + fmt.Fprintln(os.Stderr, "# Data:") + for i, d := range c.Data { + fmt.Fprintf(os.Stderr, "%4d %T %v %v\n", i, d.Data.Interface(), d.Data, dict[i]) + } +} + +func (c *Compiler) symbolsByIndex() map[int]entry { dict := map[int]entry{} for name, sym := range c.symbols { - if !sym.used || sym.local || sym.kind == symLabel { + if sym.index == unsetAddr { continue } dict[sym.index] = entry{name, sym} } - fmt.Fprintln(os.Stderr, "# Data:") + + return dict +} + +type Dump struct { + Values []*DumpValue +} + +type DumpValue struct { + Index int + Name string + Kind int + Type string + Value any +} + +// Dump gets the execution state of global variables. +func (c *Compiler) Dump() *Dump { + var dv []*DumpValue + dict := c.symbolsByIndex() for i, d := range c.Data { - fmt.Fprintf(os.Stderr, "%4d %T %v %v\n", i, d.Data.Interface(), d.Data, dict[i]) + e := dict[i] + dv = append(dv, &DumpValue{ + Index: e.index, + Name: e.name, + Kind: int(e.kind), + Type: e.Type.Name, + Value: d.Data.Interface(), + }) } + + return &Dump{Values: dv} +} + +// ApplyDump sets previously saved dump, restoring the state of global variables. +func (c *Compiler) ApplyDump(d *Dump) error { + dict := c.symbolsByIndex() + for _, dv := range d.Values { + // do all the checks to be sure we are applying the correct values + e, ok := dict[dv.Index] + if !ok { + return fmt.Errorf("entry not found on index %d", dv.Index) + } + + if dv.Name != e.name || + dv.Type != e.Type.Name || + dv.Kind != int(e.kind) { + return fmt.Errorf("entry with index %d does not match with provided entry. "+ + "dumpValue: %s, %s, %d. memoryValue: %s, %s, %d", + dv.Index, + dv.Name, dv.Type, dv.Kind, + e.name, e.Type, e.kind) + } + + if dv.Index >= len(c.Data) { + return fmt.Errorf("index (%d) bigger than memory (%d)", dv.Index, len(c.Data)) + } + + if !c.Data[dv.Index].Data.CanSet() { + return fmt.Errorf("value %v cannot be set", dv.Value) + } + + c.Data[dv.Index].Data.Set(reflect.ValueOf(dv.Value)) + } + + return nil } func (c *Compiler) typeSym(t *vm.Type) *symbol { |
