main.go 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. package main
  2. import (
  3. "io"
  4. "io/ioutil"
  5. "os"
  6. "path/filepath"
  7. // "sort"
  8. )
  9. import "src.eruta.nl/beoran/attl"
  10. import "github.com/peterh/liner"
  11. func runLine(env *attl.Environment, in string) *attl.Error {
  12. parsed, err := attl.Parse(in)
  13. if err != nil {
  14. return err
  15. }
  16. if parsed == nil {
  17. return attl.ErrorFromString("No parse results")
  18. }
  19. val, eff := parsed.Eval(env)
  20. if val != nil {
  21. env.Printi(">>${1}\n", val)
  22. } else {
  23. env.Printi(">>nil\n")
  24. }
  25. err, ok := eff.(*attl.Error)
  26. if ok {
  27. return err
  28. }
  29. return nil
  30. }
  31. func runLines(env *attl.Environment, line *liner.State) error {
  32. buf := ""
  33. for {
  34. if in, err := line.Prompt("> "); err == nil {
  35. first := ';'
  36. if len(in) > 0 {
  37. first = rune(in[0])
  38. }
  39. if first == '\\' {
  40. buf = buf + "\n" + in[1:len(in)]
  41. } else {
  42. if len(buf) > 0 {
  43. buf = buf + "\n" + in
  44. } else {
  45. buf = in + "\n"
  46. }
  47. rerr := runLine(env, buf)
  48. buf = ""
  49. if rerr != nil {
  50. env.Printi("Error ${1}: \n", attl.String(rerr.Message))
  51. }
  52. }
  53. line.AppendHistory(in)
  54. } else if err == liner.ErrPromptAborted {
  55. env.Printi("Aborted\n")
  56. return nil
  57. } else if err == io.EOF {
  58. return nil
  59. } else {
  60. env.Printi("Error reading line: ${1}\n", attl.ErrorFromError(err))
  61. }
  62. }
  63. return nil
  64. }
  65. func runFile(env *attl.Environment, name string) *attl.Error {
  66. fin, err := os.Open(name)
  67. if err != nil {
  68. return attl.ErrorFromError(err)
  69. }
  70. defer fin.Close()
  71. buf, err := ioutil.ReadAll(fin)
  72. if err != nil {
  73. return attl.ErrorFromError(err)
  74. }
  75. in := string(buf)
  76. parsed, rerr := attl.Parse(in)
  77. if rerr != nil {
  78. return rerr
  79. }
  80. if parsed == nil {
  81. return attl.ErrorFromString("Parse result is empty.")
  82. }
  83. args := attl.List{}
  84. for _, a := range os.Args {
  85. args = append(args, attl.String(a))
  86. }
  87. _, reff := parsed.Eval(env, args...)
  88. rerr, ok := reff.(*attl.Error)
  89. if ok {
  90. return rerr
  91. }
  92. return nil
  93. }
  94. func main() {
  95. // console := muesli.NewStdConsole()
  96. env := &attl.Environment{}
  97. env.Out = os.Stdout
  98. env.Push()
  99. env.RegisterBuiltins()
  100. env.RegisterTuringCompleteBuiltins()
  101. line := liner.NewLiner()
  102. defer line.Close()
  103. line.SetCtrlCAborts(true)
  104. home, _ := os.UserHomeDir()
  105. historyName := filepath.Join(home, ".attl_history")
  106. if f, err := os.Open(historyName); err == nil {
  107. line.ReadHistory(f)
  108. f.Close()
  109. }
  110. if len(os.Args) > 1 {
  111. for _, name := range os.Args {
  112. rerr := runFile(env, name)
  113. if rerr != nil {
  114. sname := attl.String(name)
  115. env.Printi("error in ${1}: ${2}\n", sname,
  116. rerr)
  117. }
  118. }
  119. return
  120. }
  121. line.SetWordCompleter(func(line string, pos int) (head string, c []string, tail string) {
  122. return attl.WordCompleter(*env, line, pos)
  123. })
  124. runLines(env, line)
  125. if f, err := os.Create(historyName); err != nil {
  126. env.Printi("Error writing history file: ${1}\n", attl.ErrorFromError(err))
  127. } else {
  128. line.WriteHistory(f)
  129. f.Close()
  130. }
  131. }