Compare commits
4 Commits
main
...
85a6092363
Author | SHA1 | Date | |
---|---|---|---|
85a6092363 | |||
760f9a7114 | |||
c1f7c4b963 | |||
5d66a2e6d7 |
39
bin/main.go
39
bin/main.go
@ -16,9 +16,8 @@ func main() {
|
|||||||
r *bufio.Reader
|
r *bufio.Reader
|
||||||
c rune
|
c rune
|
||||||
node *pcl.Cnode_t
|
node *pcl.Cnode_t
|
||||||
v pcl.Value_t
|
v *string
|
||||||
|
err error
|
||||||
err error
|
|
||||||
)
|
)
|
||||||
|
|
||||||
if len(os.Args) != 2 {
|
if len(os.Args) != 2 {
|
||||||
@ -71,10 +70,38 @@ func main() {
|
|||||||
goto oops
|
goto oops
|
||||||
}
|
}
|
||||||
|
|
||||||
if v.Kind != pcl.VALUE_STR {
|
if v == nil {
|
||||||
panic("return value must not be string")
|
panic("return value mut not be nil")
|
||||||
}
|
}
|
||||||
fmt.Printf("RETURN VALUE = [%s]\n", *(*string)(v.V))
|
fmt.Printf("RETURN VALUE = [%s]\n", *v)
|
||||||
|
|
||||||
|
/*
|
||||||
|
err = interp.FeedRunes([]rune(`
|
||||||
|
proc inc{x} {
|
||||||
|
puts {10 20}
|
||||||
|
return [expr $x + 1]
|
||||||
|
}
|
||||||
|
\{abc 11 2\ \1011 \ 2\x65 \uBc29\uaD6cdefg\uZZ\xZZ\U0000BC29\UAD6cZZ \
|
||||||
|
[donkey 1 [expr [expr 2 + 3] + 3] ]
|
||||||
|
hello { world { }man}
|
||||||
|
"command { l a n g }"
|
||||||
|
set a [puts "1111" "22 22" "3333 [expr "123" + 2] 4444"]
|
||||||
|
abc [expr [expr 2 + "4[expr 2 * 6]"] + 9]
|
||||||
|
puts $a ${ kkk qqq }
|
||||||
|
puts "\x65\ubc29\n"
|
||||||
|
{}`))
|
||||||
|
*/
|
||||||
|
//err = interp.FeedRunes([]rune(`hello [world [1 9] 2]
|
||||||
|
//`))
|
||||||
|
/*
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("ERROR %s\n", err)
|
||||||
|
} else {
|
||||||
|
err = interp.EndFeed()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("ERROR %s\n", err)
|
||||||
|
}
|
||||||
|
}*/
|
||||||
|
|
||||||
interp.Close()
|
interp.Close()
|
||||||
f.Close()
|
f.Close()
|
||||||
|
461
interp/eval.go
461
interp/eval.go
@ -8,7 +8,6 @@ import (
|
|||||||
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_strval = Value_t{Kind: VALUE_STR, V: unsafe.Pointer(new(string))}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
value stack (p.vstack)
|
value stack (p.vstack)
|
||||||
@ -22,37 +21,16 @@ var empty_strval = Value_t{Kind: VALUE_STR, V: unsafe.Pointer(new(string))}
|
|||||||
evaluation stack (p.ctx)
|
evaluation stack (p.ctx)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
func (p *process_t) push_call_frame() {
|
|
||||||
var cf *call_frame_t
|
|
||||||
|
|
||||||
cf = &call_frame_t{}
|
|
||||||
if p.cframe == nil {
|
|
||||||
// let it point to the global frame located in the interp struct
|
|
||||||
cf.parent = p.interp.cframe
|
|
||||||
} else {
|
|
||||||
cf.parent = p.cframe
|
|
||||||
}
|
|
||||||
cf.vars = make(map[string]Value_t)
|
|
||||||
p.cframe = cf
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *process_t) pop_call_frame() {
|
|
||||||
if p.cframe == p.interp.cframe {
|
|
||||||
p.cframe = nil
|
|
||||||
} else {
|
|
||||||
p.cframe = p.cframe.parent
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *process_t) push_cnode_value(val *Cnode_t) error {
|
func (p *process_t) push_cnode_value(val *Cnode_t) error {
|
||||||
if p.vsp >= cap(p.vstack) {
|
if p.vsp >= cap(p.vstack) {
|
||||||
return fmt.Errorf("stack full")
|
return fmt.Errorf("stack full")
|
||||||
}
|
}
|
||||||
|
|
||||||
p.vstack[p.vsp] = Value_t{Kind: VALUE_CNODE, V: unsafe.Pointer(val)}
|
// 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.vsp++
|
||||||
p.ctx.count++
|
p.ctx.count++
|
||||||
//fmt.Printf("push_cnode_value = ctx.count => %d\n", p.ctx.count)
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -62,49 +40,32 @@ func (p *process_t) push_string_value(val string) error {
|
|||||||
return fmt.Errorf("stack full")
|
return fmt.Errorf("stack full")
|
||||||
}
|
}
|
||||||
|
|
||||||
p.vstack[p.vsp] = Value_t{Kind: VALUE_STR, V: unsafe.Pointer(&val)}
|
p.vstack[p.vsp] = 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)
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
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 Value_t
|
|
||||||
|
|
||||||
if p.vsp < 2 {
|
if p.vsp < 2 {
|
||||||
return fmt.Errorf("stack corrupt")
|
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]
|
|
||||||
v2 = p.vstack[p.vsp-1]
|
|
||||||
|
|
||||||
if v1.Kind == VALUE_STR {
|
|
||||||
new_val += *(*string)(v1.V)
|
|
||||||
}
|
|
||||||
// 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)
|
|
||||||
}
|
|
||||||
|
|
||||||
p.vsp--
|
p.vsp--
|
||||||
p.vstack[p.vsp].V = unsafe.Pointer(nil)
|
p.vstack[p.vsp] = nil
|
||||||
p.vstack[p.vsp-1] = Value_t{Kind: VALUE_STR, V: unsafe.Pointer(&new_val)}
|
p.vstack[p.vsp-1] = unsafe.Pointer(&new_val)
|
||||||
p.ctx.count--
|
p.ctx.count--
|
||||||
|
|
||||||
if debug {
|
|
||||||
fmt.Printf("merge_top_values = ctx.count => %d\n", p.ctx.count)
|
|
||||||
}
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *process_t) pop_value() Value_t {
|
func (p *process_t) pop_value() unsafe.Pointer {
|
||||||
var v Value_t
|
var v unsafe.Pointer
|
||||||
p.vsp--
|
p.vsp--
|
||||||
v = p.vstack[p.vsp]
|
v = p.vstack[p.vsp]
|
||||||
p.vstack[p.vsp].V = unsafe.Pointer(nil)
|
p.vstack[p.vsp] = nil
|
||||||
return v
|
return v
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -115,17 +76,8 @@ func (p *process_t) call() error {
|
|||||||
)
|
)
|
||||||
|
|
||||||
callee = p.GetCalleeName()
|
callee = p.GetCalleeName()
|
||||||
|
|
||||||
if debug {
|
|
||||||
fmt.Printf("calling..... [%s]\n", *callee)
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: use a map
|
// TODO: use a map
|
||||||
switch *callee {
|
switch *callee {
|
||||||
case "proc":
|
|
||||||
proc = proc_proc
|
|
||||||
case "set":
|
|
||||||
proc = proc_set
|
|
||||||
case "if":
|
case "if":
|
||||||
proc = proc_if
|
proc = proc_if
|
||||||
case "puts":
|
case "puts":
|
||||||
@ -143,10 +95,10 @@ func (p *process_t) call() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (p *process_t) GetCalleeName() *string {
|
func (p *process_t) GetCalleeName() *string {
|
||||||
return (*string)(p.vstack[p.vsp-p.ctx.count+1].V)
|
return (*string)(p.vstack[p.vsp-p.ctx.count+1])
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *process_t) GetArg(idx int) Value_t {
|
func (p *process_t) GetArg(idx int) unsafe.Pointer {
|
||||||
return (p.vstack[p.vsp-p.ctx.count+2+idx])
|
return (p.vstack[p.vsp-p.ctx.count+2+idx])
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -154,18 +106,11 @@ func (p *process_t) GetNumArgs() int {
|
|||||||
return p.ctx.count - 2
|
return p.ctx.count - 2
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *process_t) ReturnString(val string) {
|
func (p *process_t) Return(val string) {
|
||||||
p.vstack[p.vsp-p.ctx.count] = Value_t{Kind: VALUE_STR, V: unsafe.Pointer(&val)}
|
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) {
|
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}
|
p.ctx = &context_t{count: 0, parent_ctx: p.ctx, parent_node: node, container_node: container_node}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -176,17 +121,13 @@ func (p *process_t) pop_context(clear_vstack bool) (*Cnode_t, *Cnode_t) {
|
|||||||
container *Cnode_t
|
container *Cnode_t
|
||||||
)
|
)
|
||||||
|
|
||||||
if debug {
|
|
||||||
fmt.Printf("POPPING CONTEXT.....is_stmt/clear_vstack[%v]\n", clear_vstack)
|
|
||||||
}
|
|
||||||
|
|
||||||
node = p.ctx.parent_node
|
node = p.ctx.parent_node
|
||||||
container = p.ctx.container_node
|
container = p.ctx.container_node
|
||||||
|
|
||||||
if clear_vstack { // TODO: use the conttext type instead... may be able to use container_node.code???
|
if clear_vstack {
|
||||||
// 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].V = unsafe.Pointer(nil)
|
p.vstack[p.vsp-p.ctx.count+i] = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// pop off the cleaned arguments
|
// pop off the cleaned arguments
|
||||||
@ -194,53 +135,38 @@ func (p *process_t) pop_context(clear_vstack bool) (*Cnode_t, *Cnode_t) {
|
|||||||
}
|
}
|
||||||
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 node, container
|
return node, container
|
||||||
}
|
}
|
||||||
|
|
||||||
func (interp *Interp) dump_vstack(p *process_t) {
|
func (interp *Interp) dump_vstack(p *process_t) {
|
||||||
|
//fmt.Printf("DDDDDDDDDDDDBVVVVVVVVVVVDDDd\n")
|
||||||
fmt.Printf("p.VSP => %d\n", p.vsp)
|
fmt.Printf("p.VSP => %d\n", p.vsp)
|
||||||
for i := 0; i < p.vsp; i++ {
|
for i := 0; i < p.vsp; i++ {
|
||||||
/*
|
x := uintptr(p.vstack[i])
|
||||||
x := uintptr(p.vstack[i])
|
if x&1 == 0 {
|
||||||
if x&1 == 0 {
|
// string value
|
||||||
// string value
|
fmt.Printf(" %d => [%s]\n", i, *(*string)(p.vstack[i]))
|
||||||
fmt.Printf(" %d => [%s]\n", i, *(*string)(p.vstack[i]))
|
} else {
|
||||||
} else {
|
// 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 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((*Cnode_t)(p.vstack[i].V), false)
|
|
||||||
fmt.Printf("\n")
|
|
||||||
default:
|
|
||||||
panic("internal error - unrecognized value")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
puts "hello" world
|
[STMT]
|
||||||
|
[TEXT] [DQUOTE] [TEXT]
|
||||||
|
|
||||||
[STMT]
|
[STMT]
|
||||||
[TEXT|puts] [DQUOTE] [TEXT|world]
|
[BRACKET] [TEXT]
|
||||||
[TEXT|hello]
|
|
||||||
|
|
||||||
[puts 1 2; puts 1] 999
|
|
||||||
|
|
||||||
[STMT]
|
|
||||||
[BRACKET] [TEXT|999]
|
|
||||||
[STMT]
|
[STMT]
|
||||||
[TEXT|puts] [TEXT|1] [TEXT|2]
|
[TEXT] [TEXT] [TEXT]
|
||||||
[STMT]
|
[STMT]
|
||||||
[TEXT|puts] [TEXT|1]
|
[TEXT] [TEXT]
|
||||||
|
|
||||||
"pu[null 1]ts" 10 20
|
"pu[null 1]ts" 10 20
|
||||||
|
|
||||||
@ -250,38 +176,35 @@ puts "hello" world
|
|||||||
[STMT]
|
[STMT]
|
||||||
[TEXT|null] [TEXT|1]
|
[TEXT|null] [TEXT|1]
|
||||||
*/
|
*/
|
||||||
func (interp *Interp) eval_stmt_nodes(p *process_t, container_node *Cnode_t) (Value_t, error) {
|
func (interp *Interp) eval_stmt_nodes(container_node *Cnode_t) (*string, error) {
|
||||||
var (
|
var (
|
||||||
v Value_t
|
p process_t
|
||||||
|
v *string
|
||||||
stmt_node *Cnode_t
|
stmt_node *Cnode_t
|
||||||
upper_node *Cnode_t
|
|
||||||
inner_node *Cnode_t
|
inner_node *Cnode_t
|
||||||
is_stmt bool
|
|
||||||
err error
|
err error
|
||||||
org_vsp int
|
|
||||||
)
|
)
|
||||||
|
|
||||||
v = empty_strval
|
v = new(string) // TODO: change new(string) to a const
|
||||||
|
|
||||||
upper_node = container_node
|
p.interp = interp
|
||||||
stmt_node = upper_node.child // the first statement
|
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")
|
||||||
|
|
||||||
org_vsp = p.vsp
|
|
||||||
fmt.Printf("START p.sp = %d\n", 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 {
|
if stmt_node.code != CNODE_STMT {
|
||||||
panic("internal error - not statement node")
|
panic("internal error - not statement node")
|
||||||
}
|
}
|
||||||
|
|
||||||
p.push_context(stmt_node, upper_node)
|
p.push_context(stmt_node, nil)
|
||||||
p.push_string_value("") // placeholder for return value
|
p.push_string_value("") // placeholder for return value
|
||||||
|
|
||||||
|
start_over:
|
||||||
inner_node = stmt_node.child
|
inner_node = stmt_node.child
|
||||||
resume:
|
resume:
|
||||||
for inner_node != nil {
|
for inner_node != nil {
|
||||||
@ -289,15 +212,15 @@ func (interp *Interp) eval_stmt_nodes(p *process_t, container_node *Cnode_t) (Va
|
|||||||
switch inner_node.code {
|
switch inner_node.code {
|
||||||
case CNODE_BRACKET:
|
case CNODE_BRACKET:
|
||||||
if inner_node.child != nil {
|
if inner_node.child != nil {
|
||||||
upper_node = inner_node
|
stmt_node = inner_node.child // first statement inside []
|
||||||
stmt_node = upper_node.child
|
p.push_context(stmt_node, inner_node)
|
||||||
|
p.push_string_value("") // for return value
|
||||||
if debug {
|
if debug {
|
||||||
fmt.Printf("going to start over\n")
|
fmt.Printf("going to start over\n")
|
||||||
interp.dump_cnodes(stmt_node, true)
|
interp.dump_cnodes(stmt_node, true)
|
||||||
fmt.Printf("\n--\n")
|
fmt.Printf("\n--\n")
|
||||||
}
|
}
|
||||||
goto start_over_0
|
goto start_over
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// no statements inside []. treat it like an empty string
|
// no statements inside []. treat it like an empty string
|
||||||
p.push_string_value("")
|
p.push_string_value("")
|
||||||
@ -332,177 +255,201 @@ func (interp *Interp) eval_stmt_nodes(p *process_t, container_node *Cnode_t) (Va
|
|||||||
|
|
||||||
// TODO: many more types...
|
// TODO: many more types...
|
||||||
case CNODE_JOIN:
|
case CNODE_JOIN:
|
||||||
|
//fmt.Printf("JOIN>>>>>\n")
|
||||||
p.merge_top_values()
|
p.merge_top_values()
|
||||||
|
|
||||||
case CNODE_INIT:
|
|
||||||
panic("internal error - INIT node must not appear inside a statement")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inner_node = inner_node.next
|
inner_node = inner_node.next
|
||||||
}
|
}
|
||||||
|
|
||||||
if debug {
|
if debug {
|
||||||
interp.dump_vstack(p)
|
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)
|
//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)
|
||||||
if p.ctx.container_node.code == CNODE_INIT || p.ctx.container_node.code == CNODE_BRACKET || p.ctx.container_node.code == CNODE_BRACE {
|
//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()
|
err = p.call()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
goto oops
|
goto oops
|
||||||
}
|
}
|
||||||
|
|
||||||
is_stmt = true
|
stmt_node, inner_node = p.pop_context(true)
|
||||||
} else {
|
} else {
|
||||||
is_stmt = false
|
stmt_node, inner_node = p.pop_context(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
stmt_node, upper_node = p.pop_context(is_stmt)
|
if inner_node != nil {
|
||||||
if upper_node != container_node {
|
|
||||||
if debug {
|
if debug {
|
||||||
fmt.Printf("resuming... %d upper_node.next %p\n", p.vsp, upper_node.next)
|
fmt.Printf("resuming... %d\n", p.vsp)
|
||||||
}
|
|
||||||
|
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
inner_node = inner_node.next
|
||||||
|
goto resume
|
||||||
}
|
}
|
||||||
|
|
||||||
//fmt.Printf("POPPING VALUE...\n")
|
v = (*string)(p.pop_value()) // get the return value of the statement.
|
||||||
/*v = (*string)(p.pop_value()) // get the return value of the statement.
|
|
||||||
if debug {
|
|
||||||
interp.dump_vstack(&p)
|
|
||||||
}*/
|
|
||||||
stmt_node = stmt_node.next
|
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")
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
v = p.pop_value() // get the return value of the statement.
|
|
||||||
if debug {
|
|
||||||
interp.dump_vstack(p)
|
|
||||||
}
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
v = p.pop_value() // get the return value of the statement.
|
|
||||||
if debug {
|
|
||||||
interp.dump_vstack(p)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
done:
|
|
||||||
|
|
||||||
if debug {
|
if debug {
|
||||||
interp.dump_vstack(p)
|
interp.dump_vstack(&p)
|
||||||
fmt.Printf("END p.sp = %d\n", p.vsp)
|
fmt.Printf("END p.sp = %d\n", p.vsp)
|
||||||
}
|
}
|
||||||
if p.vsp != org_vsp {
|
|
||||||
panic("internal error - stack not clean")
|
|
||||||
}
|
|
||||||
return v, nil
|
return v, nil
|
||||||
|
|
||||||
oops:
|
oops:
|
||||||
return empty_strval, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (interp *Interp) eval_arg(p *process_t, pos int) (Value_t, error) {
|
/*
|
||||||
var v Value_t
|
func (interp *Interp) eval_atom_node_old(node *Cnode_t) (*string, error) {
|
||||||
|
|
||||||
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")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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....
|
|
||||||
return nil, fmt.Errorf("not supported - unable to evaluate {} literally")
|
|
||||||
} else {
|
|
||||||
return (*string)(unsafe.Pointer(ptr)), nil
|
|
||||||
}*/
|
|
||||||
|
|
||||||
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 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 {
|
|
||||||
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 (
|
var (
|
||||||
key *string
|
p process_t
|
||||||
val Value_t
|
v *string
|
||||||
f *call_frame_t
|
err error
|
||||||
ok bool
|
|
||||||
)
|
)
|
||||||
|
|
||||||
if name.Kind != VALUE_STR {
|
p.interp = interp
|
||||||
return empty_strval, fmt.Errorf("invalid variable name")
|
p.push_context(nil)
|
||||||
}
|
p.push_string_value("") // placeholder for return value
|
||||||
|
|
||||||
key = (*string)(name.V)
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for f = p.cframe; f != nil; f = f.parent {
|
case CNODE_BRACE: // this is a container
|
||||||
val, ok = p.cframe.vars[*key]
|
err = p.push_cnode_value(node)
|
||||||
if ok {
|
if err != nil {
|
||||||
return val, 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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return empty_strval, fmt.Errorf("%s not found", *key)
|
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_arg(p *process_t, pos int) (*string, 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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (interp *Interp) EvalText(text []rune) (Value_t, error) {
|
func (interp *Interp) eval_arg_literally(p *process_t, pos int) (*string, error) {
|
||||||
var (
|
var (
|
||||||
v Value_t
|
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....
|
||||||
|
return nil, fmt.Errorf("not supported - unable to evaluate {} literally")
|
||||||
|
} else {
|
||||||
|
return (*string)(unsafe.Pointer(ptr)), nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (interp *Interp) EvalText(text []rune) (*string, error) {
|
||||||
|
var (
|
||||||
|
v *string
|
||||||
node *Cnode_t
|
node *Cnode_t
|
||||||
err error
|
err error
|
||||||
)
|
)
|
||||||
@ -531,5 +478,5 @@ func (interp *Interp) EvalText(text []rune) (Value_t, error) {
|
|||||||
return v, nil
|
return v, nil
|
||||||
|
|
||||||
oops:
|
oops:
|
||||||
return empty_strval, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -40,28 +40,15 @@ type context_t struct {
|
|||||||
container_node *Cnode_t
|
container_node *Cnode_t
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
||||||
vstack [16]Value_t // value stack - TODO: change size
|
vstack [16]unsafe.Pointer // value stack - TODO: change size
|
||||||
vsp int
|
vsp int
|
||||||
ctx *context_t
|
ctx *context_t
|
||||||
cframe *call_frame_t
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type call_frame_t struct {
|
type call_frame_t struct {
|
||||||
vars map[string]Value_t
|
vars *Var
|
||||||
parent *call_frame_t
|
parent *call_frame_t
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -119,6 +106,7 @@ type Cnode_t struct {
|
|||||||
next *Cnode_t
|
next *Cnode_t
|
||||||
child *Cnode_t // for container nodes
|
child *Cnode_t // for container nodes
|
||||||
code cnode_code_t
|
code cnode_code_t
|
||||||
|
seqno int
|
||||||
token []rune
|
token []rune
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -127,9 +115,9 @@ type Interp struct {
|
|||||||
level int
|
level int
|
||||||
max_level int
|
max_level int
|
||||||
|
|
||||||
feed *feed_struct_t
|
feed *feed_struct_t
|
||||||
cframe *call_frame_t
|
call_frame *call_frame_t
|
||||||
result string
|
result string
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewInterp(max_level int, strict bool) (*Interp, error) {
|
func NewInterp(max_level int, strict bool) (*Interp, error) {
|
||||||
@ -150,15 +138,10 @@ func NewInterp(max_level int, strict bool) (*Interp, error) {
|
|||||||
interp.push_feed_struct(FEED_TOP)
|
interp.push_feed_struct(FEED_TOP)
|
||||||
interp.push_feed_struct(FEED_INIT)
|
interp.push_feed_struct(FEED_INIT)
|
||||||
|
|
||||||
// global cframe?
|
|
||||||
interp.cframe = &call_frame_t{}
|
|
||||||
|
|
||||||
return interp, nil
|
return interp, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (interp *Interp) Close() {
|
func (interp *Interp) Close() {
|
||||||
interp.cframe = nil
|
|
||||||
|
|
||||||
for interp.feed != nil {
|
for interp.feed != nil {
|
||||||
interp.pop_feed_struct()
|
interp.pop_feed_struct()
|
||||||
}
|
}
|
||||||
@ -244,24 +227,19 @@ func get_top_call_frame(f *CallFrame) *CallFrame {
|
|||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
func (interp *Interp) Execute(node_head *Cnode_t) (Value_t, error) {
|
func (interp *Interp) Execute(node_head *Cnode_t) (*string, error) {
|
||||||
|
|
||||||
var (
|
var (
|
||||||
node *Cnode_t
|
node *Cnode_t
|
||||||
v Value_t
|
v *string
|
||||||
err error
|
err error
|
||||||
p process_t
|
|
||||||
)
|
)
|
||||||
|
|
||||||
p = process_t{interp: interp, vsp: 0}
|
v = new(string) // if there is no code the execute, the return value is an empty string
|
||||||
p.push_call_frame()
|
|
||||||
|
|
||||||
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 empty_strval, fmt.Errorf("non-init node")
|
return nil, 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
|
||||||
@ -269,18 +247,13 @@ 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(node)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
goto done
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
done:
|
return v, nil
|
||||||
// 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) {
|
||||||
|
@ -2,65 +2,6 @@ package interp
|
|||||||
|
|
||||||
import "fmt"
|
import "fmt"
|
||||||
|
|
||||||
func proc_proc(p *process_t) error {
|
|
||||||
/*
|
|
||||||
p.push_call_frame()
|
|
||||||
p.set_var("aaa", 10)
|
|
||||||
p.set_var("bbb", 20)
|
|
||||||
p.eval_stmt_nodes()
|
|
||||||
p.pop_call_frame()
|
|
||||||
*/
|
|
||||||
var err error
|
|
||||||
|
|
||||||
if p.GetNumArgs() != 3 {
|
|
||||||
err = err_num_args
|
|
||||||
goto done
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
// procedure name
|
|
||||||
v1, err = p.interp.eval_arg(p, 0)
|
|
||||||
if err != nil {
|
|
||||||
goto done
|
|
||||||
}
|
|
||||||
|
|
||||||
p.set_var(p, v1, v2)*/
|
|
||||||
done:
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func proc_set(p *process_t) error {
|
|
||||||
var (
|
|
||||||
v1, v2 Value_t
|
|
||||||
err error
|
|
||||||
)
|
|
||||||
|
|
||||||
if p.GetNumArgs() != 2 {
|
|
||||||
err = err_num_args
|
|
||||||
goto done
|
|
||||||
}
|
|
||||||
|
|
||||||
v1, err = p.interp.eval_arg(p, 0)
|
|
||||||
if err != nil {
|
|
||||||
goto done
|
|
||||||
}
|
|
||||||
|
|
||||||
v2, err = p.interp.eval_arg(p, 1)
|
|
||||||
if err != nil {
|
|
||||||
goto done
|
|
||||||
}
|
|
||||||
|
|
||||||
err = p.interp.set_var(p, v1, v2)
|
|
||||||
if err != nil {
|
|
||||||
goto done
|
|
||||||
}
|
|
||||||
|
|
||||||
p.Return(v2)
|
|
||||||
|
|
||||||
done:
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func proc_expr(p *process_t) error {
|
func proc_expr(p *process_t) error {
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@ -68,7 +9,7 @@ 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 *string
|
||||||
err error
|
err error
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -83,17 +24,14 @@ func proc_if(p *process_t) error {
|
|||||||
goto done
|
goto done
|
||||||
}
|
}
|
||||||
|
|
||||||
if v.Kind != VALUE_STR {
|
if *v != "" {
|
||||||
panic("internal error - screwed conditional value")
|
|
||||||
}
|
|
||||||
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 {
|
||||||
goto done
|
goto done
|
||||||
}
|
}
|
||||||
|
|
||||||
p.Return(v)
|
p.Return(*v)
|
||||||
} else {
|
} else {
|
||||||
// TODO: if elseif else
|
// TODO: if elseif else
|
||||||
}
|
}
|
||||||
@ -106,7 +44,7 @@ func proc_puts(p *process_t) error {
|
|||||||
var (
|
var (
|
||||||
i int
|
i int
|
||||||
nargs int
|
nargs int
|
||||||
v Value_t
|
v *string
|
||||||
err error
|
err error
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -121,33 +59,28 @@ func proc_puts(p *process_t) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
fmt.Printf("%s", *v)
|
||||||
// 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 {
|
if nargs >= 1 {
|
||||||
p.Return(v)
|
p.Return(*v)
|
||||||
} else {
|
} else {
|
||||||
p.ReturnString("hello")
|
p.Return("hello")
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func proc_false(p *process_t) error {
|
func proc_false(p *process_t) error {
|
||||||
p.ReturnString("false")
|
p.Return("false")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
func proc_true(p *process_t) error {
|
func proc_true(p *process_t) error {
|
||||||
p.ReturnString("true")
|
p.Return("true")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func proc_null(p *process_t) error {
|
func proc_null(p *process_t) error {
|
||||||
p.ReturnString("")
|
p.Return("")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user