Ver código fonte

feat: Initial code for ECAL subsystem

Matthias Ladkau 5 anos atrás
pai
commit
8d568a2087
6 arquivos alterados com 391 adições e 0 exclusões
  1. 16 0
      ecal/interpreter/debug.go
  2. 68 0
      ecal/interpreter/scope.go
  3. 35 0
      ecal/interpreter/types.go
  4. 179 0
      ecal/logging.go
  5. 62 0
      ecal/logging_test.go
  6. 31 0
      ecal/run.go

+ 16 - 0
ecal/interpreter/debug.go

@@ -0,0 +1,16 @@
+/*
+ * EliasDB
+ *
+ * Copyright 2016 Matthias Ladkau. All rights reserved.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+/*
+Package interpreter contains the ECAL interpreter.
+*/
+package interpreter
+
+// TODO: Stacktrace

+ 68 - 0
ecal/interpreter/scope.go

@@ -0,0 +1,68 @@
+/*
+ * EliasDB
+ *
+ * Copyright 2016 Matthias Ladkau. All rights reserved.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+/*
+Package interpreter contains the ECAL interpreter.
+*/
+package interpreter
+
+import (
+	"sync"
+
+	"devt.de/krotik/common/lang/ecal/parser"
+)
+
+// TODO: Scope with value buckets which can be read only - auto provide access to parent scopes
+
+/*
+DataBucket models a storage bucket for data.
+*/
+type DataBucket struct {
+	data     interface{} // Data of this bucket
+	canWrite bool        // Flag if data can be written to this bucket
+}
+
+/*
+Scope models an ECAL scope. It is used to store variable data.
+*/
+type Scope struct {
+	name    string                 // Name of the scope
+	parent  *Scope                 // Parent scope
+	storage map[string]*DataBucket // Storage for variables
+	lock    sync.RWMutex           // Lock for this scope
+}
+
+/*
+NewChild creates a new child scope.
+*/
+func (s *Scope) NewChild(name string) parser.VarsScope {
+	return nil
+}
+
+/*
+SetValue sets a new value for a variable.
+*/
+func (s *Scope) SetValue(varName string, varValue interface{}) error {
+	return nil
+}
+
+/*
+GetValue gets the current value of a variable.
+*/
+func (s *Scope) GetValue(varName string) (interface{}, bool, error) {
+	return nil, false, nil
+}
+
+/*
+String returns a string representation of this variable scope.
+*/
+func (s *Scope) String() string {
+	return ""
+}

+ 35 - 0
ecal/interpreter/types.go

@@ -0,0 +1,35 @@
+/*
+ * EliasDB
+ *
+ * Copyright 2016 Matthias Ladkau. All rights reserved.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+/*
+Package interpreter contains the ECAL interpreter.
+*/
+package interpreter
+
+/*
+Logger is required external object to which the interpreter releases its log messages.
+*/
+type Logger interface {
+
+	/*
+	   LogError adds a new error log message.
+	*/
+	LogError(v ...interface{})
+
+	/*
+	   LogInfo adds a new info log message.
+	*/
+	LogInfo(v ...interface{})
+
+	/*
+	   LogDebug adds a new debug log message.
+	*/
+	LogDebug(v ...interface{})
+}

+ 179 - 0
ecal/logging.go

@@ -0,0 +1,179 @@
+/*
+ * EliasDB
+ *
+ * Copyright 2016 Matthias Ladkau. All rights reserved.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+/*
+Package ecal contains the main API for the event condition language ECAL.
+*/
+package ecal
+
+import (
+	"fmt"
+	"log"
+
+	"devt.de/krotik/common/datautil"
+)
+
+// Logging
+// =======
+
+/*
+Logger is an interface for log message consumers.
+*/
+type Logger interface {
+
+	/*
+	   LogError adds a new error log message.
+	*/
+	LogError(p *Processor, v ...interface{})
+
+	/*
+	   LogInfo adds a new info log message.
+	*/
+	LogInfo(p *Processor, v ...interface{})
+
+	/*
+	   LogDebug adds a new debug log message.
+	*/
+	LogDebug(p *Processor, v ...interface{})
+}
+
+/*
+MemoryLogger collects log messages in a RingBuffer in memory.
+*/
+type MemoryLogger struct {
+	*datautil.RingBuffer
+}
+
+/*
+NewMemoryLogger returns a new memory logger instance.
+*/
+func NewMemoryLogger(size int) *MemoryLogger {
+	return &MemoryLogger{datautil.NewRingBuffer(size)}
+}
+
+/*
+LogError adds a new error log message.
+*/
+func (ml *MemoryLogger) LogError(p *Processor, m ...interface{}) {
+	ml.RingBuffer.Add(fmt.Sprintf("error: %v", fmt.Sprint(m...)))
+}
+
+/*
+LogInfo adds a new info log message.
+*/
+func (ml *MemoryLogger) LogInfo(p *Processor, m ...interface{}) {
+	ml.RingBuffer.Add(fmt.Sprintf("info: %v", fmt.Sprint(m...)))
+}
+
+/*
+LogDebug adds a new debug log message.
+*/
+func (ml *MemoryLogger) LogDebug(p *Processor, m ...interface{}) {
+	ml.RingBuffer.Add(fmt.Sprintf("debug: %v", fmt.Sprint(m...)))
+}
+
+/*
+Slice returns the contents of the current log as a slice.
+*/
+func (ml *MemoryLogger) Slice() []string {
+	sl := ml.RingBuffer.Slice()
+	ret := make([]string, len(sl))
+	for i, lm := range sl {
+		ret[i] = lm.(string)
+	}
+	return ret
+}
+
+/*
+Reset resets the current log.
+*/
+func (ml *MemoryLogger) Reset() {
+	ml.RingBuffer.Reset()
+}
+
+/*
+Size returns the current log size.
+*/
+func (ml *MemoryLogger) Size() int {
+	return ml.RingBuffer.Size()
+}
+
+/*
+String returns the current log as a string.
+*/
+func (ml *MemoryLogger) String() string {
+	return ml.RingBuffer.String()
+}
+
+/*
+StdOutLogger writes log messages to stdout.
+*/
+type StdOutLogger struct {
+	stdlog func(v ...interface{})
+}
+
+/*
+NewStdOutLogger returns a stdout logger instance.
+*/
+func NewStdOutLogger() Logger {
+	return &StdOutLogger{log.Print}
+}
+
+/*
+LogError adds a new error log message.
+*/
+func (sl *StdOutLogger) LogError(p *Processor, m ...interface{}) {
+	sl.stdlog(fmt.Sprintf("error: %v", fmt.Sprint(m...)))
+}
+
+/*
+LogInfo adds a new info log message.
+*/
+func (sl *StdOutLogger) LogInfo(p *Processor, m ...interface{}) {
+	sl.stdlog(fmt.Sprintf("error: %v", fmt.Sprint(m...)))
+}
+
+/*
+LogDebug adds a new debug log message.
+*/
+func (sl *StdOutLogger) LogDebug(p *Processor, m ...interface{}) {
+	sl.stdlog(fmt.Sprintf("error: %v", fmt.Sprint(m...)))
+}
+
+/*
+NullLogger discards log messages.
+*/
+type NullLogger struct {
+}
+
+/*
+NewNullLogger returns a null logger instance.
+*/
+func NewNullLogger() Logger {
+	return &NullLogger{}
+}
+
+/*
+LogError adds a new error log message.
+*/
+func (nl *NullLogger) LogError(p *Processor, m ...interface{}) {
+}
+
+/*
+LogInfo adds a new info log message.
+*/
+func (nl *NullLogger) LogInfo(p *Processor, m ...interface{}) {
+}
+
+/*
+LogDebug adds a new debug log message.
+*/
+func (nl *NullLogger) LogDebug(p *Processor, m ...interface{}) {
+}

+ 62 - 0
ecal/logging_test.go

@@ -0,0 +1,62 @@
+/*
+ * EliasDB
+ *
+ * Copyright 2016 Matthias Ladkau. All rights reserved.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+package ecal
+
+import (
+	"fmt"
+	"testing"
+)
+
+func TestLogging(t *testing.T) {
+
+	ml := NewMemoryLogger(5)
+
+	ml.LogDebug(nil, "test")
+	ml.LogInfo(nil, "test")
+
+	if ml.String() != `debug: test
+info: test` {
+		t.Error("Unexpected result:", ml.String())
+		return
+	}
+
+	if res := fmt.Sprint(ml.Slice()); res != "[debug: test info: test]" {
+		t.Error("Unexpected result:", res)
+		return
+	}
+
+	ml.Reset()
+
+	ml.LogError(nil, "test1")
+
+	if res := fmt.Sprint(ml.Slice()); res != "[error: test1]" {
+		t.Error("Unexpected result:", res)
+		return
+	}
+
+	if res := ml.Size(); res != 1 {
+		t.Error("Unexpected result:", res)
+		return
+	}
+
+	// Test that the functions can be called
+
+	nl := NewNullLogger()
+	nl.LogDebug(nil, "test")
+	nl.LogInfo(nil, "test")
+	nl.LogError(nil, "test")
+
+	sol := NewStdOutLogger()
+	sol.(*StdOutLogger).stdlog = func(v ...interface{}) {}
+	sol.LogDebug(nil, "test")
+	sol.LogInfo(nil, "test")
+	sol.LogError(nil, "test")
+}

+ 31 - 0
ecal/run.go

@@ -0,0 +1,31 @@
+/*
+ * EliasDB
+ *
+ * Copyright 2016 Matthias Ladkau. All rights reserved.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+/*
+Package ecal contains the main API for the event condition language ECAL.
+*/
+package ecal
+
+// TODO: Maybe API documentation - access comments during runtime
+
+/*
+Processor models a top level execution instance for ECAL.
+*/
+type Processor interface {
+}
+
+/*
+processor is the main implementation for the Processor interface.
+*/
+type processor struct {
+	// TODO: GM GraphManager is part of initial values published in the global scope
+
+	Logger
+}