Compare commits

...

4 Commits

Author SHA1 Message Date
chunghh
85a6092363 added the debug variable for easy toggling of debug messages 2023-08-03 00:56:42 +09:00
chunghh
760f9a7114 a bit of evaluator implentation work 2023-08-03 00:46:06 +09:00
c1f7c4b963 implementing the evaluator 2023-07-26 11:35:12 +09:00
chunghh
5d66a2e6d7 updating evaluator code 2023-07-22 00:56:04 +09:00
3 changed files with 205 additions and 70 deletions

View File

@ -5,12 +5,14 @@ import (
"unsafe" "unsafe"
) )
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"}
/* /*
value stack (p.stack) value stack (p.vstack)
<--- SP <--- SP (p.vsp)
ARG1 ARG1
ARG0 ARG0
NAME NAME
@ -20,24 +22,26 @@ var err_num_args *error_t = &error_t{msg: "wrong number of arguments"}
*/ */
func (p *process_t) push_cnode_value(val *Cnode_t) error { 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") return fmt.Errorf("stack full")
} }
p.stack[p.sp] = unsafe.Pointer(uintptr(unsafe.Pointer(val)) | 1) // TODO: using the last bit won't be compatible with go's GC.
p.sp++ // 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++ p.ctx.count++
return nil return nil
} }
func (p *process_t) push_string_value(val string) error { 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") return fmt.Errorf("stack full")
} }
p.stack[p.sp] = unsafe.Pointer(&val) p.vstack[p.vsp] = unsafe.Pointer(&val)
p.sp++ p.vsp++
p.ctx.count++ p.ctx.count++
return nil return nil
@ -46,22 +50,22 @@ 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
if p.sp < 2 { if p.vsp < 2 {
return fmt.Errorf("stack corrupt") return fmt.Errorf("stack corrupt")
} }
new_val = *(*string)(p.stack[p.sp-2]) + *(*string)(p.stack[p.sp-1]) new_val = *(*string)(p.vstack[p.vsp-2]) + *(*string)(p.vstack[p.vsp-1])
p.sp-- p.vsp--
p.stack[p.sp] = nil p.vstack[p.vsp] = nil
p.stack[p.sp-1] = unsafe.Pointer(&new_val) p.vstack[p.vsp-1] = unsafe.Pointer(&new_val)
p.ctx.count-- p.ctx.count--
return nil return nil
} }
func (p *process_t) pop_value() unsafe.Pointer { func (p *process_t) pop_value() unsafe.Pointer {
var v unsafe.Pointer var v unsafe.Pointer
p.sp-- p.vsp--
v = p.stack[p.sp] v = p.vstack[p.vsp]
p.stack[p.sp] = nil p.vstack[p.vsp] = nil
return v return v
} }
@ -78,6 +82,12 @@ func (p *process_t) call() error {
proc = proc_if proc = proc_if
case "puts": case "puts":
proc = proc_puts proc = proc_puts
case "true":
proc = proc_true
case "false":
proc = proc_false
case "null":
proc = proc_null
default: default:
proc = proc_unknown proc = proc_unknown
} }
@ -85,11 +95,11 @@ func (p *process_t) call() error {
} }
func (p *process_t) GetCalleeName() *string { 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 { 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 { func (p *process_t) GetNumArgs() int {
@ -97,96 +107,203 @@ func (p *process_t) GetNumArgs() int {
} }
func (p *process_t) Return(val string) { 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) { 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} 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) { func (p *process_t) pop_context(clear_vstack bool) (*Cnode_t, *Cnode_t) {
var i int var (
i int
node *Cnode_t
container *Cnode_t
)
node = p.ctx.parent_node node = p.ctx.parent_node
container = p.ctx.container_node
// clean up the unused part of the stack if clear_vstack {
for i = 1; i < p.ctx.count; i++ { // clean up the unused part of the stack
p.stack[p.sp-p.ctx.count+i] = nil 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 p.ctx = p.ctx.parent_ctx
if p.ctx != nil { if p.ctx != nil {
p.ctx.count++ // let the return value be the argument to the caller p.ctx.count++ // let the return value be the argument to the caller
} }
return
return node, container
}
func (interp *Interp) dump_vstack(p *process_t) {
//fmt.Printf("DDDDDDDDDDDDBVVVVVVVVVVVDDDd\n")
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
}
}
} }
/* /*
stmt [STMT]
[TEXT] [DQUOTE] [TEXT]
text text bracket [STMT]
stmt: text text [BRACKET] [TEXT]
stmt: text TEXT [STMT]
[TEXT] [TEXT] [TEXT]
[STMT]
[TEXT] [TEXT]
"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 ( var (
p process_t p process_t
v *string v *string
inode *Cnode_t stmt_node *Cnode_t
err error inner_node *Cnode_t
err error
) )
p.interp = interp v = new(string) // TODO: change new(string) to a const
for node != nil { p.interp = interp
p.push_context(node) stmt_node = container_node.child // the first statement
//interp.dump_cnodes(container_node, true)
//fmt.Printf("--------------\n")
//interp.dump_cnodes(stmt_node, true)
//fmt.Printf("--------------\n")
fmt.Printf("START p.sp = %d\n", p.vsp)
for stmt_node != nil {
if stmt_node.code != CNODE_STMT {
panic("internal error - not statement node")
}
p.push_context(stmt_node, nil)
p.push_string_value("") // placeholder for return value p.push_string_value("") // placeholder for return value
for inode = node.child; inode != nil; inode = inode.next { start_over:
switch inode.code { 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: case CNODE_BRACKET:
//p.push_context(inode) if inner_node.child != nil {
//p.push_string_value("") stmt_node = inner_node.child // first statement inside []
//node = p.push_context(stmt_node, inner_node)
p.push_string_value("") // for return value
if debug {
fmt.Printf("going to start over\n")
interp.dump_cnodes(stmt_node, true)
fmt.Printf("\n--\n")
}
goto start_over
} else {
// no statements inside []. treat it like an empty string
p.push_string_value("")
}
case CNODE_DQUOTE:
if inner_node.child != nil {
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: case CNODE_TEXT:
//fmt.Printf("XXXXXXXXXXXXXXXXXXXx[%s]\n", string(inode.token)) //fmt.Printf("XXXXXXXXXXXXXXXXXXXx[%s]\n", string(inner_node.token))
err = p.push_string_value(string(inode.token)) err = p.push_string_value(string(inner_node.token))
if err != nil { if err != nil {
goto oops goto oops
} }
// TODO: many more types...
case CNODE_JOIN:
//fmt.Printf("JOIN>>>>>\n")
p.merge_top_values()
} }
inner_node = inner_node.next
} }
fmt.Printf("CALLING\n") if debug {
err = p.call() interp.dump_vstack(&p)
if err != nil {
goto oops
} }
if p.ctx.parent_ctx != nil { //fmt.Printf("p.ctx.parent_node.code %d p.ctx.container_node.code %d CNODE_STMT %d CNODE_DQUOTE %d\n", p.ctx.parent_node.code, p.ctx.container_node.code, CNODE_STMT, CNODE_DQUOTE)
p.pop_context() //if p.ctx.parent_node.code == CNODE_STMT {
if p.ctx.container_node == nil || (p.ctx.container_node.code == CNODE_STMT || p.ctx.container_node.code == CNODE_BRACKET) {
if debug {
fmt.Printf("calling..... [%s]\n", *p.GetCalleeName())
}
err = p.call()
if err != nil {
goto oops
}
stmt_node, inner_node = p.pop_context(true)
} else {
stmt_node, inner_node = p.pop_context(false)
} }
node = node.next if inner_node != nil {
if debug {
fmt.Printf("resuming... %d\n", p.vsp)
}
inner_node = inner_node.next
goto resume
}
v = (*string)(p.pop_value()) // get the return value of the statement.
stmt_node = stmt_node.next
} }
v = (*string)(p.pop_value()) if debug {
p.pop_context() interp.dump_vstack(&p)
if p.ctx != nil { fmt.Printf("END p.sp = %d\n", p.vsp)
err = fmt.Errorf("internal error - dangling process context")
goto oops
} }
return v, nil return v, nil
oops: oops:
return nil, err return nil, err
} }
/*
func (interp *Interp) eval_atom_node_old(node *Cnode_t) (*string, error) { func (interp *Interp) eval_atom_node_old(node *Cnode_t) (*string, error) {
var ( var (
@ -295,6 +412,7 @@ func (interp *Interp) eval_atom_node_old(node *Cnode_t) (*string, error) {
oops: oops:
return nil, err return nil, err
} }
*/
func (interp *Interp) eval_arg(p *process_t, pos int) (*string, error) { func (interp *Interp) eval_arg(p *process_t, pos int) (*string, error) {
var ( var (
@ -304,8 +422,9 @@ func (interp *Interp) eval_arg(p *process_t, pos int) (*string, error) {
ptr = uintptr(p.GetArg(pos)) ptr = uintptr(p.GetArg(pos))
if ptr&1 == 1 { // cnode if ptr&1 == 1 { // cnode
ptr &= ^uintptr(1) ptr &= ^uintptr(1)
interp.dump_cnodes((*Cnode_t)(unsafe.Pointer(ptr)), true) //interp.dump_cnodes((*Cnode_t)(unsafe.Pointer(ptr)), true)
return interp.eval_atom_node((*Cnode_t)(unsafe.Pointer(ptr)).child) //return interp.eval_atom_node((*Cnode_t)(unsafe.Pointer(ptr)).child)
return interp.eval_stmt_nodes((*Cnode_t)(unsafe.Pointer(ptr)))
} else { } else {
return (*string)(unsafe.Pointer(ptr)), nil return (*string)(unsafe.Pointer(ptr)), nil
} }

View File

@ -34,15 +34,16 @@ const NULL_RUNE rune = '\u0000'
const EOF_RUNE rune = rune(^0) const EOF_RUNE rune = rune(^0)
type context_t struct { type context_t struct {
count int count int
parent_ctx *context_t parent_ctx *context_t
parent_node *Cnode_t parent_node *Cnode_t
container_node *Cnode_t
} }
type process_t struct { type process_t struct {
interp *Interp interp *Interp
stack [16]unsafe.Pointer // value stack - TODO: change size vstack [16]unsafe.Pointer // value stack - TODO: change size
sp int vsp int
ctx *context_t ctx *context_t
} }
@ -245,7 +246,8 @@ func (interp *Interp) Execute(node_head *Cnode_t) (*string, error) {
break 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 { if err != nil {
return nil, err return nil, err
} }

View File

@ -70,6 +70,20 @@ func proc_puts(p *process_t) error {
return nil 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 { func proc_unknown(p *process_t) error {
fmt.Printf("Unknown command - %s\n", *(p.GetCalleeName())) fmt.Printf("Unknown command - %s\n", *(p.GetCalleeName()))
return nil return nil