commands.go 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  1. package picol
  2. import (
  3. "fmt"
  4. "strconv"
  5. "strings"
  6. )
  7. func ArityErr(i *Interp, name string, argv []string) error {
  8. return fmt.Errorf("Wrong number of args for %s %s", name, argv)
  9. }
  10. func CommandMath(i *Interp, argv []string, pd interface{}) (string, error) {
  11. if len(argv) != 3 {
  12. return "", ArityErr(i, argv[0], argv)
  13. }
  14. a, _ := strconv.Atoi(argv[1])
  15. b, _ := strconv.Atoi(argv[2])
  16. var c int
  17. switch {
  18. case argv[0] == "+":
  19. c = a + b
  20. case argv[0] == "-":
  21. c = a - b
  22. case argv[0] == "*":
  23. c = a * b
  24. case argv[0] == "/":
  25. c = a / b
  26. case argv[0] == ">":
  27. if a > b {
  28. c = 1
  29. }
  30. case argv[0] == ">=":
  31. if a >= b {
  32. c = 1
  33. }
  34. case argv[0] == "<":
  35. if a < b {
  36. c = 1
  37. }
  38. case argv[0] == "<=":
  39. if a <= b {
  40. c = 1
  41. }
  42. case argv[0] == "==":
  43. if a == b {
  44. c = 1
  45. }
  46. case argv[0] == "!=":
  47. if a != b {
  48. c = 1
  49. }
  50. default: // FIXME I hate warnings
  51. c = 0
  52. }
  53. return fmt.Sprintf("%d", c), nil
  54. }
  55. func CommandSet(i *Interp, argv []string, pd interface{}) (string, error) {
  56. if len(argv) != 3 {
  57. return "", ArityErr(i, argv[0], argv)
  58. }
  59. i.SetVar(argv[1], argv[2])
  60. return argv[2], nil
  61. }
  62. func CommandUnset(i *Interp, argv []string, pd interface{}) (string, error) {
  63. if len(argv) != 2 {
  64. return "", ArityErr(i, argv[0], argv)
  65. }
  66. i.UnsetVar(argv[1])
  67. return "", nil
  68. }
  69. func CommandIf(i *Interp, argv []string, pd interface{}) (string, error) {
  70. if len(argv) != 3 && len(argv) != 5 {
  71. return "", ArityErr(i, argv[0], argv)
  72. }
  73. result, err := i.Eval(argv[1])
  74. if err != nil {
  75. return "", err
  76. }
  77. if r, _ := strconv.Atoi(result); r != 0 {
  78. return i.Eval(argv[2])
  79. } else if len(argv) == 5 {
  80. return i.Eval(argv[4])
  81. }
  82. return result, nil
  83. }
  84. func CommandWhile(i *Interp, argv []string, pd interface{}) (string, error) {
  85. if len(argv) != 3 {
  86. return "", ArityErr(i, argv[0], argv)
  87. }
  88. for {
  89. result, err := i.Eval(argv[1])
  90. if err != nil {
  91. return "", err
  92. }
  93. if r, _ := strconv.Atoi(result); r != 0 {
  94. result, err := i.Eval(argv[2])
  95. switch err {
  96. case PICOL_CONTINUE, nil:
  97. //pass
  98. case PICOL_BREAK:
  99. return result, nil
  100. default:
  101. return result, err
  102. }
  103. } else {
  104. return result, nil
  105. }
  106. }
  107. }
  108. func CommandRetCodes(i *Interp, argv []string, pd interface{}) (string, error) {
  109. if len(argv) != 1 {
  110. return "", ArityErr(i, argv[0], argv)
  111. }
  112. switch argv[0] {
  113. case "break":
  114. return "", PICOL_BREAK
  115. case "continue":
  116. return "", PICOL_CONTINUE
  117. }
  118. return "", nil
  119. }
  120. func CommandCallProc(i *Interp, argv []string, pd interface{}) (string, error) {
  121. var x []string
  122. if pd, ok := pd.([]string); ok {
  123. x = pd
  124. } else {
  125. return "", nil
  126. }
  127. i.callframe = &CallFrame{vars: make(map[string]Var), parent: i.callframe}
  128. defer func() { i.callframe = i.callframe.parent }() // remove the called proc callframe
  129. arity := 0
  130. for _, arg := range strings.Split(x[0], " ") {
  131. if len(arg) == 0 {
  132. continue
  133. }
  134. arity++
  135. i.SetVar(arg, argv[arity])
  136. }
  137. if arity != len(argv)-1 {
  138. return "", fmt.Errorf("Proc '%s' called with wrong arg num", argv[0])
  139. }
  140. body := x[1]
  141. result, err := i.Eval(body)
  142. if err == PICOL_RETURN {
  143. err = nil
  144. }
  145. return result, err
  146. }
  147. func CommandProc(i *Interp, argv []string, pd interface{}) (string, error) {
  148. if len(argv) != 4 {
  149. return "", ArityErr(i, argv[0], argv)
  150. }
  151. return "", i.RegisterCommand(argv[1], CommandCallProc, []string{argv[2], argv[3]})
  152. }
  153. func CommandReturn(i *Interp, argv []string, pd interface{}) (string, error) {
  154. if len(argv) != 1 && len(argv) != 2 {
  155. return "", ArityErr(i, argv[0], argv)
  156. }
  157. var r string
  158. if len(argv) == 2 {
  159. r = argv[1]
  160. }
  161. return r, PICOL_RETURN
  162. }
  163. func CommandError(i *Interp, argv []string, pd interface{}) (string, error) {
  164. if len(argv) != 1 && len(argv) != 2 {
  165. return "", ArityErr(i, argv[0], argv)
  166. }
  167. return "", fmt.Errorf(argv[1])
  168. }
  169. func (i *Interp) RegisterCoreCommands() {
  170. name := [...]string{"+", "-", "*", "/", ">", ">=", "<", "<=", "==", "!="}
  171. for _, n := range name {
  172. i.RegisterCommand(n, CommandMath, nil)
  173. }
  174. i.RegisterCommand("set", CommandSet, nil)
  175. i.RegisterCommand("unset", CommandUnset, nil)
  176. i.RegisterCommand("if", CommandIf, nil)
  177. i.RegisterCommand("while", CommandWhile, nil)
  178. i.RegisterCommand("break", CommandRetCodes, nil)
  179. i.RegisterCommand("continue", CommandRetCodes, nil)
  180. i.RegisterCommand("proc", CommandProc, nil)
  181. i.RegisterCommand("return", CommandReturn, nil)
  182. i.RegisterCommand("error", CommandError, nil)
  183. }