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
}
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()

View File

@ -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
}

View File

@ -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) {

View File

@ -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 {