directive.go raw

   1  package organ
   2  
   3  import (
   4  	"time"
   5  
   6  	"git.mleku.dev/mleku/dendrite/pkg/axiom"
   7  	"git.mleku.dev/mleku/dendrite/pkg/ratio"
   8  )
   9  
  10  // Directive is an operator input that bonds to the lattice with
  11  // maximum priority. Sticky directives survive dissolution.
  12  type Directive struct {
  13  	Text      string      `json:"text"`
  14  	Priority  ratio.Ratio `json:"priority"`
  15  	Timestamp time.Time   `json:"timestamp"`
  16  	Sticky    bool        `json:"sticky"`
  17  }
  18  
  19  // DirectiveElement wraps a Directive as a lattice Element.
  20  // It implements axiom.Element and axiom.StickyElement.
  21  type DirectiveElement struct {
  22  	Directive Directive
  23  }
  24  
  25  // Type returns "directive" — the type tag for directive elements.
  26  func (d DirectiveElement) Type() string { return "directive" }
  27  
  28  // Value returns the directive text.
  29  func (d DirectiveElement) Value() any { return d.Directive.Text }
  30  
  31  // IsSticky returns true if this directive survives dissolution.
  32  // This implements axiom.StickyElement.
  33  func (d DirectiveElement) IsSticky() bool { return d.Directive.Sticky }
  34  
  35  // DirectiveConstraint defines a lattice site that accepts directive elements.
  36  type DirectiveConstraint struct{}
  37  
  38  // Tag returns "directive".
  39  func (c DirectiveConstraint) Tag() string { return "directive" }
  40  
  41  // Admits returns true only for DirectiveElement instances.
  42  func (c DirectiveConstraint) Admits(e axiom.Element) bool {
  43  	_, ok := e.(DirectiveElement)
  44  	return ok
  45  }
  46  
  47  // NewDirectiveElement creates a DirectiveElement from text with default
  48  // high priority and stickiness.
  49  func NewDirectiveElement(text string) DirectiveElement {
  50  	return DirectiveElement{
  51  		Directive: Directive{
  52  			Text:      text,
  53  			Priority:  ratio.One,
  54  			Timestamp: time.Now(),
  55  			Sticky:    true,
  56  		},
  57  	}
  58  }
  59  
  60  // TokenizeDirective splits directive text into individual tokens,
  61  // each wrapped as a DirectiveElement. All tokens inherit the
  62  // parent directive's priority and stickiness.
  63  func TokenizeDirective(text string, sticky bool, priority ratio.Ratio) []DirectiveElement {
  64  	// Simple whitespace tokenization. The enzyme system will do
  65  	// finer-grained decomposition once it learns the directive vocabulary.
  66  	var tokens []DirectiveElement
  67  	start := -1
  68  	for i, r := range text {
  69  		if r == ' ' || r == '\t' || r == '\n' || r == '\r' {
  70  			if start >= 0 {
  71  				tokens = append(tokens, DirectiveElement{
  72  					Directive: Directive{
  73  						Text:      text[start:i],
  74  						Priority:  priority,
  75  						Timestamp: time.Now(),
  76  						Sticky:    sticky,
  77  					},
  78  				})
  79  				start = -1
  80  			}
  81  		} else if start < 0 {
  82  			start = i
  83  		}
  84  	}
  85  	if start >= 0 {
  86  		tokens = append(tokens, DirectiveElement{
  87  			Directive: Directive{
  88  				Text:      text[start:],
  89  				Priority:  priority,
  90  				Timestamp: time.Now(),
  91  				Sticky:    sticky,
  92  			},
  93  		})
  94  	}
  95  	return tokens
  96  }
  97