From bff0c3b31d4bebdc929282c6b415f0be877f361a Mon Sep 17 00:00:00 2001 From: hyung-hwan Date: Mon, 14 Aug 2023 01:08:37 +0900 Subject: [PATCH] chagned Value_t to use unsafe.Pointer --- bin/main.go | 6 +-- interp/eval.go | 132 +++++++++++++++++++++++++++---------------------- interp/pcl.go | 30 ++++++++--- interp/proc.go | 15 +++--- 4 files changed, 107 insertions(+), 76 deletions(-) diff --git a/bin/main.go b/bin/main.go index 24984ca..17e19e3 100644 --- a/bin/main.go +++ b/bin/main.go @@ -71,10 +71,10 @@ func main() { goto oops } - if v == nil { - panic("return value mut not be nil") + if v.Kind != pcl.VALUE_STR { + panic("return value must not be string") } - fmt.Printf("RETURN VALUE = [%s]\n", *v.(*string)) + fmt.Printf("RETURN VALUE = [%s]\n", *(*string)(v.V)) interp.Close() f.Close() diff --git a/interp/eval.go b/interp/eval.go index 707a553..aac7855 100644 --- a/interp/eval.go +++ b/interp/eval.go @@ -2,12 +2,13 @@ package interp import ( "fmt" + "unsafe" ) var debug bool = false var err_num_args *error_t = &error_t{msg: "wrong number of arguments"} -var empty_string = "" +var empty_strval = Value_t{Kind: VALUE_STR, V: unsafe.Pointer(new(string))} /* value stack (p.vstack) @@ -31,6 +32,7 @@ func (p *process_t) push_call_frame() { } else { cf.parent = p.cframe } + cf.vars = make(map[string]Value_t) p.cframe = cf } @@ -47,7 +49,7 @@ func (p *process_t) push_cnode_value(val *Cnode_t) error { return fmt.Errorf("stack full") } - p.vstack[p.vsp] = val + p.vstack[p.vsp] = Value_t{Kind: VALUE_CNODE, V: unsafe.Pointer(val)} p.vsp++ p.ctx.count++ //fmt.Printf("push_cnode_value = ctx.count => %d\n", p.ctx.count) @@ -60,7 +62,7 @@ func (p *process_t) push_string_value(val string) error { return fmt.Errorf("stack full") } - p.vstack[p.vsp] = &val + p.vstack[p.vsp] = Value_t{Kind: VALUE_STR, V: unsafe.Pointer(&val)} p.vsp++ p.ctx.count++ //fmt.Printf("push_string_value = ctx.count => %d\n", p.ctx.count) @@ -69,31 +71,27 @@ func (p *process_t) push_string_value(val string) error { func (p *process_t) merge_top_values() error { var new_val string - var v1, v2 *string - var ok1, ok2 bool + var v1, v2 Value_t if p.vsp < 2 { return fmt.Errorf("stack corrupt") } - v1, ok1 = p.vstack[p.vsp-2].(*string) - v2, ok2 = p.vstack[p.vsp-1].(*string) + v1 = p.vstack[p.vsp-2] + v2 = p.vstack[p.vsp-1] - if !ok1 { - // TODO: correct this to get the original text inside{} - // or must panic here by making {} unmergable in the feeder side - v1 = &empty_string + if v1.Kind == VALUE_STR { + new_val += *(*string)(v1.V) } - if !ok2 { - // TODO: correct this to get the original text inside {} - // or must panic here by making {} unmergable in the feeder side - v2 = &empty_string + // TODO: correct this to get the original text inside{} + // or must panic here by making {} unmergable in the feeder side + if v2.Kind == VALUE_STR { + new_val += *(*string)(v2.V) } - //new_val = *(*string)(p.vstack[p.vsp-2]) + *(*string)(p.vstack[p.vsp-1]) - new_val = *v1 + *v2 + p.vsp-- - p.vstack[p.vsp] = nil - p.vstack[p.vsp-1] = &new_val + p.vstack[p.vsp].V = unsafe.Pointer(nil) + p.vstack[p.vsp-1] = Value_t{Kind: VALUE_STR, V: unsafe.Pointer(&new_val)} p.ctx.count-- if debug { @@ -106,7 +104,7 @@ func (p *process_t) pop_value() Value_t { var v Value_t p.vsp-- v = p.vstack[p.vsp] - p.vstack[p.vsp] = nil + p.vstack[p.vsp].V = unsafe.Pointer(nil) return v } @@ -145,9 +143,7 @@ func (p *process_t) call() error { } func (p *process_t) GetCalleeName() *string { - var v *string - v, _ = (p.vstack[p.vsp-p.ctx.count+1]).(*string) - return v + return (*string)(p.vstack[p.vsp-p.ctx.count+1].V) } func (p *process_t) GetArg(idx int) Value_t { @@ -159,7 +155,7 @@ func (p *process_t) GetNumArgs() int { } func (p *process_t) ReturnString(val string) { - p.vstack[p.vsp-p.ctx.count] = &val + p.vstack[p.vsp-p.ctx.count] = Value_t{Kind: VALUE_STR, V: unsafe.Pointer(&val)} } func (p *process_t) Return(val Value_t) { @@ -190,7 +186,7 @@ func (p *process_t) pop_context(clear_vstack bool) (*Cnode_t, *Cnode_t) { if clear_vstack { // TODO: use the conttext type instead... may be able to use container_node.code??? // clean up the unused part of the stack for i = 1; i < p.ctx.count; i++ { - p.vstack[p.vsp-p.ctx.count+i] = nil + p.vstack[p.vsp-p.ctx.count+i].V = unsafe.Pointer(nil) } // pop off the cleaned arguments @@ -217,12 +213,12 @@ func (interp *Interp) dump_vstack(p *process_t) { // cnode value fmt.Printf(" %d => cnode %p", i, p.vstack[i]) // TODO: strip 1 off }*/ - switch t := p.vstack[i].(type) { - case *string: - fmt.Printf(" %d => [%s]\n", i, *t) - case *Cnode_t: + switch p.vstack[i].Kind { + case VALUE_STR: + fmt.Printf(" %d => [%s]\n", i, *(*string)(p.vstack[i].V)) + case VALUE_CNODE: fmt.Printf(" %d => ", i) - interp.dump_cnodes(t, false) + interp.dump_cnodes((*Cnode_t)(p.vstack[i].V), false) fmt.Printf("\n") default: panic("internal error - unrecognized value") @@ -265,7 +261,7 @@ func (interp *Interp) eval_stmt_nodes(p *process_t, container_node *Cnode_t) (Va org_vsp int ) - v = new(string) // TODO: change new(string) to a const + v = empty_strval upper_node = container_node stmt_node = upper_node.child // the first statement @@ -422,31 +418,18 @@ done: return v, nil oops: - return nil, err + return empty_strval, err } func (interp *Interp) eval_arg(p *process_t, pos int) (Value_t, error) { - /* - var ( - ptr uintptr - ) + var v Value_t - ptr = uintptr(p.GetArg(pos)) - if ptr&1 == 1 { // cnode - ptr &= ^uintptr(1) - //interp.dump_cnodes((*Cnode_t)(unsafe.Pointer(ptr)), true) - //return interp.eval_atom_node((*Cnode_t)(unsafe.Pointer(ptr)).child) - return interp.eval_stmt_nodes((*Cnode_t)(unsafe.Pointer(ptr))) - } else { - return (*string)(unsafe.Pointer(ptr)), nil - } - */ - - switch t := p.GetArg(pos).(type) { - case *string: - return t, nil - case *Cnode_t: - return interp.eval_stmt_nodes(p, t) + v = p.GetArg(pos) + switch v.Kind { + case VALUE_STR: + return v, nil + case VALUE_CNODE: + return interp.eval_stmt_nodes(p, (*Cnode_t)(v.V)) default: panic("internal error - argument type unrecognized") } @@ -469,23 +452,54 @@ func (interp *Interp) eval_arg_literally(p *process_t, pos int) (Value_t, error) return (*string)(unsafe.Pointer(ptr)), nil }*/ - switch t := p.GetArg(pos).(type) { - case *string: - return t, nil - case *Cnode_t: + var v Value_t + + v = p.GetArg(pos) + switch v.Kind { + case VALUE_STR: + return v, nil + case VALUE_CNODE: // TODO: can support this? by storing the original text? - return nil, fmt.Errorf("not supported - unable to evaluate {} literally") + return empty_strval, fmt.Errorf("not supported - unable to evaluate {} literally") default: panic("internal error - argument type unrecognized") } } func (interp *Interp) set_var(p *process_t, name Value_t, val Value_t) error { - //var err error_t + if name.Kind != VALUE_STR { + return fmt.Errorf("invalid variable name") + } + // TODO: error check? + p.cframe.vars[*(*string)(name.V)] = val return nil } +func (interp *Interp) get_var(p *process_t, name Value_t) (Value_t, error) { + var ( + key *string + val Value_t + f *call_frame_t + ok bool + ) + + if name.Kind != VALUE_STR { + return empty_strval, fmt.Errorf("invalid variable name") + } + + key = (*string)(name.V) + + for f = p.cframe; f != nil; f = f.parent { + val, ok = p.cframe.vars[*key] + if ok { + return val, nil + } + } + + return empty_strval, fmt.Errorf("%s not found", *key) +} + func (interp *Interp) EvalText(text []rune) (Value_t, error) { var ( v Value_t @@ -517,5 +531,5 @@ func (interp *Interp) EvalText(text []rune) (Value_t, error) { return v, nil oops: - return nil, err + return empty_strval, err } diff --git a/interp/pcl.go b/interp/pcl.go index 523a887..638cd1d 100644 --- a/interp/pcl.go +++ b/interp/pcl.go @@ -3,6 +3,7 @@ package interp import ( "fmt" "runtime" + "unsafe" ) type error_t struct { @@ -39,7 +40,17 @@ type context_t struct { container_node *Cnode_t } -type Value_t interface{} +type ValueKind int + +const ( + VALUE_STR ValueKind = iota + VALUE_CNODE +) + +type Value_t struct { + Kind ValueKind + V unsafe.Pointer +} type process_t struct { interp *Interp @@ -50,7 +61,7 @@ type process_t struct { } type call_frame_t struct { - vars *Var + vars map[string]Value_t parent *call_frame_t } @@ -243,12 +254,14 @@ func (interp *Interp) Execute(node_head *Cnode_t) (Value_t, error) { ) p = process_t{interp: interp, vsp: 0} + p.push_call_frame() - v = new(string) // if there is no code the execute, the return value is an empty string + v = empty_strval // if there is no code the execute, the return value is an empty string + err = nil for node = node_head; node != nil; node = node.next { if node.code != CNODE_INIT { - return nil, fmt.Errorf("non-init node") + return empty_strval, fmt.Errorf("non-init node") } if node.child == nil { // TODO: optmize the cnode tree that this check is not needed. the reader must not create an INIT node with empty @@ -258,11 +271,16 @@ func (interp *Interp) Execute(node_head *Cnode_t) (Value_t, error) { //v, err = interp.eval_node_child(node.child) v, err = interp.eval_stmt_nodes(&p, node) if err != nil { - return nil, err + goto done } } - return v, nil +done: + // if there is no error, p.cframe must point to the global call frame here. + for p.cframe != nil { + p.pop_call_frame() + } + return v, err } func (interp *Interp) dump_cnodes(node *Cnode_t, nl bool) { diff --git a/interp/proc.go b/interp/proc.go index de625ce..ec97974 100644 --- a/interp/proc.go +++ b/interp/proc.go @@ -69,8 +69,6 @@ func proc_expr(p *process_t) error { func proc_if(p *process_t) error { var ( v Value_t - vv *string - ok bool err error ) @@ -85,11 +83,10 @@ func proc_if(p *process_t) error { goto done } - vv, ok = v.(*string) - if !ok { + if v.Kind != VALUE_STR { panic("internal error - screwed conditional value") } - if *vv != "" { + if *(*string)(v.V) != "" { //v, err = p.interp.eval_atom_node((*Cnode_t)(p.GetArg(1))) v, err = p.interp.eval_arg(p, 1) if err != nil { @@ -110,7 +107,6 @@ func proc_puts(p *process_t) error { i int nargs int v Value_t - vv *string err error ) @@ -126,8 +122,11 @@ func proc_puts(p *process_t) error { return err } - vv, _ = v.(*string) - fmt.Printf("%s", *vv) + // TODO: check if v.kind is VALUE_STR + if v.Kind != VALUE_STR { + panic("internal error... invalid evaluation resutl") + } + fmt.Printf("%s", *(*string)(v.V)) } if nargs >= 1 {