Compare commits
	
		
			4 Commits
		
	
	
		
			1ad6779aa4
			...
			85a6092363
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 85a6092363 | |||
| 760f9a7114 | |||
| c1f7c4b963 | |||
| 5d66a2e6d7 | 
							
								
								
									
										247
									
								
								interp/eval.go
									
									
									
									
									
								
							
							
						
						
									
										247
									
								
								interp/eval.go
									
									
									
									
									
								
							| @ -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 | ||||||
| 	} | 	} | ||||||
|  | |||||||
| @ -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 | ||||||
| 		} | 		} | ||||||
|  | |||||||
| @ -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 | ||||||
|  | |||||||
		Reference in New Issue
	
	Block a user
	