// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com). // All rights reserved. // parser.go package expr import ( "fmt" ) //-------- parser type parser struct { ctx exprContext } func NewParser(ctx exprContext) (p *parser) { p = &parser{ ctx: ctx, } return p } func (self *parser) parseFunction(scanner *scanner, tk *Token) (tree *term, err error) { name, _ := tk.Value.(string) funcObj := self.ctx.GetFuncInfo(name) if funcObj == nil { err = fmt.Errorf("unknown function %s()", name) return } maxArgs := funcObj.MaxArgs() if maxArgs < 0 { maxArgs = funcObj.MinArgs() + 10 } args := make([]*term, 0, maxArgs) lastSym := SymUnknown for lastSym != SymClosedRound && lastSym != SymEos { var subTree *ast if subTree, err = self.parse(scanner, SymComma, SymClosedRound); err == nil { if subTree.root != nil { args = append(args, subTree.root) } } else { break } lastSym = scanner.Previous().Sym } if err == nil { // TODO Check arguments tree = newFuncTerm(tk, args) } return } func (self *parser) parseList(scanner *scanner) (tree *term, err error) { args := make([]*term, 0) lastSym := SymUnknown for lastSym != SymClosedSquare && lastSym != SymEos { var subTree *ast if subTree, err = self.parse(scanner, SymComma, SymClosedSquare); err == nil { if subTree.root != nil { args = append(args, subTree.root) } } else { break } lastSym = scanner.Previous().Sym } if err == nil { // TODO Check arguments tree = newListTerm(args) } return } func (self *parser) parse(scanner *scanner, termSymbols ...Symbol) (tree *ast, err error) { tree = NewAst() firstToken := true lastSym := SymUnknown for tk := scanner.Next(); err == nil && tk != nil && !tk.IsTerm(termSymbols); tk = scanner.Next() { if tk.Sym == SymComment { continue } if tk.Sym == SymSemiColon { tree.ToForest() continue } //fmt.Println("Token:", tk) if firstToken && (tk.Sym == SymMinus || tk.Sym == SymPlus) { if tk.Sym == SymMinus { tk.Sym = SymChangeSign } else { tk.Sym = SymUnchangeSign } } firstToken = false switch tk.Sym { case SymOpenRound: var subTree *ast if subTree, err = self.parse(scanner, SymClosedRound); err == nil { subTree.root.priority = priValue tree.addTerm(subTree.root) } case SymFunction: var funcTerm *term if funcTerm, err = self.parseFunction(scanner, tk); err == nil { err = tree.addTerm(funcTerm) } case SymOpenSquare: var listTerm *term if listTerm, err = self.parseList(scanner); err == nil { err = tree.addTerm(listTerm) } case SymEqual: if lastSym == SymIdentifier { err = tree.addToken(tk) } else { err = fmt.Errorf(`assign operator (%q) must be preceded by a variable`, tk.source) } default: err = tree.addToken(tk) } lastSym = tk.Sym } return }