Compare commits
6 Commits
85a6092363
...
1ad6779aa4
Author | SHA1 | Date | |
---|---|---|---|
1ad6779aa4 | |||
9481de61d5 | |||
1945452429 | |||
fab6ab5595 | |||
cb130353ce | |||
379a6e5030 |
396
interp/eval.go
396
interp/eval.go
@ -5,12 +5,14 @@ import (
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
var debug bool = true
|
||||
|
||||
var err_num_args *error_t = &error_t{msg: "wrong number of arguments"}
|
||||
|
||||
/*
|
||||
value stack (p.stack)
|
||||
value stack (p.vstack)
|
||||
|
||||
<--- SP
|
||||
<--- SP (p.vsp)
|
||||
ARG1
|
||||
ARG0
|
||||
NAME
|
||||
@ -20,48 +22,52 @@ var err_num_args *error_t = &error_t{msg: "wrong number of arguments"}
|
||||
*/
|
||||
|
||||
func (p *process_t) push_cnode_value(val *Cnode_t) error {
|
||||
if p.sp >= cap(p.stack) {
|
||||
if p.vsp >= cap(p.vstack) {
|
||||
return fmt.Errorf("stack full")
|
||||
}
|
||||
|
||||
p.stack[p.sp] = unsafe.Pointer(uintptr(unsafe.Pointer(val)) | 1)
|
||||
p.sp++
|
||||
// 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.vsp++
|
||||
p.ctx.count++
|
||||
fmt.Printf("push_cnode_value = ctx.count => %d\n", p.ctx.count)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *process_t) push_string_value(val string) error {
|
||||
if p.sp >= cap(p.stack) {
|
||||
if p.vsp >= cap(p.vstack) {
|
||||
return fmt.Errorf("stack full")
|
||||
}
|
||||
|
||||
p.stack[p.sp] = unsafe.Pointer(&val)
|
||||
p.sp++
|
||||
p.vstack[p.vsp] = unsafe.Pointer(&val)
|
||||
p.vsp++
|
||||
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
|
||||
|
||||
if p.sp < 2 {
|
||||
if p.vsp < 2 {
|
||||
return fmt.Errorf("stack corrupt")
|
||||
}
|
||||
new_val = *(*string)(p.stack[p.sp-2]) + *(*string)(p.stack[p.sp-1])
|
||||
p.sp--
|
||||
p.stack[p.sp] = nil
|
||||
p.stack[p.sp-1] = unsafe.Pointer(&new_val)
|
||||
new_val = *(*string)(p.vstack[p.vsp-2]) + *(*string)(p.vstack[p.vsp-1])
|
||||
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)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *process_t) pop_value() unsafe.Pointer {
|
||||
var v unsafe.Pointer
|
||||
p.sp--
|
||||
v = p.stack[p.sp]
|
||||
p.stack[p.sp] = nil
|
||||
p.vsp--
|
||||
v = p.vstack[p.vsp]
|
||||
p.vstack[p.vsp] = nil
|
||||
return v
|
||||
}
|
||||
|
||||
@ -78,6 +84,12 @@ func (p *process_t) call() error {
|
||||
proc = proc_if
|
||||
case "puts":
|
||||
proc = proc_puts
|
||||
case "true":
|
||||
proc = proc_true
|
||||
case "false":
|
||||
proc = proc_false
|
||||
case "null":
|
||||
proc = proc_null
|
||||
default:
|
||||
proc = proc_unknown
|
||||
}
|
||||
@ -85,11 +97,11 @@ func (p *process_t) call() error {
|
||||
}
|
||||
|
||||
func (p *process_t) GetCalleeName() *string {
|
||||
return (*string)(p.stack[p.sp-p.ctx.count+1])
|
||||
return (*string)(p.vstack[p.vsp-p.ctx.count+1])
|
||||
}
|
||||
|
||||
func (p *process_t) GetArg(idx int) unsafe.Pointer {
|
||||
return (p.stack[p.sp-p.ctx.count+2+idx])
|
||||
return (p.vstack[p.vsp-p.ctx.count+2+idx])
|
||||
}
|
||||
|
||||
func (p *process_t) GetNumArgs() int {
|
||||
@ -97,199 +109,242 @@ func (p *process_t) GetNumArgs() int {
|
||||
}
|
||||
|
||||
func (p *process_t) Return(val string) {
|
||||
p.stack[p.sp-p.ctx.count] = unsafe.Pointer(&val)
|
||||
p.vstack[p.vsp-p.ctx.count] = unsafe.Pointer(&val)
|
||||
}
|
||||
|
||||
func (p *process_t) push_context(node *Cnode_t) {
|
||||
p.ctx = &context_t{count: 0, parent_ctx: p.ctx, parent_node: node}
|
||||
func (p *process_t) push_context(node *Cnode_t, container_node *Cnode_t) {
|
||||
p.ctx = &context_t{count: 0, parent_ctx: p.ctx, parent_node: node, container_node: container_node}
|
||||
}
|
||||
|
||||
func (p *process_t) pop_context() (node *Cnode_t) {
|
||||
var i int
|
||||
func (p *process_t) pop_context(clear_vstack bool) (*Cnode_t, *Cnode_t) {
|
||||
var (
|
||||
i int
|
||||
node *Cnode_t
|
||||
container *Cnode_t
|
||||
)
|
||||
|
||||
node = p.ctx.parent_node
|
||||
container = p.ctx.container_node
|
||||
|
||||
// clean up the unused part of the stack
|
||||
for i = 1; i < p.ctx.count; i++ {
|
||||
p.stack[p.sp-p.ctx.count+i] = nil
|
||||
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
|
||||
}
|
||||
|
||||
// pop off the cleaned arguments
|
||||
p.vsp -= p.ctx.count - 1 // keep the return value in the stack
|
||||
}
|
||||
|
||||
// pop off the cleaned arguments
|
||||
p.sp -= p.ctx.count - 1 // keep the return value in the stack
|
||||
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
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
stmt
|
||||
puts "hello" world
|
||||
|
||||
text text bracket
|
||||
stmt: text text
|
||||
stmt: text TEXT
|
||||
[STMT]
|
||||
[TEXT|puts] [DQUOTE] [TEXT|world]
|
||||
[TEXT|hello]
|
||||
|
||||
[puts 1 2; puts 1] 999
|
||||
|
||||
[STMT]
|
||||
[BRACKET] [TEXT|999]
|
||||
[STMT]
|
||||
[TEXT|puts] [TEXT|1] [TEXT|2]
|
||||
[STMT]
|
||||
[TEXT|puts] [TEXT|1]
|
||||
|
||||
"pu[null 1]ts" 10 20
|
||||
|
||||
[STMT]
|
||||
[DQUOTE] [TEXT|10] [TEXT|20]
|
||||
[TEXT|pu] [BRACKET] [JOIN] [TEXT|ts] [JOIN]
|
||||
[STMT]
|
||||
[TEXT|null] [TEXT|1]
|
||||
*/
|
||||
func (interp *Interp) eval_atom_node(node *Cnode_t) (*string, error) {
|
||||
func (interp *Interp) eval_stmt_nodes(container_node *Cnode_t) (*string, error) {
|
||||
var (
|
||||
p process_t
|
||||
v *string
|
||||
inode *Cnode_t
|
||||
err error
|
||||
p process_t
|
||||
v *string
|
||||
stmt_node *Cnode_t
|
||||
upper_node *Cnode_t
|
||||
inner_node *Cnode_t
|
||||
is_stmt bool
|
||||
err error
|
||||
)
|
||||
|
||||
p.interp = interp
|
||||
v = new(string) // TODO: change new(string) to a const
|
||||
|
||||
for node != nil {
|
||||
p.push_context(node)
|
||||
p.interp = interp
|
||||
upper_node = container_node
|
||||
stmt_node = upper_node.child // the first statement
|
||||
|
||||
fmt.Printf("START p.sp = %d\n", p.vsp)
|
||||
|
||||
for stmt_node != nil {
|
||||
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
|
||||
|
||||
for inode = node.child; inode != nil; inode = inode.next {
|
||||
switch inode.code {
|
||||
//start_over:
|
||||
inner_node = stmt_node.child
|
||||
resume:
|
||||
for inner_node != nil {
|
||||
//fmt.Printf("handling %d\n", inner_node.code)
|
||||
switch inner_node.code {
|
||||
case CNODE_BRACKET:
|
||||
//p.push_context(inode)
|
||||
//p.push_string_value("")
|
||||
//node =
|
||||
if inner_node.child != nil {
|
||||
upper_node = inner_node
|
||||
stmt_node = upper_node.child
|
||||
if debug {
|
||||
fmt.Printf("going to start over\n")
|
||||
interp.dump_cnodes(stmt_node, true)
|
||||
fmt.Printf("\n--\n")
|
||||
}
|
||||
goto start_over_0
|
||||
|
||||
} else {
|
||||
// no statements inside []. treat it like an empty string
|
||||
p.push_string_value("")
|
||||
}
|
||||
|
||||
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
|
||||
if debug {
|
||||
fmt.Printf("going to start over\n")
|
||||
interp.dump_cnodes(stmt_node, true)
|
||||
fmt.Printf("\n--\n")
|
||||
}
|
||||
goto resume
|
||||
} else {
|
||||
// no statements inside []. treat it like an empty string
|
||||
p.push_string_value("")
|
||||
}
|
||||
|
||||
case CNODE_BRACE:
|
||||
p.push_cnode_value(inner_node)
|
||||
|
||||
case CNODE_TEXT:
|
||||
|
||||
//fmt.Printf("XXXXXXXXXXXXXXXXXXXx[%s]\n", string(inode.token))
|
||||
err = p.push_string_value(string(inode.token))
|
||||
//fmt.Printf("XXXXXXXXXXXXXXXXXXXx[%s]\n", string(inner_node.token))
|
||||
err = p.push_string_value(string(inner_node.token))
|
||||
if err != nil {
|
||||
goto oops
|
||||
}
|
||||
|
||||
// TODO: many more types...
|
||||
case CNODE_JOIN:
|
||||
p.merge_top_values()
|
||||
}
|
||||
|
||||
inner_node = inner_node.next
|
||||
}
|
||||
|
||||
fmt.Printf("CALLING\n")
|
||||
err = p.call()
|
||||
if err != nil {
|
||||
goto oops
|
||||
if debug {
|
||||
interp.dump_vstack(&p)
|
||||
}
|
||||
if p.ctx.parent_ctx != nil {
|
||||
p.pop_context()
|
||||
}
|
||||
|
||||
node = node.next
|
||||
}
|
||||
|
||||
v = (*string)(p.pop_value())
|
||||
p.pop_context()
|
||||
if p.ctx != nil {
|
||||
err = fmt.Errorf("internal error - dangling process context")
|
||||
goto oops
|
||||
}
|
||||
|
||||
return v, nil
|
||||
|
||||
oops:
|
||||
return nil, err
|
||||
}
|
||||
|
||||
func (interp *Interp) eval_atom_node_old(node *Cnode_t) (*string, error) {
|
||||
|
||||
var (
|
||||
p process_t
|
||||
v *string
|
||||
err error
|
||||
)
|
||||
|
||||
p.interp = interp
|
||||
p.push_context(nil)
|
||||
p.push_string_value("") // placeholder for return value
|
||||
|
||||
for node != nil {
|
||||
switch node.code {
|
||||
case CNODE_BRACKET: // this is a container
|
||||
if node.child != nil {
|
||||
p.push_context(node)
|
||||
err = p.push_string_value("") // placeholder for return value
|
||||
if err != nil {
|
||||
goto oops
|
||||
}
|
||||
node = node.child
|
||||
continue
|
||||
} else {
|
||||
err = p.push_string_value("")
|
||||
if err != nil {
|
||||
goto oops
|
||||
}
|
||||
//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())
|
||||
}
|
||||
|
||||
case CNODE_BRACE: // this is a container
|
||||
err = p.push_cnode_value(node)
|
||||
if err != nil {
|
||||
goto oops
|
||||
}
|
||||
|
||||
case CNODE_DQUOTE: // this is a container
|
||||
// TODO: at the feed layer, recompose CNODE_DQUOTE item to
|
||||
// successive ATOM item
|
||||
// "abc $ddd [xx 11]" must be TEXT("abc ") + VAR("ddd") + BRACKET["xx 11"] without SEP in between
|
||||
|
||||
// this is not right.....
|
||||
if node.child != nil {
|
||||
// TODO: something is not right here. handle inner stuffs
|
||||
//fmt.Printf("pushing [%s]\n", string(node.child.token))
|
||||
err = p.push_string_value(string(node.child.token))
|
||||
} else {
|
||||
err = p.push_string_value("")
|
||||
}
|
||||
if err != nil {
|
||||
goto oops
|
||||
}
|
||||
|
||||
case CNODE_VAR:
|
||||
|
||||
case CNODE_TEXT:
|
||||
//fmt.Printf("pushing [%s]\n", string(node.token))
|
||||
err = p.push_string_value(string(node.token))
|
||||
if err != nil {
|
||||
goto oops
|
||||
}
|
||||
|
||||
default:
|
||||
err = fmt.Errorf("internal error - non-atom node - %d", node.code)
|
||||
goto oops
|
||||
}
|
||||
|
||||
node = node.next
|
||||
check_end:
|
||||
if node == nil { // reached the last node
|
||||
err = p.call()
|
||||
if err != nil {
|
||||
goto oops
|
||||
}
|
||||
if p.ctx.parent_ctx != nil {
|
||||
node = p.pop_context()
|
||||
if node.seqno > 0 {
|
||||
// merge the top 2 values (return from [] + previous argument)
|
||||
// for instance, the expression `aa[qq 11]` must product a single word
|
||||
// `aa` concatenated of the result of `qq 11`
|
||||
err = p.merge_top_values()
|
||||
if err != nil {
|
||||
goto oops
|
||||
}
|
||||
}
|
||||
node = node.next
|
||||
|
||||
// take `aa 11 22 [dd [bb cc]]` as an example
|
||||
// after [bb cc] is called, it must call `[dd]`` followed by `aa`.
|
||||
// this goto loop is to handle successive calls when a nested call is the
|
||||
// last argument
|
||||
goto check_end
|
||||
is_stmt = true
|
||||
} else {
|
||||
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 {
|
||||
fmt.Printf("resuming... %d upper_node.next %p\n", p.vsp, upper_node.next)
|
||||
}
|
||||
|
||||
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
|
||||
goto resume
|
||||
}
|
||||
}
|
||||
|
||||
//fmt.Printf("POPPING VALUE...\n")
|
||||
/*v = (*string)(p.pop_value()) // get the return value of the statement.
|
||||
if debug {
|
||||
interp.dump_vstack(&p)
|
||||
}*/
|
||||
stmt_node = stmt_node.next
|
||||
|
||||
if stmt_node == nil {
|
||||
// go doesn't allow jumping into a block.
|
||||
// let's the put the code here
|
||||
if upper_node != container_node {
|
||||
// the upper node is not the top containing node passed to this function.
|
||||
// the contenxt stack must not be empty in this case.
|
||||
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
|
||||
goto resume
|
||||
}
|
||||
|
||||
fmt.Printf("POPVAL...\n")
|
||||
v = (*string)(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.
|
||||
if debug {
|
||||
interp.dump_vstack(&p)
|
||||
}
|
||||
}
|
||||
|
||||
v = (*string)(p.pop_value())
|
||||
p.pop_context()
|
||||
if p.ctx != nil {
|
||||
err = fmt.Errorf("internal error - dangling process context")
|
||||
goto oops
|
||||
if debug {
|
||||
interp.dump_vstack(&p)
|
||||
fmt.Printf("END p.sp = %d\n", p.vsp)
|
||||
}
|
||||
|
||||
return v, nil
|
||||
|
||||
oops:
|
||||
@ -304,8 +359,9 @@ func (interp *Interp) eval_arg(p *process_t, pos int) (*string, error) {
|
||||
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)
|
||||
//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
|
||||
}
|
||||
|
@ -34,15 +34,16 @@ const NULL_RUNE rune = '\u0000'
|
||||
const EOF_RUNE rune = rune(^0)
|
||||
|
||||
type context_t struct {
|
||||
count int
|
||||
parent_ctx *context_t
|
||||
parent_node *Cnode_t
|
||||
count int
|
||||
parent_ctx *context_t
|
||||
parent_node *Cnode_t
|
||||
container_node *Cnode_t
|
||||
}
|
||||
|
||||
type process_t struct {
|
||||
interp *Interp
|
||||
stack [16]unsafe.Pointer // value stack - TODO: change size
|
||||
sp int
|
||||
vstack [16]unsafe.Pointer // value stack - TODO: change size
|
||||
vsp int
|
||||
ctx *context_t
|
||||
}
|
||||
|
||||
@ -245,7 +246,8 @@ func (interp *Interp) Execute(node_head *Cnode_t) (*string, error) {
|
||||
break
|
||||
}
|
||||
|
||||
v, err = interp.eval_atom_node(node.child)
|
||||
//v, err = interp.eval_node_child(node.child)
|
||||
v, err = interp.eval_stmt_nodes(node)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -70,6 +70,20 @@ func proc_puts(p *process_t) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func proc_false(p *process_t) error {
|
||||
p.Return("false")
|
||||
return nil
|
||||
}
|
||||
func proc_true(p *process_t) error {
|
||||
p.Return("true")
|
||||
return nil
|
||||
}
|
||||
|
||||
func proc_null(p *process_t) error {
|
||||
p.Return("")
|
||||
return nil
|
||||
}
|
||||
|
||||
func proc_unknown(p *process_t) error {
|
||||
fmt.Printf("Unknown command - %s\n", *(p.GetCalleeName()))
|
||||
return nil
|
||||
|
Loading…
Reference in New Issue
Block a user