mirror of
https://github.com/mudler/LocalAI.git
synced 2026-04-01 05:36:49 -04:00
* feat: add distributed mode (experimental) Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * fix data races, mutexes, transactions Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * refactorings Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * fixups Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * fix events and tool stream in agent chat Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * use ginkgo Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * refactoring and consolidation Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * refactoring and consolidation Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * refactoring and consolidation Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * refactoring and consolidation Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * refactoring and consolidation Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * refactoring and consolidation Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * refactoring and consolidation Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * refactoring and consolidation Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * fix(cron): compute correctly time boundaries avoiding re-triggering Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * enhancements, refactorings Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * do not flood of healthy checks Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * do not list obvious backends as text backends Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * tests fixups Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * refactoring and consolidation Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * Drop redundant healthcheck Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * enhancements, refactorings Signed-off-by: Ettore Di Giacinto <mudler@localai.io> --------- Signed-off-by: Ettore Di Giacinto <mudler@localai.io>
137 lines
3.2 KiB
Go
137 lines
3.2 KiB
Go
package peg
|
|
|
|
import "fmt"
|
|
|
|
// Arena stores parser instances and provides the Parse entry point.
|
|
type Arena struct {
|
|
parsers []Parser
|
|
rules map[string]ParserID
|
|
root ParserID
|
|
}
|
|
|
|
func NewArena() *Arena {
|
|
return &Arena{
|
|
rules: make(map[string]ParserID),
|
|
root: InvalidParserID,
|
|
}
|
|
}
|
|
|
|
func (a *Arena) addParser(p Parser) ParserID {
|
|
id := ParserID(len(a.parsers))
|
|
a.parsers = append(a.parsers, p)
|
|
return id
|
|
}
|
|
|
|
func (a *Arena) Get(id ParserID) Parser {
|
|
return a.parsers[id]
|
|
}
|
|
|
|
func (a *Arena) Root() ParserID {
|
|
return a.root
|
|
}
|
|
|
|
func (a *Arena) SetRoot(id ParserID) {
|
|
a.root = id
|
|
}
|
|
|
|
func (a *Arena) GetRule(name string) ParserID {
|
|
id, ok := a.rules[name]
|
|
if !ok {
|
|
panic(fmt.Sprintf("Rule not found: %s", name))
|
|
}
|
|
return id
|
|
}
|
|
|
|
func (a *Arena) HasRule(name string) bool {
|
|
_, ok := a.rules[name]
|
|
return ok
|
|
}
|
|
|
|
// Parse parses from the root parser.
|
|
func (a *Arena) Parse(ctx *ParseContext) ParseResult {
|
|
if a.root == InvalidParserID {
|
|
panic("No root parser set")
|
|
}
|
|
return a.ParseAt(a.root, ctx, 0)
|
|
}
|
|
|
|
// ParseFrom parses from the root parser starting at position start.
|
|
func (a *Arena) ParseFrom(ctx *ParseContext, start int) ParseResult {
|
|
if a.root == InvalidParserID {
|
|
panic("No root parser set")
|
|
}
|
|
return a.ParseAt(a.root, ctx, start)
|
|
}
|
|
|
|
// ParseAt parses using a specific parser at a given position.
|
|
func (a *Arena) ParseAt(id ParserID, ctx *ParseContext, start int) ParseResult {
|
|
parser := a.parsers[id]
|
|
return parser.parse(a, ctx, start)
|
|
}
|
|
|
|
// ParseAnywhere tries parsing from every position in the input until it succeeds.
|
|
func (a *Arena) ParseAnywhere(ctx *ParseContext) ParseResult {
|
|
if a.root == InvalidParserID {
|
|
panic("No root parser set")
|
|
}
|
|
if len(ctx.Input) == 0 {
|
|
return a.ParseAt(a.root, ctx, 0)
|
|
}
|
|
for i := range len(ctx.Input) {
|
|
result := a.ParseAt(a.root, ctx, i)
|
|
if result.Type == Success || i == len(ctx.Input)-1 {
|
|
return result
|
|
}
|
|
}
|
|
return NewParseResult(Fail, 0)
|
|
}
|
|
|
|
// resolveRefs walks all parsers and replaces refs with resolved rule IDs.
|
|
func (a *Arena) resolveRefs() {
|
|
for i, p := range a.parsers {
|
|
switch pt := p.(type) {
|
|
case *SequenceParser:
|
|
for j, child := range pt.Children {
|
|
pt.Children[j] = a.resolveRef(child)
|
|
}
|
|
case *ChoiceParser:
|
|
for j, child := range pt.Children {
|
|
pt.Children[j] = a.resolveRef(child)
|
|
}
|
|
case *RepetitionParser:
|
|
pt.Child = a.resolveRef(pt.Child)
|
|
case *AndParser:
|
|
pt.Child = a.resolveRef(pt.Child)
|
|
case *NotParser:
|
|
pt.Child = a.resolveRef(pt.Child)
|
|
case *RuleParser:
|
|
pt.Child = a.resolveRef(pt.Child)
|
|
case *TagParser:
|
|
pt.Child = a.resolveRef(pt.Child)
|
|
case *AtomicParser:
|
|
pt.Child = a.resolveRef(pt.Child)
|
|
case *SchemaParser:
|
|
pt.Child = a.resolveRef(pt.Child)
|
|
// Leaf parsers — no children to resolve
|
|
case *EpsilonParser, *StartParser, *EndParser, *LiteralParser,
|
|
*AnyParser, *SpaceParser, *CharsParser, *JSONStringParser,
|
|
*PythonDictStringParser, *UntilParser, *RefParser, *JSONParser,
|
|
*jsonNumberParser:
|
|
// nothing to do
|
|
default:
|
|
_ = i // satisfy compiler
|
|
}
|
|
}
|
|
|
|
if a.root != InvalidParserID {
|
|
a.root = a.resolveRef(a.root)
|
|
}
|
|
}
|
|
|
|
func (a *Arena) resolveRef(id ParserID) ParserID {
|
|
if ref, ok := a.parsers[id].(*RefParser); ok {
|
|
return a.GetRule(ref.Name)
|
|
}
|
|
return id
|
|
}
|