123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218 |
- /*
- * ECAL
- *
- * Copyright 2020 Matthias Ladkau. All rights reserved.
- *
- * This Source Code Form is subject to the terms of the MIT
- * License, If a copy of the MIT License was not distributed with this
- * file, You can obtain one at https://opensource.org/licenses/MIT.
- */
- package interpreter
- import (
- "fmt"
- "os"
- "path/filepath"
- "sync"
- "devt.de/krotik/common/timeutil"
- "devt.de/krotik/ecal/config"
- "devt.de/krotik/ecal/engine"
- "devt.de/krotik/ecal/parser"
- "devt.de/krotik/ecal/util"
- )
- /*
- ecalRuntimeNew is used to instantiate ECAL runtime components.
- */
- type ecalRuntimeNew func(*ECALRuntimeProvider, *parser.ASTNode) parser.Runtime
- /*
- providerMap contains the mapping of AST nodes to runtime components for ECAL ASTs.
- */
- var providerMap = map[string]ecalRuntimeNew{
- parser.NodeEOF: invalidRuntimeInst,
- parser.NodeSTRING: stringValueRuntimeInst, // String constant
- parser.NodeNUMBER: numberValueRuntimeInst, // Number constant
- parser.NodeIDENTIFIER: identifierRuntimeInst, // Idendifier
- // Constructed tokens
- parser.NodeSTATEMENTS: statementsRuntimeInst, // List of statements
- parser.NodeFUNCCALL: voidRuntimeInst, // Function call
- parser.NodeCOMPACCESS: voidRuntimeInst, // Composition structure access
- parser.NodeLIST: listValueRuntimeInst, // List value
- parser.NodeMAP: mapValueRuntimeInst, // Map value
- parser.NodePARAMS: voidRuntimeInst, // Function parameters
- parser.NodeGUARD: guardRuntimeInst, // Guard expressions for conditional statements
- // Condition operators
- parser.NodeGEQ: greaterequalOpRuntimeInst,
- parser.NodeLEQ: lessequalOpRuntimeInst,
- parser.NodeNEQ: notequalOpRuntimeInst,
- parser.NodeEQ: equalOpRuntimeInst,
- parser.NodeGT: greaterOpRuntimeInst,
- parser.NodeLT: lessOpRuntimeInst,
- // Separators
- parser.NodeKVP: voidRuntimeInst, // Key-value pair
- parser.NodePRESET: voidRuntimeInst, // Preset value
- // Arithmetic operators
- parser.NodePLUS: plusOpRuntimeInst,
- parser.NodeMINUS: minusOpRuntimeInst,
- parser.NodeTIMES: timesOpRuntimeInst,
- parser.NodeDIV: divOpRuntimeInst,
- parser.NodeMODINT: modintOpRuntimeInst,
- parser.NodeDIVINT: divintOpRuntimeInst,
- // Assignment statement
- parser.NodeASSIGN: assignmentRuntimeInst,
- parser.NodeLET: letRuntimeInst,
- // Import statement
- parser.NodeIMPORT: importRuntimeInst,
- parser.NodeAS: voidRuntimeInst,
- // Sink definition
- parser.NodeSINK: sinkRuntimeInst,
- parser.NodeKINDMATCH: kindMatchRuntimeInst,
- parser.NodeSCOPEMATCH: scopeMatchRuntimeInst,
- parser.NodeSTATEMATCH: stateMatchRuntimeInst,
- parser.NodePRIORITY: priorityRuntimeInst,
- parser.NodeSUPPRESSES: suppressesRuntimeInst,
- // Function definition
- parser.NodeFUNC: funcRuntimeInst,
- parser.NodeRETURN: returnRuntimeInst,
- // Boolean operators
- parser.NodeOR: orOpRuntimeInst,
- parser.NodeAND: andOpRuntimeInst,
- parser.NodeNOT: notOpRuntimeInst,
- // Condition operators
- parser.NodeLIKE: likeOpRuntimeInst,
- parser.NodeIN: inOpRuntimeInst,
- parser.NodeHASPREFIX: beginswithOpRuntimeInst,
- parser.NodeHASSUFFIX: endswithOpRuntimeInst,
- parser.NodeNOTIN: notinOpRuntimeInst,
- // Constant terminals
- parser.NodeFALSE: falseRuntimeInst,
- parser.NodeTRUE: trueRuntimeInst,
- parser.NodeNULL: nullRuntimeInst,
- // Conditional statements
- parser.NodeIF: ifRuntimeInst,
- // Loop statements
- parser.NodeLOOP: loopRuntimeInst,
- parser.NodeBREAK: breakRuntimeInst,
- parser.NodeCONTINUE: continueRuntimeInst,
- // Try statement
- parser.NodeTRY: tryRuntimeInst,
- parser.NodeEXCEPT: voidRuntimeInst,
- parser.NodeOTHERWISE: voidRuntimeInst,
- parser.NodeFINALLY: voidRuntimeInst,
- // Mutex block
- parser.NodeMUTEX: mutexRuntimeInst,
- }
- /*
- ECALRuntimeProvider is the factory object producing runtime objects for ECAL ASTs.
- */
- type ECALRuntimeProvider struct {
- Name string // Name to identify the input
- ImportLocator util.ECALImportLocator // Locator object for imports
- Logger util.Logger // Logger object for log messages
- Processor engine.Processor // Processor of the ECA engine
- Mutexes map[string]*sync.Mutex // Map of named mutexes
- Cron *timeutil.Cron // Cron object for scheduled execution
- Debugger util.ECALDebugger // Optional: ECAL Debugger object
- }
- /*
- NewECALRuntimeProvider returns a new instance of a ECAL runtime provider.
- */
- func NewECALRuntimeProvider(name string, importLocator util.ECALImportLocator, logger util.Logger) *ECALRuntimeProvider {
- if importLocator == nil {
- // By default imports are located in the current directory
- importLocator = &util.FileImportLocator{Root: filepath.Dir(os.Args[0])}
- }
- if logger == nil {
- // By default we just have a memory logger
- logger = util.NewMemoryLogger(100)
- }
- proc := engine.NewProcessor(config.Int(config.WorkerCount))
- // By default ECAL should stop the triggering sequence of sinks after the
- // first sink that returns a sinkerror.
- proc.SetFailOnFirstErrorInTriggerSequence(true)
- cron := timeutil.NewCron()
- cron.Start()
- return &ECALRuntimeProvider{name, importLocator, logger, proc,
- make(map[string]*sync.Mutex), cron, nil}
- }
- /*
- Runtime returns a runtime component for a given ASTNode.
- */
- func (erp *ECALRuntimeProvider) Runtime(node *parser.ASTNode) parser.Runtime {
- if instFunc, ok := providerMap[node.Name]; ok {
- return instFunc(erp, node)
- }
- return invalidRuntimeInst(erp, node)
- }
- /*
- NewRuntimeError creates a new RuntimeError object.
- */
- func (erp *ECALRuntimeProvider) NewRuntimeError(t error, d string, node *parser.ASTNode) error {
- source := erp.Name
- if node.Token != nil {
- source = fmt.Sprintf("%v (%v)", source, node.Token.Lsource)
- }
- return util.NewRuntimeError(source, t, d, node)
- }
- /*
- NewThreadID creates a new thread ID unique to this runtime provider instance.
- This ID can be safely used for the thread ID when calling Eval on a
- parser.Runtime instance.
- */
- func (erp *ECALRuntimeProvider) NewThreadID() uint64 {
- return erp.Processor.ThreadPool().NewThreadID()
- }
|