mirror of
https://github.com/dragonheim/gagent.git
synced 2025-02-23 09:19:53 -08:00
226 lines
5.2 KiB
Go
226 lines
5.2 KiB
Go
package picol
|
|
|
|
import (
|
|
"fmt"
|
|
"strconv"
|
|
"strings"
|
|
)
|
|
|
|
func ArityErr(i *Interp, name string, argv []string) error {
|
|
return fmt.Errorf("wrong number of args for %s %s", name, argv)
|
|
}
|
|
|
|
// CommandMath is the math command for TCL
|
|
func CommandMath(i *Interp, argv []string, pd interface{}) (string, error) {
|
|
if len(argv) != 3 {
|
|
return "", ArityErr(i, argv[0], argv)
|
|
}
|
|
a, _ := strconv.Atoi(argv[1])
|
|
b, _ := strconv.Atoi(argv[2])
|
|
var c int
|
|
switch {
|
|
case argv[0] == "+":
|
|
c = a + b
|
|
case argv[0] == "-":
|
|
c = a - b
|
|
case argv[0] == "*":
|
|
c = a * b
|
|
case argv[0] == "/":
|
|
c = a / b
|
|
case argv[0] == ">":
|
|
if a > b {
|
|
c = 1
|
|
}
|
|
case argv[0] == ">=":
|
|
if a >= b {
|
|
c = 1
|
|
}
|
|
case argv[0] == "<":
|
|
if a < b {
|
|
c = 1
|
|
}
|
|
case argv[0] == "<=":
|
|
if a <= b {
|
|
c = 1
|
|
}
|
|
case argv[0] == "==":
|
|
if a == b {
|
|
c = 1
|
|
}
|
|
case argv[0] == "!=":
|
|
if a != b {
|
|
c = 1
|
|
}
|
|
default: // FIXME I hate warnings
|
|
c = 0
|
|
}
|
|
return fmt.Sprintf("%d", c), nil
|
|
}
|
|
|
|
// CommandSet is the set command for TCL
|
|
func CommandSet(i *Interp, argv []string, pd interface{}) (string, error) {
|
|
if len(argv) != 3 {
|
|
return "", ArityErr(i, argv[0], argv)
|
|
}
|
|
i.SetVar(argv[1], argv[2])
|
|
return argv[2], nil
|
|
}
|
|
|
|
// CommandUnset is the unset command for TCL
|
|
func CommandUnset(i *Interp, argv []string, pd interface{}) (string, error) {
|
|
if len(argv) != 2 {
|
|
return "", ArityErr(i, argv[0], argv)
|
|
}
|
|
i.UnsetVar(argv[1])
|
|
return "", nil
|
|
}
|
|
|
|
// CommandIf is the if command for TCL
|
|
func CommandIf(i *Interp, argv []string, pd interface{}) (string, error) {
|
|
if len(argv) != 3 && len(argv) != 5 {
|
|
return "", ArityErr(i, argv[0], argv)
|
|
}
|
|
|
|
result, err := i.Eval(argv[1])
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
if r, _ := strconv.Atoi(result); r != 0 {
|
|
return i.Eval(argv[2])
|
|
} else if len(argv) == 5 {
|
|
return i.Eval(argv[4])
|
|
}
|
|
|
|
return result, nil
|
|
}
|
|
|
|
// CommandWhile is the while command for TCL
|
|
func CommandWhile(i *Interp, argv []string, pd interface{}) (string, error) {
|
|
if len(argv) != 3 {
|
|
return "", ArityErr(i, argv[0], argv)
|
|
}
|
|
|
|
for {
|
|
result, err := i.Eval(argv[1])
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
if r, _ := strconv.Atoi(result); r != 0 {
|
|
result, err := i.Eval(argv[2])
|
|
switch err {
|
|
case errContinue, nil:
|
|
//pass
|
|
case errBreak:
|
|
return result, nil
|
|
default:
|
|
return result, err
|
|
}
|
|
} else {
|
|
return result, nil
|
|
}
|
|
}
|
|
}
|
|
|
|
// CommandRetCodes is a function to get the return codes for TCL
|
|
func CommandRetCodes(i *Interp, argv []string, pd interface{}) (string, error) {
|
|
if len(argv) != 1 {
|
|
return "", ArityErr(i, argv[0], argv)
|
|
}
|
|
switch argv[0] {
|
|
case "break":
|
|
return "", errBreak
|
|
case "continue":
|
|
return "", errContinue
|
|
}
|
|
return "", nil
|
|
}
|
|
|
|
// CommandCallProc is a function to call proc commands for TCL
|
|
func CommandCallProc(i *Interp, argv []string, pd interface{}) (string, error) {
|
|
var x []string
|
|
|
|
if pd, ok := pd.([]string); ok {
|
|
x = pd
|
|
} else {
|
|
return "", nil
|
|
}
|
|
|
|
i.callframe = &CallFrame{vars: make(map[string]Var), parent: i.callframe}
|
|
defer func() { i.callframe = i.callframe.parent }() // remove the called proc callframe
|
|
|
|
arity := 0
|
|
for _, arg := range strings.Split(x[0], " ") {
|
|
if len(arg) == 0 {
|
|
continue
|
|
}
|
|
arity++
|
|
i.SetVar(arg, argv[arity])
|
|
}
|
|
|
|
if arity != len(argv)-1 {
|
|
return "", fmt.Errorf("proc '%s' called with wrong arg num", argv[0])
|
|
}
|
|
|
|
body := x[1]
|
|
result, err := i.Eval(body)
|
|
if err == errReturn {
|
|
err = nil
|
|
}
|
|
return result, err
|
|
}
|
|
|
|
// CommandProc is a function to register proc commands for TCL
|
|
func CommandProc(i *Interp, argv []string, pd interface{}) (string, error) {
|
|
if len(argv) != 4 {
|
|
return "", ArityErr(i, argv[0], argv)
|
|
}
|
|
return "", i.RegisterCommand(argv[1], CommandCallProc, []string{argv[2], argv[3]})
|
|
}
|
|
|
|
// CommandReturn is a function to register return codes for commands for TCL
|
|
func CommandReturn(i *Interp, argv []string, pd interface{}) (string, error) {
|
|
if len(argv) != 1 && len(argv) != 2 {
|
|
return "", ArityErr(i, argv[0], argv)
|
|
}
|
|
var r string
|
|
if len(argv) == 2 {
|
|
r = argv[1]
|
|
}
|
|
return r, errReturn
|
|
}
|
|
|
|
// CommandError is a function to return error codes for commands for TCL
|
|
func CommandError(i *Interp, argv []string, pd interface{}) (string, error) {
|
|
if len(argv) != 1 && len(argv) != 2 {
|
|
return "", ArityErr(i, argv[0], argv)
|
|
}
|
|
return "", fmt.Errorf(argv[1])
|
|
}
|
|
|
|
// CommandPuts is a function to print strings for TCL
|
|
func CommandPuts(i *Interp, argv []string, pd interface{}) (string, error) {
|
|
if len(argv) != 2 {
|
|
return "", fmt.Errorf("wrong number of args for %s %s", argv[0], argv)
|
|
}
|
|
fmt.Println(argv[1])
|
|
return "", nil
|
|
}
|
|
|
|
// RegisterCoreCommands is a callable to register TCL commands.
|
|
func (i *Interp) RegisterCoreCommands() {
|
|
name := [...]string{"+", "-", "*", "/", ">", ">=", "<", "<=", "==", "!="}
|
|
for _, n := range name {
|
|
i.RegisterCommand(n, CommandMath, nil)
|
|
}
|
|
i.RegisterCommand("set", CommandSet, nil)
|
|
i.RegisterCommand("unset", CommandUnset, nil)
|
|
i.RegisterCommand("if", CommandIf, nil)
|
|
i.RegisterCommand("while", CommandWhile, nil)
|
|
i.RegisterCommand("break", CommandRetCodes, nil)
|
|
i.RegisterCommand("continue", CommandRetCodes, nil)
|
|
i.RegisterCommand("proc", CommandProc, nil)
|
|
i.RegisterCommand("return", CommandReturn, nil)
|
|
i.RegisterCommand("error", CommandError, nil)
|
|
i.RegisterCommand("puts", CommandPuts, nil)
|
|
}
|