interpreter.go 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. /*
  2. * EliasDB
  3. *
  4. * Copyright 2016 Matthias Ladkau. All rights reserved.
  5. *
  6. * This Source Code Form is subject to the terms of the Mozilla Public
  7. * License, v. 2.0. If a copy of the MPL was not distributed with this
  8. * file, You can obtain one at http://mozilla.org/MPL/2.0/.
  9. */
  10. package ecal
  11. import (
  12. "fmt"
  13. "io/ioutil"
  14. "path/filepath"
  15. "strings"
  16. "devt.de/krotik/common/fileutil"
  17. "devt.de/krotik/ecal/cli/tool"
  18. "devt.de/krotik/ecal/stdlib"
  19. "devt.de/krotik/ecal/util"
  20. "devt.de/krotik/eliasdb/config"
  21. "devt.de/krotik/eliasdb/ecal/dbfunc"
  22. "devt.de/krotik/eliasdb/graph"
  23. )
  24. /*
  25. ScriptingInterpreter models a ECAL script interpreter instance.
  26. */
  27. type ScriptingInterpreter struct {
  28. GM *graph.Manager // GraphManager for the interpreter
  29. Dir string // Root dir for interpreter
  30. EntryFile string // Entry file for the program
  31. LogLevel string // Log level string (Debug, Info, Error)
  32. LogFile string // Logfile (blank for stdout)
  33. RunDebugServer bool // Run a debug server
  34. DebugServerHost string // Debug server host
  35. DebugServerPort string // Debug server port
  36. }
  37. /*
  38. NewScriptingInterpreter returns a new ECAL scripting interpreter.
  39. */
  40. func NewScriptingInterpreter(scriptFolder string, gm *graph.Manager) *ScriptingInterpreter {
  41. return &ScriptingInterpreter{
  42. GM: gm,
  43. Dir: scriptFolder,
  44. EntryFile: filepath.Join(scriptFolder, config.Str(config.ECALEntryScript)),
  45. LogLevel: config.Str(config.ECALLogLevel),
  46. LogFile: config.Str(config.ECALLogFile),
  47. RunDebugServer: config.Bool(config.EnableECALDebugServer),
  48. DebugServerHost: config.Str(config.ECALDebugServerHost),
  49. DebugServerPort: config.Str(config.ECALDebugServerPort),
  50. }
  51. }
  52. /*
  53. dummyEntryFile is a small valid ECAL which does not do anything. It is used
  54. as the default entry file if no entry file exists.
  55. */
  56. const dummyEntryFile = `0 # Write your ECAL code here
  57. `
  58. /*
  59. Run runs the ECAL scripting interpreter.
  60. */
  61. func (si *ScriptingInterpreter) Run() error {
  62. var err error
  63. // Ensure we have a dummy entry point
  64. if ok, _ := fileutil.PathExists(si.EntryFile); !ok {
  65. err = ioutil.WriteFile(si.EntryFile, []byte(dummyEntryFile), 0600)
  66. }
  67. if err == nil {
  68. i := tool.NewCLIInterpreter()
  69. i.Dir = &si.Dir
  70. i.LogFile = &si.LogFile
  71. i.LogLevel = &si.LogLevel
  72. i.EntryFile = si.EntryFile
  73. i.LoadPlugins = true
  74. i.CreateRuntimeProvider("eliasdb-runtime")
  75. // Adding functions
  76. stdlib.AddStdlibPkg("db", "EliasDB related functions")
  77. stdlib.AddStdlibFunc("db", "storeNode", &dbfunc.StoreNodeFunc{GM: si.GM})
  78. stdlib.AddStdlibFunc("db", "removeNode", &dbfunc.RemoveNodeFunc{GM: si.GM})
  79. stdlib.AddStdlibFunc("db", "fetchNode", &dbfunc.FetchNodeFunc{GM: si.GM})
  80. stdlib.AddStdlibFunc("db", "storeEdge", &dbfunc.StoreEdgeFunc{GM: si.GM})
  81. stdlib.AddStdlibFunc("db", "removeEdge", &dbfunc.RemoveEdgeFunc{GM: si.GM})
  82. stdlib.AddStdlibFunc("db", "fetchEdge", &dbfunc.FetchEdgeFunc{GM: si.GM})
  83. stdlib.AddStdlibFunc("db", "traverse", &dbfunc.TraverseFunc{GM: si.GM})
  84. stdlib.AddStdlibFunc("db", "newTrans", &dbfunc.NewTransFunc{GM: si.GM})
  85. stdlib.AddStdlibFunc("db", "newRollingTrans", &dbfunc.NewRollingTransFunc{GM: si.GM})
  86. stdlib.AddStdlibFunc("db", "commit", &dbfunc.CommitTransFunc{GM: si.GM})
  87. stdlib.AddStdlibFunc("db", "query", &dbfunc.QueryFunc{GM: si.GM})
  88. stdlib.AddStdlibFunc("db", "graphQL", &dbfunc.GraphQLFunc{GM: si.GM})
  89. stdlib.AddStdlibFunc("db", "raiseGraphEventHandled", &dbfunc.RaiseGraphEventHandledFunc{})
  90. if err == nil {
  91. if si.RunDebugServer {
  92. di := tool.NewCLIDebugInterpreter(i)
  93. addr := fmt.Sprintf("%v:%v", si.DebugServerHost, si.DebugServerPort)
  94. di.DebugServerAddr = &addr
  95. di.RunDebugServer = &si.RunDebugServer
  96. falseFlag := false
  97. di.EchoDebugServer = &falseFlag
  98. di.Interactive = &falseFlag
  99. di.BreakOnStart = &falseFlag
  100. trueFlag := true
  101. di.BreakOnError = &trueFlag
  102. err = di.Interpret()
  103. } else {
  104. err = i.Interpret(false)
  105. }
  106. // Rules for the GraphManager are loaded after the code has been
  107. // executed and all rules have been added. The ECA processor can now be started.
  108. i.RuntimeProvider.Processor.Start()
  109. // EliasDB graph events can not be forwarded to ECAL via the eventbridge.
  110. si.GM.SetGraphRule(&EventBridge{
  111. Processor: i.RuntimeProvider.Processor,
  112. Logger: i.RuntimeProvider.Logger,
  113. })
  114. }
  115. }
  116. // Include a traceback if possible
  117. if ss, ok := err.(util.TraceableRuntimeError); ok {
  118. err = fmt.Errorf("%v\n %v", err.Error(), strings.Join(ss.GetTraceString(), "\n "))
  119. }
  120. return err
  121. }