provider.go 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  1. /*
  2. * ECAL
  3. *
  4. * Copyright 2020 Matthias Ladkau. All rights reserved.
  5. *
  6. * This Source Code Form is subject to the terms of the MIT
  7. * License, If a copy of the MIT License was not distributed with this
  8. * file, You can obtain one at https://opensource.org/licenses/MIT.
  9. */
  10. package interpreter
  11. import (
  12. "fmt"
  13. "os"
  14. "path/filepath"
  15. "sync"
  16. "devt.de/krotik/common/datautil"
  17. "devt.de/krotik/common/timeutil"
  18. "devt.de/krotik/ecal/config"
  19. "devt.de/krotik/ecal/engine"
  20. "devt.de/krotik/ecal/parser"
  21. "devt.de/krotik/ecal/util"
  22. )
  23. /*
  24. ecalRuntimeNew is used to instantiate ECAL runtime components.
  25. */
  26. type ecalRuntimeNew func(*ECALRuntimeProvider, *parser.ASTNode) parser.Runtime
  27. /*
  28. providerMap contains the mapping of AST nodes to runtime components for ECAL ASTs.
  29. */
  30. var providerMap = map[string]ecalRuntimeNew{
  31. parser.NodeEOF: invalidRuntimeInst,
  32. parser.NodeSTRING: stringValueRuntimeInst, // String constant
  33. parser.NodeNUMBER: numberValueRuntimeInst, // Number constant
  34. parser.NodeIDENTIFIER: identifierRuntimeInst, // Idendifier
  35. // Constructed tokens
  36. parser.NodeSTATEMENTS: statementsRuntimeInst, // List of statements
  37. parser.NodeFUNCCALL: voidRuntimeInst, // Function call
  38. parser.NodeCOMPACCESS: voidRuntimeInst, // Composition structure access
  39. parser.NodeLIST: listValueRuntimeInst, // List value
  40. parser.NodeMAP: mapValueRuntimeInst, // Map value
  41. parser.NodePARAMS: voidRuntimeInst, // Function parameters
  42. parser.NodeGUARD: guardRuntimeInst, // Guard expressions for conditional statements
  43. // Condition operators
  44. parser.NodeGEQ: greaterequalOpRuntimeInst,
  45. parser.NodeLEQ: lessequalOpRuntimeInst,
  46. parser.NodeNEQ: notequalOpRuntimeInst,
  47. parser.NodeEQ: equalOpRuntimeInst,
  48. parser.NodeGT: greaterOpRuntimeInst,
  49. parser.NodeLT: lessOpRuntimeInst,
  50. // Separators
  51. parser.NodeKVP: voidRuntimeInst, // Key-value pair
  52. parser.NodePRESET: voidRuntimeInst, // Preset value
  53. // Arithmetic operators
  54. parser.NodePLUS: plusOpRuntimeInst,
  55. parser.NodeMINUS: minusOpRuntimeInst,
  56. parser.NodeTIMES: timesOpRuntimeInst,
  57. parser.NodeDIV: divOpRuntimeInst,
  58. parser.NodeMODINT: modintOpRuntimeInst,
  59. parser.NodeDIVINT: divintOpRuntimeInst,
  60. // Assignment statement
  61. parser.NodeASSIGN: assignmentRuntimeInst,
  62. parser.NodeLET: letRuntimeInst,
  63. // Import statement
  64. parser.NodeIMPORT: importRuntimeInst,
  65. parser.NodeAS: voidRuntimeInst,
  66. // Sink definition
  67. parser.NodeSINK: sinkRuntimeInst,
  68. parser.NodeKINDMATCH: kindMatchRuntimeInst,
  69. parser.NodeSCOPEMATCH: scopeMatchRuntimeInst,
  70. parser.NodeSTATEMATCH: stateMatchRuntimeInst,
  71. parser.NodePRIORITY: priorityRuntimeInst,
  72. parser.NodeSUPPRESSES: suppressesRuntimeInst,
  73. // Function definition
  74. parser.NodeFUNC: funcRuntimeInst,
  75. parser.NodeRETURN: returnRuntimeInst,
  76. // Boolean operators
  77. parser.NodeOR: orOpRuntimeInst,
  78. parser.NodeAND: andOpRuntimeInst,
  79. parser.NodeNOT: notOpRuntimeInst,
  80. // Condition operators
  81. parser.NodeLIKE: likeOpRuntimeInst,
  82. parser.NodeIN: inOpRuntimeInst,
  83. parser.NodeHASPREFIX: beginswithOpRuntimeInst,
  84. parser.NodeHASSUFFIX: endswithOpRuntimeInst,
  85. parser.NodeNOTIN: notinOpRuntimeInst,
  86. // Constant terminals
  87. parser.NodeFALSE: falseRuntimeInst,
  88. parser.NodeTRUE: trueRuntimeInst,
  89. parser.NodeNULL: nullRuntimeInst,
  90. // Conditional statements
  91. parser.NodeIF: ifRuntimeInst,
  92. // Loop statements
  93. parser.NodeLOOP: loopRuntimeInst,
  94. parser.NodeBREAK: breakRuntimeInst,
  95. parser.NodeCONTINUE: continueRuntimeInst,
  96. // Try statement
  97. parser.NodeTRY: tryRuntimeInst,
  98. parser.NodeEXCEPT: voidRuntimeInst,
  99. parser.NodeOTHERWISE: voidRuntimeInst,
  100. parser.NodeFINALLY: voidRuntimeInst,
  101. // Mutex block
  102. parser.NodeMUTEX: mutexRuntimeInst,
  103. }
  104. /*
  105. ECALRuntimeProvider is the factory object producing runtime objects for ECAL ASTs.
  106. */
  107. type ECALRuntimeProvider struct {
  108. Name string // Name to identify the input
  109. ImportLocator util.ECALImportLocator // Locator object for imports
  110. Logger util.Logger // Logger object for log messages
  111. Processor engine.Processor // Processor of the ECA engine
  112. Mutexes map[string]*sync.Mutex // Map of named mutexes
  113. MutexLog *datautil.RingBuffer // Ringbuffer to track locking events
  114. MutexeOwners map[string]uint64 // Map of mutex owners
  115. MutexesMutex *sync.Mutex // Mutex for mutexes map
  116. Cron *timeutil.Cron // Cron object for scheduled execution
  117. Debugger util.ECALDebugger // Optional: ECAL Debugger object
  118. }
  119. /*
  120. NewECALRuntimeProvider returns a new instance of a ECAL runtime provider.
  121. */
  122. func NewECALRuntimeProvider(name string, importLocator util.ECALImportLocator, logger util.Logger) *ECALRuntimeProvider {
  123. if importLocator == nil {
  124. // By default imports are located in the current directory
  125. importLocator = &util.FileImportLocator{Root: filepath.Dir(os.Args[0])}
  126. }
  127. if logger == nil {
  128. // By default we just have a memory logger
  129. logger = util.NewMemoryLogger(100)
  130. }
  131. proc := engine.NewProcessor(config.Int(config.WorkerCount))
  132. // By default ECAL should stop the triggering sequence of sinks after the
  133. // first sink that returns a sinkerror.
  134. proc.SetFailOnFirstErrorInTriggerSequence(true)
  135. cron := timeutil.NewCron()
  136. cron.Start()
  137. return &ECALRuntimeProvider{name, importLocator, logger, proc,
  138. make(map[string]*sync.Mutex), datautil.NewRingBuffer(1024), make(map[string]uint64), &sync.Mutex{}, cron, nil}
  139. }
  140. /*
  141. Runtime returns a runtime component for a given ASTNode.
  142. */
  143. func (erp *ECALRuntimeProvider) Runtime(node *parser.ASTNode) parser.Runtime {
  144. if instFunc, ok := providerMap[node.Name]; ok {
  145. return instFunc(erp, node)
  146. }
  147. return invalidRuntimeInst(erp, node)
  148. }
  149. /*
  150. NewRuntimeError creates a new RuntimeError object.
  151. */
  152. func (erp *ECALRuntimeProvider) NewRuntimeError(t error, d string, node *parser.ASTNode) error {
  153. source := erp.Name
  154. if node.Token != nil {
  155. source = fmt.Sprintf("%v (%v)", source, node.Token.Lsource)
  156. }
  157. return util.NewRuntimeError(source, t, d, node)
  158. }
  159. /*
  160. NewThreadID creates a new thread ID unique to this runtime provider instance.
  161. This ID can be safely used for the thread ID when calling Eval on a
  162. parser.Runtime instance.
  163. */
  164. func (erp *ECALRuntimeProvider) NewThreadID() uint64 {
  165. return erp.Processor.ThreadPool().NewThreadID()
  166. }