123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205 |
- 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)
- }
- 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
- }
- 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
- }
- 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
- }
- 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
- }
- 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 PICOL_CONTINUE, nil:
- //pass
- case PICOL_BREAK:
- return result, nil
- default:
- return result, err
- }
- } else {
- return result, nil
- }
- }
- }
- 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 "", PICOL_BREAK
- case "continue":
- return "", PICOL_CONTINUE
- }
- return "", nil
- }
- 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 == PICOL_RETURN {
- err = nil
- }
- return result, err
- }
- 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]})
- }
- 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, PICOL_RETURN
- }
- 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])
- }
- 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)
- }
|