main.go 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  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. fmt.Printf(">>%s\n", val.String())
  34. } else {
  35. fmt.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.Errorf("Error %s: \n", err)
  47. }
  48. line.AppendHistory(in)
  49. } else if err == liner.ErrPromptAborted {
  50. vm.Errorf("Aborted\n")
  51. return nil
  52. } else if err == io.EOF {
  53. return nil
  54. } else {
  55. vm.Errorf("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.Errorf("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.Errorf("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. vm := muesli.NewVM()
  79. // defer func () { os.Exit(vm.ExitStatus) }()
  80. // vm.Tracer = &muesli.FmtTracer{}
  81. vm.RegisterBuiltins()
  82. line := liner.NewLiner()
  83. defer line.Close()
  84. line.SetCtrlCAborts(true)
  85. home, _ := os.UserHomeDir()
  86. historyName := filepath.Join(home, ".muesli_history")
  87. if f, err := os.Open(historyName); err == nil {
  88. line.ReadHistory(f)
  89. f.Close()
  90. }
  91. if len(os.Args) > 1 {
  92. for _, name := range os.Args {
  93. err := runFile(vm, name)
  94. if err != nil {
  95. return
  96. }
  97. }
  98. return
  99. }
  100. line.SetWordCompleter(func(line string, pos int) (head string, c []string, tail string) {
  101. end := pos
  102. // XXX unicode support!
  103. for end < len(line) && unicode.IsLetter(rune(line[end])) {
  104. end++
  105. }
  106. if end > len(line) {
  107. end = len(line)
  108. }
  109. tail = line[end:]
  110. start := pos - 1
  111. for start > 0 && unicode.IsLetter(rune(line[start-1])) {
  112. start--
  113. }
  114. if start < 0 {
  115. start = 0
  116. }
  117. fmt.Printf("%d %d %d\n", start, end, len(line))
  118. head = line[0:start]
  119. word := line[start:end]
  120. fmt.Printf(">%s<\n", word)
  121. c = vm.DefinedNamesLike(word)
  122. sort.Strings(c)
  123. return head, c, tail
  124. })
  125. runLines(vm, line)
  126. if f, err := os.Create(historyName); err != nil {
  127. vm.Errorf("Error writing history file: %s\n", err)
  128. } else {
  129. line.WriteHistory(f)
  130. f.Close()
  131. }
  132. }