diff --git a/bin/main.go b/bin/main.go index 4c43635..007100b 100644 --- a/bin/main.go +++ b/bin/main.go @@ -16,8 +16,9 @@ func main() { r *bufio.Reader c rune node *pcl.Cnode_t - v *string - err error + v pcl.Value_t + + err error ) if len(os.Args) != 2 { @@ -73,7 +74,7 @@ func main() { if v == nil { panic("return value mut not be nil") } - fmt.Printf("RETURN VALUE = [%s]\n", *v) + fmt.Printf("RETURN VALUE = [%s]\n", *v.(*string)) /* err = interp.FeedRunes([]rune(` diff --git a/interp/eval.go b/interp/eval.go index 50b22c8..25a859d 100644 --- a/interp/eval.go +++ b/interp/eval.go @@ -5,7 +5,7 @@ import ( "unsafe" ) -var debug bool = true +var debug bool = false var err_num_args *error_t = &error_t{msg: "wrong number of arguments"} @@ -26,12 +26,10 @@ func (p *process_t) push_cnode_value(val *Cnode_t) error { return fmt.Errorf("stack full") } - // TODO: using the last bit won't be compatible with go's GC. - // CHANGE to use inteface{} or devise a different scheme... - p.vstack[p.vsp] = unsafe.Pointer(uintptr(unsafe.Pointer(val)) | 1) + p.vstack[p.vsp] = val p.vsp++ 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) return nil } @@ -41,30 +39,38 @@ func (p *process_t) push_string_value(val string) error { return fmt.Errorf("stack full") } - p.vstack[p.vsp] = unsafe.Pointer(&val) + p.vstack[p.vsp] = &val p.vsp++ 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) return nil } func (p *process_t) merge_top_values() error { var new_val string + var v1, v2 *string if p.vsp < 2 { return fmt.Errorf("stack corrupt") } - new_val = *(*string)(p.vstack[p.vsp-2]) + *(*string)(p.vstack[p.vsp-1]) + + v1, _ = p.vstack[p.vsp-2].(*string) + v2, _ = p.vstack[p.vsp-1].(*string) + //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] = unsafe.Pointer(&new_val) p.ctx.count-- - fmt.Printf("merge_top_values = ctx.count => %d\n", p.ctx.count) + + if debug { + fmt.Printf("merge_top_values = ctx.count => %d\n", p.ctx.count) + } return nil } -func (p *process_t) pop_value() unsafe.Pointer { - var v unsafe.Pointer +func (p *process_t) pop_value() Value_t { + var v Value_t p.vsp-- v = p.vstack[p.vsp] p.vstack[p.vsp] = nil @@ -78,6 +84,11 @@ func (p *process_t) call() error { ) callee = p.GetCalleeName() + + if debug { + fmt.Printf("calling..... [%s]\n", *callee) + } + // TODO: use a map switch *callee { case "if": @@ -97,10 +108,12 @@ func (p *process_t) call() error { } func (p *process_t) GetCalleeName() *string { - return (*string)(p.vstack[p.vsp-p.ctx.count+1]) + var v *string + v, _ = (p.vstack[p.vsp-p.ctx.count+1]).(*string) + return v } -func (p *process_t) GetArg(idx int) unsafe.Pointer { +func (p *process_t) GetArg(idx int) Value_t { return (p.vstack[p.vsp-p.ctx.count+2+idx]) } @@ -108,11 +121,14 @@ func (p *process_t) GetNumArgs() int { return p.ctx.count - 2 } -func (p *process_t) Return(val string) { - p.vstack[p.vsp-p.ctx.count] = unsafe.Pointer(&val) +func (p *process_t) Return(val Value_t) { + p.vstack[p.vsp-p.ctx.count] = val } func (p *process_t) push_context(node *Cnode_t, container_node *Cnode_t) { + if debug { + fmt.Printf("PUSHING CONTEXT.....\n") + } p.ctx = &context_t{count: 0, parent_ctx: p.ctx, parent_node: node, container_node: container_node} } @@ -123,6 +139,10 @@ func (p *process_t) pop_context(clear_vstack bool) (*Cnode_t, *Cnode_t) { container *Cnode_t ) + if debug { + fmt.Printf("POPPING CONTEXT.....is_stmt/clear_vstack[%v]\n", clear_vstack) + } + node = p.ctx.parent_node container = p.ctx.container_node @@ -137,9 +157,9 @@ func (p *process_t) pop_context(clear_vstack bool) (*Cnode_t, *Cnode_t) { } p.ctx = p.ctx.parent_ctx -// if p.ctx != nil { -// p.ctx.count++ // let the return value be the argument to the caller -// } + // if p.ctx != nil { + // p.ctx.count++ // let the return value be the argument to the caller + // } return node, container } @@ -147,13 +167,24 @@ func (p *process_t) pop_context(clear_vstack bool) (*Cnode_t, *Cnode_t) { func (interp *Interp) dump_vstack(p *process_t) { fmt.Printf("p.VSP => %d\n", p.vsp) for i := 0; i < p.vsp; i++ { - x := uintptr(p.vstack[i]) - if x&1 == 0 { - // string value - fmt.Printf(" %d => [%s]\n", i, *(*string)(p.vstack[i])) - } else { - // cnode value - fmt.Printf(" %d => cnode %p", i, p.vstack[i]) // TODO: strip 1 off + /* + x := uintptr(p.vstack[i]) + if x&1 == 0 { + // string value + fmt.Printf(" %d => [%s]\n", i, *(*string)(p.vstack[i])) + } else { + // 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: + fmt.Printf(" %d => ", i) + interp.dump_cnodes(t, false) + fmt.Printf("\n") + default: + panic("internal error - unrecognized value") } } } @@ -182,15 +213,16 @@ puts "hello" world [STMT] [TEXT|null] [TEXT|1] */ -func (interp *Interp) eval_stmt_nodes(container_node *Cnode_t) (*string, error) { +func (interp *Interp) eval_stmt_nodes(container_node *Cnode_t) (Value_t, error) { var ( p process_t - v *string + v Value_t stmt_node *Cnode_t upper_node *Cnode_t inner_node *Cnode_t is_stmt bool err error + org_vsp int ) v = new(string) // TODO: change new(string) to a const @@ -199,19 +231,22 @@ func (interp *Interp) eval_stmt_nodes(container_node *Cnode_t) (*string, error) upper_node = container_node stmt_node = upper_node.child // the first statement + org_vsp = p.vsp fmt.Printf("START p.sp = %d\n", p.vsp) - for stmt_node != nil { + if stmt_node == nil { + goto done + } + + for { start_over_0: if stmt_node.code != CNODE_STMT { panic("internal error - not statement node") } - fmt.Printf("PUSHING CONTEXT.....\n") p.push_context(stmt_node, upper_node) p.push_string_value("") // placeholder for return value - //start_over: inner_node = stmt_node.child resume: for inner_node != nil { @@ -235,7 +270,6 @@ func (interp *Interp) eval_stmt_nodes(container_node *Cnode_t) (*string, error) case CNODE_DQUOTE: if inner_node.child != nil { - fmt.Printf("PUSHING CONTEXT.....\n") p.push_context(stmt_node, inner_node) //p.push_string_value("") // no placeholder for return value is needed inner_node = inner_node.child @@ -264,6 +298,9 @@ func (interp *Interp) eval_stmt_nodes(container_node *Cnode_t) (*string, error) // TODO: many more types... case CNODE_JOIN: p.merge_top_values() + + case CNODE_INIT: + panic("internal error - INIT node must not appear inside a statement") } inner_node = inner_node.next @@ -273,10 +310,7 @@ func (interp *Interp) eval_stmt_nodes(container_node *Cnode_t) (*string, error) interp.dump_vstack(&p) } //fmt.Printf("p.ctx.parent_node.code %d p.ctx.container_node.code %d CNODE_STMT %d CNODE_DQUOTE %d CNODE_BRACKET %d\n", p.ctx.parent_node.code, p.ctx.container_node.code, CNODE_STMT, CNODE_DQUOTE, CNODE_BRACKET) - if p.ctx.container_node.code == CNODE_INIT || p.ctx.container_node.code == CNODE_BRACKET { - if debug { - fmt.Printf("calling..... [%s]\n", *p.GetCalleeName()) - } + if p.ctx.container_node.code == CNODE_INIT || p.ctx.container_node.code == CNODE_BRACKET || p.ctx.container_node.code == CNODE_BRACE { err = p.call() if err != nil { goto oops @@ -287,7 +321,6 @@ func (interp *Interp) eval_stmt_nodes(container_node *Cnode_t) (*string, error) is_stmt = false } - fmt.Printf("POPPING CONTEXT.....is_stmt[%v]\n", is_stmt) stmt_node, upper_node = p.pop_context(is_stmt) if upper_node != container_node { if debug { @@ -296,7 +329,7 @@ func (interp *Interp) eval_stmt_nodes(container_node *Cnode_t) (*string, error) if upper_node.code != CNODE_BRACKET { inner_node = upper_node.next // as if it hit the bottom of the innner for loop - p.ctx.count++; // use return value on the stack as an argument + p.ctx.count++ // use return value on the stack as an argument goto resume } } @@ -317,76 +350,100 @@ func (interp *Interp) eval_stmt_nodes(container_node *Cnode_t) (*string, error) if upper_node.code != CNODE_BRACKET { panic("internal error - invalid cnode type in the context statck") } - fmt.Printf("POPPING CONTEXT.....false\n") - //stmt_node, upper_node = p.pop_context(false) - inner_node = upper_node.next - fmt.Printf(">>>>>>>>>>>>>>>>>> vsp %d ctx.count %d\n", p.vsp, p.ctx.count) - p.ctx.count++; // use the result value as an argument + inner_node = upper_node.next + //fmt.Printf(">>>>>>>>>>>>>>>>>> vsp %d ctx.count %d\n", p.vsp, p.ctx.count) + + p.ctx.count++ // use the result value as an argument goto resume } - fmt.Printf("POPVAL...\n") - v = (*string)(p.pop_value()) // get the return value of the statement. + v = p.pop_value() // get the return value of the statement. if debug { interp.dump_vstack(&p) } break } - fmt.Printf("POPVAL...\n") - v = (*string)(p.pop_value()) // get the return value of the statement. + v = p.pop_value() // get the return value of the statement. if debug { interp.dump_vstack(&p) } } +done: + if debug { interp.dump_vstack(&p) fmt.Printf("END p.sp = %d\n", p.vsp) } + if p.vsp != org_vsp { + panic("internal error - stack not clean") + } return v, nil oops: return nil, err } -func (interp *Interp) eval_arg(p *process_t, pos int) (*string, error) { - var ( - ptr uintptr - ) +func (interp *Interp) eval_arg(p *process_t, pos int) (Value_t, error) { + /* + var ( + ptr uintptr + ) - 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 + 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(t) + default: + panic("internal error - argument type unrecognized") } } -func (interp *Interp) eval_arg_literally(p *process_t, pos int) (*string, error) { - var ( - ptr uintptr - //cnode *Cnode_t - ) +func (interp *Interp) eval_arg_literally(p *process_t, pos int) (Value_t, error) { + /* + var ( + ptr uintptr + //cnode *Cnode_t + ) - ptr = uintptr(p.GetArg(pos)) - if ptr&1 == 1 { // cnode - ptr &= ^uintptr(1) - //cnode = (*Cnode_t)(unsafe.Pointer(ptr)) - //cnode.child i hate this portion.... + ptr = uintptr(p.GetArg(pos)) + if ptr&1 == 1 { // cnode + ptr &= ^uintptr(1) + //cnode = (*Cnode_t)(unsafe.Pointer(ptr)) + //cnode.child i hate this portion.... + return nil, fmt.Errorf("not supported - unable to evaluate {} literally") + } else { + return (*string)(unsafe.Pointer(ptr)), nil + }*/ + + switch t := p.GetArg(pos).(type) { + case *string: + return t, nil + case *Cnode_t: + // TODO: can support this? by storing the original text? return nil, fmt.Errorf("not supported - unable to evaluate {} literally") - } else { - return (*string)(unsafe.Pointer(ptr)), nil + default: + panic("internal error - argument type unrecognized") } } -func (interp *Interp) EvalText(text []rune) (*string, error) { +func (interp *Interp) EvalText(text []rune) (Value_t, error) { var ( - v *string + v Value_t node *Cnode_t err error ) diff --git a/interp/pcl.go b/interp/pcl.go index bdfa6ef..72b205a 100644 --- a/interp/pcl.go +++ b/interp/pcl.go @@ -3,7 +3,6 @@ package interp import ( "fmt" "runtime" - "unsafe" ) type error_t struct { @@ -40,9 +39,11 @@ type context_t struct { container_node *Cnode_t } +type Value_t interface{} + type process_t struct { interp *Interp - vstack [16]unsafe.Pointer // value stack - TODO: change size + vstack [16]Value_t // value stack - TODO: change size vsp int ctx *context_t } @@ -227,11 +228,11 @@ func get_top_call_frame(f *CallFrame) *CallFrame { } */ -func (interp *Interp) Execute(node_head *Cnode_t) (*string, error) { +func (interp *Interp) Execute(node_head *Cnode_t) (Value_t, error) { var ( node *Cnode_t - v *string + v Value_t err error ) diff --git a/interp/proc.go b/interp/proc.go index c216141..16a3960 100644 --- a/interp/proc.go +++ b/interp/proc.go @@ -9,7 +9,9 @@ func proc_expr(p *process_t) error { func proc_if(p *process_t) error { var ( - v *string + v Value_t + vv *string + ok bool err error ) @@ -24,14 +26,18 @@ func proc_if(p *process_t) error { goto done } - if *v != "" { + vv, ok = v.(*string) + if !ok { + panic("internal error - screwed conditional value") + } + if *vv != "" { //v, err = p.interp.eval_atom_node((*Cnode_t)(p.GetArg(1))) v, err = p.interp.eval_arg(p, 1) if err != nil { goto done } - p.Return(*v) + p.Return(v) } else { // TODO: if elseif else } @@ -44,7 +50,8 @@ func proc_puts(p *process_t) error { var ( i int nargs int - v *string + v Value_t + vv *string err error ) @@ -59,11 +66,13 @@ func proc_puts(p *process_t) error { if err != nil { return err } - fmt.Printf("%s", *v) + + vv, _ = v.(*string) + fmt.Printf("%s", *vv) } if nargs >= 1 { - p.Return(*v) + p.Return(v) } else { p.Return("hello") }