chagned Value_t to use unsafe.Pointer

This commit is contained in:
hyung-hwan 2023-08-14 01:08:37 +09:00
parent ca5c1efd8a
commit bff0c3b31d
4 changed files with 107 additions and 76 deletions

View File

@ -71,10 +71,10 @@ func main() {
goto oops goto oops
} }
if v == nil { if v.Kind != pcl.VALUE_STR {
panic("return value mut not be nil") 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() interp.Close()
f.Close() f.Close()

View File

@ -2,12 +2,13 @@ package interp
import ( import (
"fmt" "fmt"
"unsafe"
) )
var debug bool = false var debug bool = false
var err_num_args *error_t = &error_t{msg: "wrong number of arguments"} 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) value stack (p.vstack)
@ -31,6 +32,7 @@ func (p *process_t) push_call_frame() {
} else { } else {
cf.parent = p.cframe cf.parent = p.cframe
} }
cf.vars = make(map[string]Value_t)
p.cframe = cf p.cframe = cf
} }
@ -47,7 +49,7 @@ func (p *process_t) push_cnode_value(val *Cnode_t) error {
return fmt.Errorf("stack full") 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.vsp++
p.ctx.count++ p.ctx.count++
//fmt.Printf("push_cnode_value = ctx.count => %d\n", 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") 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.vsp++
p.ctx.count++ p.ctx.count++
//fmt.Printf("push_string_value = ctx.count => %d\n", 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 { func (p *process_t) merge_top_values() error {
var new_val string var new_val string
var v1, v2 *string var v1, v2 Value_t
var ok1, ok2 bool
if p.vsp < 2 { if p.vsp < 2 {
return fmt.Errorf("stack corrupt") return fmt.Errorf("stack corrupt")
} }
v1, ok1 = p.vstack[p.vsp-2].(*string) v1 = p.vstack[p.vsp-2]
v2, ok2 = p.vstack[p.vsp-1].(*string) v2 = p.vstack[p.vsp-1]
if !ok1 { if v1.Kind == VALUE_STR {
// TODO: correct this to get the original text inside{} new_val += *(*string)(v1.V)
// or must panic here by making {} unmergable in the feeder side
v1 = &empty_string
} }
if !ok2 { // TODO: correct this to get the original text inside{}
// TODO: correct this to get the original text inside {} // or must panic here by making {} unmergable in the feeder side
// or must panic here by making {} unmergable in the feeder side if v2.Kind == VALUE_STR {
v2 = &empty_string 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.vsp--
p.vstack[p.vsp] = nil p.vstack[p.vsp].V = unsafe.Pointer(nil)
p.vstack[p.vsp-1] = &new_val p.vstack[p.vsp-1] = Value_t{Kind: VALUE_STR, V: unsafe.Pointer(&new_val)}
p.ctx.count-- p.ctx.count--
if debug { if debug {
@ -106,7 +104,7 @@ func (p *process_t) pop_value() Value_t {
var v Value_t var v Value_t
p.vsp-- p.vsp--
v = p.vstack[p.vsp] v = p.vstack[p.vsp]
p.vstack[p.vsp] = nil p.vstack[p.vsp].V = unsafe.Pointer(nil)
return v return v
} }
@ -145,9 +143,7 @@ func (p *process_t) call() error {
} }
func (p *process_t) GetCalleeName() *string { func (p *process_t) GetCalleeName() *string {
var v *string return (*string)(p.vstack[p.vsp-p.ctx.count+1].V)
v, _ = (p.vstack[p.vsp-p.ctx.count+1]).(*string)
return v
} }
func (p *process_t) GetArg(idx int) Value_t { 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) { 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) { 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??? 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 // clean up the unused part of the stack
for i = 1; i < p.ctx.count; i++ { 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 // pop off the cleaned arguments
@ -217,12 +213,12 @@ func (interp *Interp) dump_vstack(p *process_t) {
// cnode value // cnode value
fmt.Printf(" %d => cnode %p", i, p.vstack[i]) // TODO: strip 1 off fmt.Printf(" %d => cnode %p", i, p.vstack[i]) // TODO: strip 1 off
}*/ }*/
switch t := p.vstack[i].(type) { switch p.vstack[i].Kind {
case *string: case VALUE_STR:
fmt.Printf(" %d => [%s]\n", i, *t) fmt.Printf(" %d => [%s]\n", i, *(*string)(p.vstack[i].V))
case *Cnode_t: case VALUE_CNODE:
fmt.Printf(" %d => ", i) fmt.Printf(" %d => ", i)
interp.dump_cnodes(t, false) interp.dump_cnodes((*Cnode_t)(p.vstack[i].V), false)
fmt.Printf("\n") fmt.Printf("\n")
default: default:
panic("internal error - unrecognized value") 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 org_vsp int
) )
v = new(string) // TODO: change new(string) to a const v = empty_strval
upper_node = container_node upper_node = container_node
stmt_node = upper_node.child // the first statement stmt_node = upper_node.child // the first statement
@ -422,31 +418,18 @@ done:
return v, nil return v, nil
oops: oops:
return nil, err return empty_strval, err
} }
func (interp *Interp) eval_arg(p *process_t, pos int) (Value_t, error) { func (interp *Interp) eval_arg(p *process_t, pos int) (Value_t, error) {
/* var v Value_t
var (
ptr uintptr
)
ptr = uintptr(p.GetArg(pos)) v = p.GetArg(pos)
if ptr&1 == 1 { // cnode switch v.Kind {
ptr &= ^uintptr(1) case VALUE_STR:
//interp.dump_cnodes((*Cnode_t)(unsafe.Pointer(ptr)), true) return v, nil
//return interp.eval_atom_node((*Cnode_t)(unsafe.Pointer(ptr)).child) case VALUE_CNODE:
return interp.eval_stmt_nodes((*Cnode_t)(unsafe.Pointer(ptr))) return interp.eval_stmt_nodes(p, (*Cnode_t)(v.V))
} 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)
default: default:
panic("internal error - argument type unrecognized") 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 return (*string)(unsafe.Pointer(ptr)), nil
}*/ }*/
switch t := p.GetArg(pos).(type) { var v Value_t
case *string:
return t, nil v = p.GetArg(pos)
case *Cnode_t: switch v.Kind {
case VALUE_STR:
return v, nil
case VALUE_CNODE:
// TODO: can support this? by storing the original text? // 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: default:
panic("internal error - argument type unrecognized") panic("internal error - argument type unrecognized")
} }
} }
func (interp *Interp) set_var(p *process_t, name Value_t, val Value_t) error { 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 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) { func (interp *Interp) EvalText(text []rune) (Value_t, error) {
var ( var (
v Value_t v Value_t
@ -517,5 +531,5 @@ func (interp *Interp) EvalText(text []rune) (Value_t, error) {
return v, nil return v, nil
oops: oops:
return nil, err return empty_strval, err
} }

View File

@ -3,6 +3,7 @@ package interp
import ( import (
"fmt" "fmt"
"runtime" "runtime"
"unsafe"
) )
type error_t struct { type error_t struct {
@ -39,7 +40,17 @@ type context_t struct {
container_node *Cnode_t 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 { type process_t struct {
interp *Interp interp *Interp
@ -50,7 +61,7 @@ type process_t struct {
} }
type call_frame_t struct { type call_frame_t struct {
vars *Var vars map[string]Value_t
parent *call_frame_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 = 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 { for node = node_head; node != nil; node = node.next {
if node.code != CNODE_INIT { 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 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_node_child(node.child)
v, err = interp.eval_stmt_nodes(&p, node) v, err = interp.eval_stmt_nodes(&p, node)
if err != nil { 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) { func (interp *Interp) dump_cnodes(node *Cnode_t, nl bool) {

View File

@ -69,8 +69,6 @@ func proc_expr(p *process_t) error {
func proc_if(p *process_t) error { func proc_if(p *process_t) error {
var ( var (
v Value_t v Value_t
vv *string
ok bool
err error err error
) )
@ -85,11 +83,10 @@ func proc_if(p *process_t) error {
goto done goto done
} }
vv, ok = v.(*string) if v.Kind != VALUE_STR {
if !ok {
panic("internal error - screwed conditional value") 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_atom_node((*Cnode_t)(p.GetArg(1)))
v, err = p.interp.eval_arg(p, 1) v, err = p.interp.eval_arg(p, 1)
if err != nil { if err != nil {
@ -110,7 +107,6 @@ func proc_puts(p *process_t) error {
i int i int
nargs int nargs int
v Value_t v Value_t
vv *string
err error err error
) )
@ -126,8 +122,11 @@ func proc_puts(p *process_t) error {
return err return err
} }
vv, _ = v.(*string) // TODO: check if v.kind is VALUE_STR
fmt.Printf("%s", *vv) if v.Kind != VALUE_STR {
panic("internal error... invalid evaluation resutl")
}
fmt.Printf("%s", *(*string)(v.V))
} }
if nargs >= 1 { if nargs >= 1 {