Skip to content

Commit

Permalink
feat: Merging 1.4.0 release
Browse files Browse the repository at this point in the history
  • Loading branch information
krotik committed Jan 9, 2021
1 parent 30700c8 commit 0bc3df0
Show file tree
Hide file tree
Showing 15 changed files with 741 additions and 114 deletions.
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
ecal
/ecal
/ecal.exe
/.cache
/.cover
/.ecal_console_history
Expand All @@ -7,6 +8,8 @@ ecal
/coverage.html
/dist
/build
/examples/embedding/embedding
/examples/plugin/*.so
/ecal-support/node_modules
/ecal-support/out
/ecal-support/*.vsix
Expand Down
42 changes: 42 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,48 @@

All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.

## [1.4.0](https://devt.de///compare/v1.3.3...v1.4.0) (2021-01-09)


### Features

* Better pretty printer ([18e42f7](https://devt.de///commit/18e42f771dc386a8a6cfb9329f59c5a246934be0))

### [1.3.3](https://devt.de///compare/v1.3.2...v1.3.3) (2021-01-01)


### Bug Fixes

* Not stopping debug server if not running in interactive mode ([4d62c35](https://devt.de///commit/4d62c353384d5cc718b891540abf0e5e344d9326))

### [1.3.2](https://devt.de///compare/v1.3.1...v1.3.2) (2020-12-30)


### Bug Fixes

* Adding error display when reloading interpreter state ([f5cc392](https://devt.de///commit/f5cc392a9cd4dd2a1d743fd9f1bc54bb71f1484a))

### [1.3.1](https://devt.de///compare/v1.3.0...v1.3.1) (2020-12-30)


### Bug Fixes

* Stopping and starting the processor when loading the initial file. ([981956f](https://devt.de///commit/981956ff9309b8395081d25a2c5711d872818015))

## [1.3.0](https://devt.de///compare/v1.2.0...v1.3.0) (2020-12-29)


### Features

* Adding conversion helper for JSON objects ([1050423](https://devt.de///commit/1050423c453169f22da029a52f131e2d3054a1f1))

## [1.2.0](https://devt.de///compare/v1.1.0...v1.2.0) (2020-12-26)


### Features

* Adding conversion helper for JSON objects ([0454de3](https://devt.de///commit/0454de30f32b70cb936675c86bf6bdafd4e4bc3b))

## [1.1.0](https://devt.de///compare/v1.0.4...v1.1.0) (2020-12-13)


Expand Down
31 changes: 22 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,10 @@ ECAL

ECAL is an ECA (Event Condition Action) language for concurrent event processing. ECAL can define event-based systems using rules which are triggered by events. ECAL is intended to be embedded into other software to provide an easy to use scripting language which can react to external events.

<p>
<a href="https://void.devt.de/pub/ecal/coverage.txt"><img src="https://void.devt.de/pub/ecal/test_result.svg" alt="Code coverage"></a>
<a href="https://goreportcard.com/report/devt.de/krotik/ecal">
<img src="https://goreportcard.com/badge/devt.de/krotik/ecal?style=flat-square" alt="Go Report Card"></a>
<a href="https://godoc.org/devt.de/krotik/ecal">
<img src="https://godoc.org/devt.de/krotik/ecal?status.svg" alt="Go Doc"></a>
</p>
[![Code coverage](https://void.devt.de/pub/ecal/test_result.svg)](https://void.devt.de/pub/ecal/coverage.txt)
[![Go Report Card](https://goreportcard.com/badge/devt.de/krotik/ecal?style=flat-square)](https://goreportcard.com/report/devt.de/krotik/ecal)
[![Go Reference](https://pkg.go.dev/badge/krotik/ecal.svg)](https://pkg.go.dev/devt.de/krotik/ecal)
[![Mentioned in Awesome Go](https://awesome.re/mentioned-badge-flat.svg)](https://github.com/avelino/awesome-go)

Features
--------
Expand Down Expand Up @@ -83,7 +80,7 @@ The interpreter can be run in debug mode which adds debug commands to the consol

It is possible to package your ECAL project into an executable that can be run without a separate ECAL interpreter. Run the `sh pack.sh` and see the script for details.

### Embedding ECAL
### Embedding ECAL and using event processing

The primary purpose of ECAL is to be a simple multi-purpose language which can be embedded into other software:
- It has a minimal (quite generic) syntax.
Expand Down Expand Up @@ -115,9 +112,11 @@ If events are to be used then the processor of the runtime provider needs to be
```
rtp.Processor.Start()
```
The processor must be started *after* all sinks have been declared and *before* events are thrown.

Events can then be injected into the interpreter.
```
monitor, err := rtp.Processor.AddEventAndWait(engine.NewEvent("MyEvent", []string{"foo", "bar"}, map[interface{}]interface{}{
monitor, err := rtp.Processor.AddEventAndWait(engine.NewEvent("MyEvent", []string{"foo", "bar", "myevent"}, map[interface{}]interface{}{
"data1": 123,
"data2": "123",
}), nil)
Expand All @@ -126,6 +125,20 @@ All errors are collected in the returned monitor.
```
monitor.RootMonitor().AllErrors()
```
The above event could be handled in ECAL with the following sinks:
```
sink mysink
kindmatch [ "foo.bar.myevent" ],
{
log("Got event: ", event)
}
sink mysink2
kindmatch [ "foo.*.*" ],
{
log("Got event: ", event)
}
```

### Using Go plugins in ECAL

Expand Down
29 changes: 18 additions & 11 deletions cli/tool/debug.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,16 +45,16 @@ type CLIDebugInterpreter struct {
BreakOnStart *bool // Flag if the debugger should stop the execution on start
BreakOnError *bool // Flag if the debugger should stop when encountering an error

// Log output
LogOut io.Writer // Log output

LogOut io.Writer
debugServer *debugTelnetServer // Debug server if started
}

/*
NewCLIDebugInterpreter wraps an existing CLIInterpreter object and adds capabilities.
*/
func NewCLIDebugInterpreter(i *CLIInterpreter) *CLIDebugInterpreter {
return &CLIDebugInterpreter{i, nil, nil, nil, nil, nil, nil, os.Stdout}
return &CLIDebugInterpreter{i, nil, nil, nil, nil, nil, nil, os.Stdout, nil}
}

/*
Expand Down Expand Up @@ -112,20 +112,17 @@ func (i *CLIDebugInterpreter) Interpret() error {

// Start the debug server

debugServer := &debugTelnetServer{*i.DebugServerAddr, "ECALDebugServer: ",
i.debugServer = &debugTelnetServer{*i.DebugServerAddr, "ECALDebugServer: ",
nil, true, *i.EchoDebugServer, i, i.RuntimeProvider.Logger}

wg := &sync.WaitGroup{}
wg.Add(1)
go debugServer.Run(wg)
go i.debugServer.Run(wg)
wg.Wait()

defer func() {
if debugServer.listener != nil {
debugServer.listen = false
debugServer.listener.Close() // Attempt to cleanup
}
}()
if *i.Interactive {
defer i.StopDebugServer()
}
}

err = i.CLIInterpreter.Interpret(*i.Interactive)
Expand All @@ -134,6 +131,16 @@ func (i *CLIDebugInterpreter) Interpret() error {
return err
}

/*
StopDebugServer stops the debug server if it was started.
*/
func (i *CLIDebugInterpreter) StopDebugServer() {
if i.debugServer != nil && i.debugServer.listener != nil {
i.debugServer.listen = false
i.debugServer.listener.Close() // Attempt to cleanup
}
}

/*
LoadInitialFile clears the global scope and reloads the initial file.
*/
Expand Down
56 changes: 36 additions & 20 deletions cli/tool/format.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,6 @@ import (
Format formats a given set of ECAL files.
*/
func Format() error {
var err error

wd, _ := os.Getwd()

dir := flag.String("dir", wd, "Root directory for ECAL files")
Expand Down Expand Up @@ -54,31 +52,49 @@ func Format() error {

fmt.Fprintln(flag.CommandLine.Output(), fmt.Sprintf("Formatting all %v files in %v", *ext, *dir))

err = filepath.Walk(*dir,
func(path string, i os.FileInfo, err error) error {
if err == nil && !i.IsDir() {
var data []byte
var ast *parser.ASTNode
var srcFormatted string
return FormatFiles(*dir, *ext)
}

/*
FormatFiles formats all ECAL files in a given directory with a given ending.
*/
func FormatFiles(dir string, ext string) error {
var err error

// Try to resolve symbolic links

scanDir, lerr := os.Readlink(dir)
if lerr != nil {
scanDir = dir
}

if err == nil {
err = filepath.Walk(scanDir,
func(path string, i os.FileInfo, err error) error {
if err == nil && !i.IsDir() {
var data []byte
var ast *parser.ASTNode
var srcFormatted string

if strings.HasSuffix(path, *ext) {
if data, err = ioutil.ReadFile(path); err == nil {
var ferr error
if strings.HasSuffix(path, ext) {
if data, err = ioutil.ReadFile(path); err == nil {
var ferr error

if ast, ferr = parser.Parse(path, string(data)); ferr == nil {
if srcFormatted, ferr = parser.PrettyPrint(ast); ferr == nil {
ioutil.WriteFile(path, []byte(srcFormatted), i.Mode())
if ast, ferr = parser.Parse(path, string(data)); ferr == nil {
if srcFormatted, ferr = parser.PrettyPrint(ast); ferr == nil {
ioutil.WriteFile(path, []byte(fmt.Sprintln(srcFormatted)), i.Mode())
}
}
}

if ferr != nil {
fmt.Fprintln(flag.CommandLine.Output(), fmt.Sprintf("Could not format %v: %v", path, ferr))
if ferr != nil {
fmt.Fprintln(flag.CommandLine.Output(), fmt.Sprintf("Could not format %v: %v", path, ferr))
}
}
}
}
}
return err
})
return err
})
}

return err
}
44 changes: 36 additions & 8 deletions cli/tool/interpret.go
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,9 @@ LoadInitialFile clears the global scope and reloads the initial file.
func (i *CLIInterpreter) LoadInitialFile(tid uint64) error {
var err error

i.RuntimeProvider.Processor.Finish()
i.RuntimeProvider.Processor.Reset()

if i.CustomHandler != nil {
i.CustomHandler.LoadInitialFile(tid)
}
Expand All @@ -203,6 +206,8 @@ func (i *CLIInterpreter) LoadInitialFile(tid uint64) error {
}
}

i.RuntimeProvider.Processor.Start()

return err
}

Expand Down Expand Up @@ -363,22 +368,18 @@ func (i *CLIInterpreter) HandleInput(ot OutputTerminal, line string, tid uint64)
ot.WriteString(fmt.Sprint("\n"))
ot.WriteString(fmt.Sprint("Console supports all normal ECAL statements and the following special commands:\n"))
ot.WriteString(fmt.Sprint("\n"))
ot.WriteString(fmt.Sprint(" @format - Format all .ecal files in the current root directory.\n"))
ot.WriteString(fmt.Sprint(" @reload - Clear the interpreter and reload the initial file if it was given.\n"))
ot.WriteString(fmt.Sprint(" @sym [glob] - List all available inbuild functions and available stdlib packages of ECAL.\n"))
ot.WriteString(fmt.Sprint(" @std <package> [glob] - List all available constants and functions of a stdlib package.\n"))
ot.WriteString(fmt.Sprint(" @sym [glob] - List all available inbuild functions and available stdlib packages of ECAL.\n"))
if i.CustomHelpString != "" {
ot.WriteString(i.CustomHelpString)
}
ot.WriteString(fmt.Sprint("\n"))
ot.WriteString(fmt.Sprint("Add an argument after a list command to do a full text search. The search string should be in glob format.\n"))

} else if strings.HasPrefix(line, "@reload") {

// Reload happens in a separate thread as it may be suspended on start

go i.LoadInitialFile(i.RuntimeProvider.NewThreadID())
ot.WriteString(fmt.Sprintln(fmt.Sprintln("Reloading interpreter state")))

} else if i.handleSpecialStatements(ot, line) {
return
} else if strings.HasPrefix(line, "@sym") {
i.displaySymbols(ot, strings.Split(line, " ")[1:])

Expand Down Expand Up @@ -416,6 +417,33 @@ func (i *CLIInterpreter) HandleInput(ot OutputTerminal, line string, tid uint64)
}
}

/*
handleSpecialStatements handles inbuild special statements.
*/
func (i *CLIInterpreter) handleSpecialStatements(ot OutputTerminal, line string) bool {

if strings.HasPrefix(line, "@format") {
err := FormatFiles(*i.Dir, ".ecal")
ot.WriteString(fmt.Sprintln(fmt.Sprintln("Files formatted:", err)))

return true

} else if strings.HasPrefix(line, "@reload") {

// Reload happens in a separate thread as it may be suspended on start

go func() {
err := i.LoadInitialFile(i.RuntimeProvider.NewThreadID())
ot.WriteString(fmt.Sprintln(fmt.Sprintln("Interpreter reloaded:", err)))
}()
ot.WriteString(fmt.Sprintln(fmt.Sprintln("Reloading interpreter state")))

return true
}

return false
}

/*
displaySymbols lists all available inbuild functions and available stdlib packages of ECAL.
*/
Expand Down
7 changes: 4 additions & 3 deletions cli/tool/interpret_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -323,7 +323,7 @@ func TestHandleInput(t *testing.T) {
l2 := ""
tin.LogLevel = &l2

testTerm.in = []string{"?", "@reload", "@sym", "@std", "@cus", "q"}
testTerm.in = []string{"?", "@format", "@reload", "@sym", "@std", "@cus", "q"}

if err := tin.Interpret(true); err != nil {
t.Error("Unexpected result:", err)
Expand All @@ -346,7 +346,7 @@ func TestHandleInput(t *testing.T) {
return
}

if testTerm.out.String() != `╒═════════════════╤═══════════════════════════════╕
if strings.HasSuffix(testTerm.out.String(), `╒═════════════════╤═══════════════════════════════╕
│Inbuild function │Description │
╞═════════════════╪═══════════════════════════════╡
│raise │Raise returns an error object. │
Expand All @@ -364,7 +364,8 @@ func TestHandleInput(t *testing.T) {
│foo.Println │xxx │
│ │ │
╘════════════╧════════════╛
` {
`) {
t.Error("Unexpected result:", testTerm.out.String())
return
}
Expand Down
2 changes: 1 addition & 1 deletion config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import (
/*
ProductVersion is the current version of ECAL
*/
const ProductVersion = "1.1.0"
const ProductVersion = "1.4.0"

/*
Known configuration options for ECAL
Expand Down
4 changes: 2 additions & 2 deletions parser/lexer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -271,10 +271,10 @@ func TestCommentLexing(t *testing.T) {

input := `name /* foo
bar
x*/ 'b/* - */la' /*test*/`
x*/ 'b/* - */la' /*test*/`
if res := LexToList("mytest", input); fmt.Sprint(res) != `["name" /* foo
bar
x */ v:"b/* - */la" /* test */ EOF]` {
x */ v:"b/* - */la" /* test */ EOF]` {
t.Error("Unexpected lexer result:", res)
return
}
Expand Down
Loading

0 comments on commit 0bc3df0

Please sign in to comment.