// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com). // All rights reserved. // parser.go package expr import ( "errors" "fmt" ) //-------- parser type parser struct { ctx ExprContext } func NewParser(ctx ExprContext) (p *parser) { p = &parser{ ctx: ctx, } return p } func (self *parser) parseFuncCall(scanner *scanner, allowVarRef bool, 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) args := make([]*term, 0, 10) lastSym := SymUnknown for lastSym != SymClosedRound && lastSym != SymEos { var subTree *ast if subTree, err = self.parseItem(scanner, allowVarRef, 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 if lastSym != SymClosedRound { err = errors.New("unterminate arguments list") } else { tree = newFuncCallTerm(tk, args) } } return } func (self *parser) parseFuncDef(scanner *scanner) (tree *term, err error) { // Example: "add = func(x,y) {x+y} var body *ast args := make([]*term, 0) tk := scanner.Next() for tk.Sym != SymClosedRound && tk.Sym != SymEos { if tk.Sym == SymIdentifier { t := newTerm(tk, nil) args = append(args, t) } else { err = tk.Errorf("invalid param %q, variable identifier expected", tk.source) break } tk = scanner.Next() } if err == nil && tk.Sym != SymClosedRound { err = tk.Errorf("unterminate function params list") } if err == nil { tk = scanner.Next() if tk.Sym == SymOpenBrace { body, err = self.parseGeneral(scanner, true, true, SymClosedBrace) } } if err == nil { // TODO Check arguments if scanner.Previous().Sym != SymClosedBrace { err = scanner.Previous().Errorf("not properly terminated function body") } else { tk = scanner.makeValueToken(SymExpression, "", body) tree = newFuncDefTerm(tk, args) } } return } func (self *parser) parseList(scanner *scanner, allowVarRef bool) (subtree *term, err error) { args := make([]*term, 0) lastSym := SymUnknown for lastSym != SymClosedSquare && lastSym != SymEos { var subTree *ast if subTree, err = self.parseItem(scanner, allowVarRef, 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 if lastSym != SymClosedSquare { err = scanner.Previous().Errorf("unterminate items list") } else { subtree = newListTerm(args) } } return } func (self *parser) parseSelectorCase(scanner *scanner, allowVarRef bool, defaultCase bool) (caseTerm *term, err error) { var filterList *term var caseExpr *ast tk := scanner.Next() startRow := tk.row startCol := tk.col if tk.Sym == SymOpenSquare { if defaultCase { err = tk.Errorf("case list in default clause") return } if filterList, err = self.parseList(scanner, allowVarRef); err != nil { return } tk = scanner.Next() startRow = tk.row startCol = tk.col } else if !defaultCase { filterList = newListTerm(make([]*term, 0)) } if tk.Sym == SymOpenBrace { if caseExpr, err = self.parseGeneral(scanner, true, allowVarRef, SymClosedBrace); err != nil { return } } else { err = tk.Errorf("selector-case expected, got %q", tk.source) } if err == nil { caseTerm = newSelectorCaseTerm(startRow, startCol, filterList, caseExpr) } return } func addSelectorCase(selectorTerm, caseTerm *term) { if len(selectorTerm.children) < 2 { caseListTerm := newListTermA(caseTerm) selectorTerm.children = append(selectorTerm.children, caseListTerm) } else { caseListTerm := selectorTerm.children[1] caseList, _ := caseListTerm.value().([]*term) caseList = append(caseList, caseTerm) caseListTerm.tk.Value = caseList } caseTerm.parent = selectorTerm } func (self *parser) parseSelector(scanner *scanner, tree *ast, allowVarRef bool) (selectorTerm *term, err error) { var caseTerm *term tk := scanner.makeToken(SymSelector, '?') if selectorTerm, err = tree.addToken2(tk); err != nil { return } if caseTerm, err = self.parseSelectorCase(scanner, allowVarRef, false); err == nil { addSelectorCase(selectorTerm, caseTerm) } return } func (self *parser) parseItem(scanner *scanner, allowVarRef bool, termSymbols ...Symbol) (tree *ast, err error) { return self.parseGeneral(scanner, false, allowVarRef, termSymbols...) } func (self *parser) Parse(scanner *scanner, termSymbols ...Symbol) (tree *ast, err error) { return self.parseGeneral(scanner, true, false, termSymbols...) } func (self *parser) parseGeneral(scanner *scanner, allowForest bool, allowVarRef bool, termSymbols ...Symbol) (tree *ast, err error) { var selectorTerm *term = nil var currentTerm *term = nil var tk *Token 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 { if allowForest { tree.ToForest() firstToken = true continue } else { err = tk.Errorf(`unexpected token %q, expected ",", "]", or ")"`, tk.source) break } } //fmt.Println("Token:", tk) if firstToken { if tk.Sym == SymMinus { tk.Sym = SymChangeSign } else if tk.Sym == SymPlus { tk.Sym = SymUnchangeSign } firstToken = false } switch tk.Sym { case SymOpenRound: var subTree *ast if subTree, err = self.parseGeneral(scanner, false, allowVarRef, SymClosedRound); err == nil { subTree.root.priority = priValue err = tree.addTerm(subTree.root) currentTerm = subTree.root } case SymFuncCall: var funcCallTerm *term if funcCallTerm, err = self.parseFuncCall(scanner, allowVarRef, tk); err == nil { err = tree.addTerm(funcCallTerm) currentTerm = funcCallTerm } case SymOpenSquare: var listTerm *term if listTerm, err = self.parseList(scanner, allowVarRef); err == nil { err = tree.addTerm(listTerm) currentTerm = listTerm } case SymEqual: if err = checkPrevSymbol(lastSym, SymIdentifier, tk); err == nil { currentTerm, err = tree.addToken2(tk) } case SymFuncDef: var funcDefTerm *term if funcDefTerm, err = self.parseFuncDef(scanner); err == nil { err = tree.addTerm(funcDefTerm) currentTerm = funcDefTerm } case SymIdentifier: if tk.source[0] == '@' && !allowVarRef { err = tk.Errorf("variable references are not allowed in top level expressions: %q", tk.source) } else { currentTerm, err = tree.addToken2(tk) } case SymQuestion: if selectorTerm, err = self.parseSelector(scanner, tree, allowVarRef); err == nil { currentTerm = selectorTerm } case SymColon, SymDoubleColon: var caseTerm *term if selectorTerm == nil { err = tk.Errorf("selector-case outside of a selector context") } else if caseTerm, err = self.parseSelectorCase(scanner, allowVarRef, tk.Sym == SymDoubleColon); err == nil { addSelectorCase(selectorTerm, caseTerm) currentTerm = caseTerm if tk.Sym == SymDoubleColon { selectorTerm = nil } } default: currentTerm, err = tree.addToken2(tk) } if currentTerm != nil && currentTerm.tk.Sym != SymSelector && currentTerm.parent != nil && currentTerm.parent.tk.Sym != SymSelector { selectorTerm = nil } lastSym = tk.Sym } if err == nil { err = tk.Error() } return } func checkPrevSymbol(lastSym, wantedSym Symbol, tk *Token) (err error) { if lastSym != wantedSym { err = fmt.Errorf(`assign operator (%q) must be preceded by a variable`, tk.source) } return }