main.go 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. package main
  2. import (
  3. "fmt"
  4. "os"
  5. "io"
  6. "sort"
  7. "path/filepath"
  8. "unicode"
  9. )
  10. import "gitlab.com/beoran/muesli"
  11. import "github.com/peterh/liner"
  12. func runLine(vm *muesli.VM, in string) error {
  13. parser := muesli.NewParserFromString(in)
  14. if val := vm.Lookup("__muesli_debug__"); val == muesli.TrueValue {
  15. parser.SetVmLogger(vm)
  16. }
  17. kw := vm.LoadKeywords()
  18. if kw != nil {
  19. parser.AddKeywords(kw)
  20. } else {
  21. parser.AddKeywords(muesli.DefaultKeywords)
  22. vm.StoreKeywords(muesli.DefaultKeywords)
  23. }
  24. ast := parser.Parse()
  25. err := ast.ToError()
  26. if err != nil {
  27. return err
  28. }
  29. result := vm.RunAst(*ast, muesli.NewListValue())
  30. if result != nil {
  31. for _, val := range result {
  32. if val != nil {
  33. vm.Printf(">>%s\n", val.String())
  34. } else {
  35. vm.Printf(">>nil\n")
  36. }
  37. }
  38. }
  39. return nil
  40. }
  41. func runLines(vm *muesli.VM, line *liner.State) error {
  42. for {
  43. if in, err := line.Prompt("> "); err == nil {
  44. err = runLine(vm, in)
  45. if err != nil {
  46. vm.Errf("Error %s: \n", err)
  47. }
  48. line.AppendHistory(in)
  49. } else if err == liner.ErrPromptAborted {
  50. vm.Errf("Aborted\n")
  51. return nil
  52. } else if err == io.EOF {
  53. return nil
  54. } else {
  55. vm.Errf("Error reading line: %s\n", err)
  56. }
  57. }
  58. return nil
  59. }
  60. func runFile(vm *muesli.VM, name string) error {
  61. parser, err := muesli.NewParserFromFilename(name)
  62. if err != nil {
  63. vm.Errf("Error opening file %s: %s\n", name, err)
  64. return err
  65. }
  66. ast := parser.Parse()
  67. err = ast.ToError()
  68. if err == io.EOF {
  69. return nil
  70. } else if err != nil {
  71. vm.Errf("Error opening file %s: %s\n", name, err)
  72. return err
  73. }
  74. vm.RunAst(*ast, muesli.NewListValue())
  75. return nil
  76. }
  77. func main() {
  78. // console := muesli.NewStdConsole()
  79. vm := muesli.NewVM()
  80. // defer func () { os.Exit(vm.ExitStatus) }()
  81. // vm.Tracer = &muesli.FmtTracer{}
  82. // vm.Console = console
  83. vm.RegisterBuiltins()
  84. line := liner.NewLiner()
  85. defer line.Close()
  86. line.SetCtrlCAborts(true)
  87. home, _ := os.UserHomeDir()
  88. historyName := filepath.Join(home, ".muesli_history")
  89. if f, err := os.Open(historyName); err == nil {
  90. line.ReadHistory(f)
  91. f.Close()
  92. }
  93. if len(os.Args) > 1 {
  94. for _, name := range os.Args {
  95. err := runFile(vm, name)
  96. if err != nil {
  97. return
  98. }
  99. }
  100. return
  101. }
  102. line.SetWordCompleter(func(line string, pos int) (head string, c []string, tail string) {
  103. end := pos
  104. // XXX unicode support!
  105. for end < len(line) && unicode.IsLetter(rune(line[end])) {
  106. end++
  107. }
  108. if end > len(line) {
  109. end = len(line)
  110. }
  111. tail = line[end:]
  112. start := pos - 1
  113. for start > 0 && unicode.IsLetter(rune(line[start-1])) {
  114. start--
  115. }
  116. if start < 0 {
  117. start = 0
  118. }
  119. fmt.Printf("%d %d %d\n", start, end, len(line))
  120. head = line[0:start]
  121. word := line[start:end]
  122. fmt.Printf(">%s<\n", word)
  123. c = vm.DefinedNamesLike(word)
  124. sort.Strings(c)
  125. return head, c, tail
  126. })
  127. runLines(vm, line)
  128. if f, err := os.Create(historyName); err != nil {
  129. vm.Errf("Error writing history file: %s\n", err)
  130. } else {
  131. line.WriteHistory(f)
  132. f.Close()
  133. }
  134. }