diff --git a/ast/ArgumentList.go b/ast/ArgumentList.go index 0c94ecf3..b142adde 100755 --- a/ast/ArgumentList.go +++ b/ast/ArgumentList.go @@ -134,6 +134,7 @@ func (e *ArgumentList) Evaluate(dataContext IDataContext, memory *WorkingMemory) for i, exp := range e.Arguments { val, err := exp.Evaluate(dataContext, memory) if err != nil { + return values, err } values[i] = val diff --git a/ast/ArrayMapSelector.go b/ast/ArrayMapSelector.go index 010aa619..03af3c10 100755 --- a/ast/ArrayMapSelector.go +++ b/ast/ArrayMapSelector.go @@ -128,6 +128,7 @@ func (e *ArrayMapSelector) Evaluate(dataContext IDataContext, memory *WorkingMem if e.Expression != nil { val, err := e.Expression.Evaluate(dataContext, memory) if err != nil { + return val, err } e.Value = val diff --git a/ast/DataContext.go b/ast/DataContext.go index ca739a37..a5908bb8 100755 --- a/ast/DataContext.go +++ b/ast/DataContext.go @@ -39,6 +39,7 @@ type DataContext struct { retracted []string variableChangeCount uint64 complete bool + ruleEntry *RuleEntry } func (ctx *DataContext) GetKeys() []string { @@ -63,6 +64,15 @@ func (ctx *DataContext) IsComplete() bool { return ctx.complete } +func (ctx *DataContext) GetRuleEntry() *RuleEntry { + + return ctx.ruleEntry +} + +func (ctx *DataContext) SetRuleEntry(re *RuleEntry) { + ctx.ruleEntry = re +} + // IDataContext is the interface for the DataContext struct. type IDataContext interface { ResetVariableChangeCount() @@ -74,6 +84,8 @@ type IDataContext interface { Get(key string) model.ValueNode GetKeys() []string + SetRuleEntry(re *RuleEntry) + GetRuleEntry() *RuleEntry Retract(key string) IsRetracted(key string) bool Complete() diff --git a/ast/RuleEntry.go b/ast/RuleEntry.go index 0e5e5184..165fa57e 100755 --- a/ast/RuleEntry.go +++ b/ast/RuleEntry.go @@ -167,7 +167,7 @@ func (e *RuleEntry) SetGrlText(grlText string) { func (e *RuleEntry) Evaluate(ctx context.Context, dataContext IDataContext, memory *WorkingMemory) (can bool, err error) { if ctx.Err() != nil { - return false, ctx.Err() + return false, fmt.Errorf("context error on evaluating rule %s. got %w", e.RuleName, ctx.Err()) } defer func() { if r := recover(); r != nil { @@ -176,17 +176,18 @@ func (e *RuleEntry) Evaluate(ctx context.Context, dataContext IDataContext, memo } }() if e.Retracted { + return false, nil } val, err := e.WhenScope.Evaluate(dataContext, memory) if err != nil { - AstLog.Errorf("Error while evaluating rule %s, got %v", e.RuleName, err) + AstLog.Errorf("Error while evaluating rule '%s', got %v", e.RuleName, err) - return false, err + return false, fmt.Errorf("evaluating expression in rule '%s' the when raised an error. got %v", dataContext.GetRuleEntry().RuleName, err) } if val.Kind() != reflect.Bool { - return false, fmt.Errorf("expression in when is not a boolean expression : %s", e.WhenScope.Expression.GetGrlText()) + return false, fmt.Errorf("evaluating expression in rule '%s', the when is not a boolean expression : %s", dataContext.GetRuleEntry().RuleName, e.WhenScope.Expression.GetGrlText()) } return val.Bool(), nil @@ -196,7 +197,7 @@ func (e *RuleEntry) Evaluate(ctx context.Context, dataContext IDataContext, memo func (e *RuleEntry) Execute(ctx context.Context, dataContext IDataContext, memory *WorkingMemory) (err error) { if ctx.Err() != nil { - return ctx.Err() + return fmt.Errorf("context error on executing rule %s. got %w", e.RuleName, ctx.Err()) } if e.ThenScope == nil { @@ -204,7 +205,7 @@ func (e *RuleEntry) Execute(ctx context.Context, dataContext IDataContext, memor } defer func() { if r := recover(); r != nil { - err = fmt.Errorf("rule engine execute panic ! recovered : %v", r) + err = fmt.Errorf("rule engine execute panic on rule %s ! recovered : %v", e.RuleName, r) } }() diff --git a/ast/Serializer.go b/ast/Serializer.go index 831bbac1..5dc9a96d 100755 --- a/ast/Serializer.go +++ b/ast/Serializer.go @@ -1535,11 +1535,15 @@ func (meta *ConstantMeta) ReadMetaFrom(reader io.Reader) error { return err } byteArr := make([]byte, length) - _, err = reader.Read(byteArr) + readCount, err := reader.Read(byteArr) if err != nil { return err } + if uint64(readCount) != length { + + return io.ErrShortBuffer + } meta.ValueBytes = byteArr b, err := ReadBoolFromReader(reader) diff --git a/engine/GruleEngine.go b/engine/GruleEngine.go index 628e8fab..72ab5ea3 100755 --- a/engine/GruleEngine.go +++ b/engine/GruleEngine.go @@ -218,6 +218,9 @@ func (g *GruleEngine) ExecuteWithContext(ctx context.Context, dataCtx ast.IDataC } } } + // set the current rule entry to run. This is for trace ability purpose + dataCtx.SetRuleEntry(runner) + // notify listeners that we are about to execute a rule entry then scope g.notifyExecuteRuleEntry(cycle, runner) // execute the top most prioritized rule