// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com). // All rights reserved. // parser.go package expr import ( "errors" ) //-------- parser type parser struct { } func NewParser() (p *parser) { p = &parser{} return p } func (parser *parser) Next(scanner *scanner) (tk *Token) { for tk = scanner.Next(); tk.IsSymbol(SymComment); tk = scanner.Next() { } return } func (parser *parser) parseFuncCall(scanner *scanner, allowVarRef bool, tk *Token) (tree *term, err error) { args := make([]*term, 0, 10) itemExpected := false lastSym := SymUnknown for lastSym != SymClosedRound && lastSym != SymEos { var subTree *ast if subTree, err = parser.parseItem(scanner, allowVarRef, SymComma, SymClosedRound); err != nil { break } prev := scanner.Previous() if subTree.root != nil { args = append(args, subTree.root) } else if itemExpected { err = prev.ErrorExpectedGot("function-param-value") break } itemExpected = prev.Sym == SymComma lastSym = scanner.Previous().Sym } if err == nil { if lastSym != SymClosedRound { err = errors.New("unterminated arguments list") } else { tree = newFuncCallTerm(tk, args) } } return } func (parser *parser) parseFuncDef(scanner *scanner) (tree *term, err error) { // Example: "add = func(x,y) {x+y} var body *ast args := make([]*term, 0) lastSym := SymUnknown defaultParamsStarted := false itemExpected := false tk := scanner.Previous() for lastSym != SymClosedRound && lastSym != SymEos { tk = parser.Next(scanner) if tk.IsSymbol(SymIdentifier) { param := newTerm(tk) args = append(args, param) tk = parser.Next(scanner) if tk.Sym == SymEqual { var paramExpr *ast defaultParamsStarted = true if paramExpr, err = parser.parseItem(scanner, false, SymComma, SymClosedRound); err != nil { break } param.forceChild(paramExpr.root) } else if defaultParamsStarted { err = tk.Errorf("can't mix default and non-default parameters") break } } else if itemExpected { prev := scanner.Previous() err = prev.ErrorExpectedGot("function-param-spec") break } lastSym = scanner.Previous().Sym itemExpected = lastSym == SymComma } if err == nil && lastSym != SymClosedRound { err = tk.ErrorExpectedGot(")") } if err == nil { tk = parser.Next(scanner) if tk.IsSymbol(SymOpenBrace) { body, err = parser.parseGeneral(scanner, true, true, SymClosedBrace) } else { err = tk.ErrorExpectedGot("{") } } if err == nil { if scanner.Previous().Sym != SymClosedBrace { err = scanner.Previous().ErrorExpectedGot("}") } else { tk = scanner.makeValueToken(SymExpression, "", body) tree = newFuncDefTerm(tk, args) } } return } func (parser *parser) parseList(scanner *scanner, parsingIndeces bool, allowVarRef bool) (subtree *term, err error) { r, c := scanner.lastPos() args := make([]*term, 0) lastSym := SymUnknown itemExpected := false for lastSym != SymClosedSquare && lastSym != SymEos { var subTree *ast zeroRequired := scanner.current.Sym == SymColon if subTree, err = parser.parseItem(scanner, allowVarRef, SymComma, SymClosedSquare); err == nil { root := subTree.root if root != nil { if !parsingIndeces && root.symbol() == SymColon { err = root.Errorf("unexpected range expression") break } args = append(args, root) if parsingIndeces && root.symbol() == SymColon && zeroRequired { //len(root.children) == 0 { if len(root.children) == 1 { root.children = append(root.children, root.children[0]) } else if len(root.children) > 1 { err = root.Errorf("invalid range specification") break } zeroTk := NewValueToken(root.tk.row, root.tk.col, SymInteger, "0", int64(0)) zeroTerm := newTerm(zeroTk) zeroTerm.setParent(root) root.children[0] = zeroTerm } } else if itemExpected { prev := scanner.Previous() err = prev.ErrorExpectedGot("list-item") break } } else { break } lastSym = scanner.Previous().Sym itemExpected = lastSym == SymComma } if err == nil { if lastSym != SymClosedSquare { err = scanner.Previous().ErrorExpectedGot("]") } else { subtree = newListTerm(r, c, args) } } return } func (parser *parser) parseIterDef(scanner *scanner, allowVarRef bool) (subtree *term, err error) { tk := scanner.Previous() args := make([]*term, 0) lastSym := SymUnknown itemExpected := false for lastSym != SymClosedRound && lastSym != SymEos { var subTree *ast if subTree, err = parser.parseItem(scanner, allowVarRef, SymComma, SymClosedRound); err == nil { if subTree.root != nil { args = append(args, subTree.root) } else if itemExpected { prev := scanner.Previous() err = prev.ErrorExpectedGot("iterator-param") break } } else { break } lastSym = scanner.Previous().Sym itemExpected = lastSym == SymComma } if err == nil { if lastSym != SymClosedRound { err = scanner.Previous().ErrorExpectedGot(")") } else { subtree = newIteratorTerm(tk, args) } } return } func (parser *parser) parseDictKey(scanner *scanner) (key any, err error) { tk := parser.Next(scanner) if tk.Sym == SymError { err = tk.Error() return } if tk.Sym == SymClosedBrace || tk.Sym == SymEos { return } if tk.Sym == SymInteger || tk.Sym == SymString { tkSep := parser.Next(scanner) if tkSep.Sym != SymColon { err = tkSep.ErrorExpectedGot(":") } else { key = tk.Value } } else { err = tk.ErrorExpectedGot("dictionary-key or }") } return } func (parser *parser) parseDictionary(scanner *scanner, allowVarRef bool) (subtree *term, err error) { args := make(map[any]*term, 0) lastSym := SymUnknown itemExpected := false for lastSym != SymClosedBrace && lastSym != SymEos { var subTree *ast var key any if key, err = parser.parseDictKey(scanner); err != nil { break } else if key == nil { tk := scanner.Previous() lastSym = tk.Sym if itemExpected { err = tk.ErrorExpectedGot("dictionary-key") } break } if subTree, err = parser.parseItem(scanner, allowVarRef, SymComma, SymClosedBrace); err == nil { if subTree.root != nil { args[key] = subTree.root } else /*if key != nil*/ { prev := scanner.Previous() err = prev.ErrorExpectedGot("dictionary-value") break } } else { break } lastSym = scanner.Previous().Sym itemExpected = lastSym == SymComma } if err == nil { if lastSym != SymClosedBrace { err = scanner.Previous().ErrorExpectedGot("}") } else { subtree = newDictTerm(args) // subtree = newMapTerm(args) } } return } func (parser *parser) parseSelectorCase(scanner *scanner, allowVarRef bool, defaultCase bool) (caseTerm *term, err error) { var filterList *term var caseExpr *ast tk := parser.Next(scanner) startRow := tk.row startCol := tk.col if tk.Sym == SymOpenSquare { if defaultCase { err = tk.Errorf("case list in default clause") return } if filterList, err = parser.parseList(scanner, false, allowVarRef); err != nil { return } tk = parser.Next(scanner) startRow = tk.row startCol = tk.col } else if !defaultCase { filterList = newListTerm(startRow, startCol, make([]*term, 0)) } if tk.Sym == SymOpenBrace { if caseExpr, err = parser.parseGeneral(scanner, true, allowVarRef, SymClosedBrace); err != nil { return } } else { err = tk.ErrorExpectedGot("{") } 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 (parser *parser) parseSelector(scanner *scanner, tree *ast, allowVarRef bool) (selectorTerm *term, err error) { var caseTerm *term tk := scanner.makeToken(SymSelector, '?') if selectorTerm, err = tree.addToken(tk); err != nil { return } if caseTerm, err = parser.parseSelectorCase(scanner, allowVarRef, false); err == nil { addSelectorCase(selectorTerm, caseTerm) } return } func (parser *parser) parseItem(scanner *scanner, allowVarRef bool, termSymbols ...Symbol) (tree *ast, err error) { return parser.parseGeneral(scanner, false, allowVarRef, termSymbols...) } func (parser *parser) Parse(scanner *scanner, termSymbols ...Symbol) (tree *ast, err error) { return parser.parseGeneral(scanner, true, false, termSymbols...) } func couldBeACollection(t *term) bool { var sym = SymUnknown if t != nil { sym = t.symbol() } return sym == SymList || sym == SymString || sym == SymDict || sym == SymExpression || sym == SymVariable } // func areSymbolsOutOfCtx(tk *Token, ctxTerm *term, syms ...Symbol) bool { // var areOut = false // if ctxTerm != nil { // areOut = tk.IsOneOf(syms) // } // return areOut // } func (parser *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 = parser.Next(scanner); err == nil && tk != nil && !tk.IsTerm(termSymbols); /*&& !areSymbolsOutOfCtx(tk, selectorTerm, SymColon, SymDoubleColon)*/ tk = parser.Next(scanner) { // if tk.Sym == SymComment { // continue // } if tk.Sym == SymSemiColon { if allowForest { tree.ToForest() firstToken = true currentTerm = nil selectorTerm = nil 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 = parser.parseGeneral(scanner, false, allowVarRef, SymClosedRound); err == nil { subTree.root.priority = priValue err = tree.addTerm(newExprTerm(subTree.root)) currentTerm = subTree.root } case SymFuncCall: var funcCallTerm *term if funcCallTerm, err = parser.parseFuncCall(scanner, allowVarRef, tk); err == nil { err = tree.addTerm(funcCallTerm) currentTerm = funcCallTerm } case SymOpenSquare: var listTerm *term parsingIndeces := couldBeACollection(currentTerm) if listTerm, err = parser.parseList(scanner, parsingIndeces, allowVarRef); err == nil { if parsingIndeces { indexTk := NewToken(listTerm.tk.row, listTerm.tk.col, SymIndex, listTerm.source()) indexTerm := newTerm(indexTk) if err = tree.addTerm(indexTerm); err == nil { err = tree.addTerm(listTerm) } } else { err = tree.addTerm(listTerm) } currentTerm = listTerm } case SymOpenBrace: if currentTerm != nil && currentTerm.symbol() == SymColon { err = currentTerm.Errorf(`selector-case outside of a selector context`) } else { var mapTerm *term if mapTerm, err = parser.parseDictionary(scanner, allowVarRef); err == nil { err = tree.addTerm(mapTerm) currentTerm = mapTerm } } case SymEqual: // if err = checkPrevSymbol(lastSym, SymIdentifier, tk); err == nil { currentTerm, err = tree.addToken(tk) firstToken = true // } case SymFuncDef: var funcDefTerm *term if funcDefTerm, err = parser.parseFuncDef(scanner); err == nil { err = tree.addTerm(funcDefTerm) currentTerm = funcDefTerm } case SymDollarRound: var iterDefTerm *term if iterDefTerm, err = parser.parseIterDef(scanner, allowVarRef); err == nil { err = tree.addTerm(iterDefTerm) currentTerm = iterDefTerm } 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.addToken(tk) } case SymQuestion: if selectorTerm, err = parser.parseSelector(scanner, tree, allowVarRef); err == nil { currentTerm = selectorTerm } case SymColon, SymDoubleColon: var caseTerm *term if selectorTerm != nil { if caseTerm, err = parser.parseSelectorCase(scanner, allowVarRef, tk.Sym == SymDoubleColon); err == nil { addSelectorCase(selectorTerm, caseTerm) currentTerm = caseTerm if tk.Sym == SymDoubleColon { selectorTerm = nil } } } else { currentTerm, err = tree.addToken(tk) } if tk.IsSymbol(SymColon) { // Colon outside a selector term acts like a separator firstToken = true } case SymPlusEqual, SymMinusEqual, SymStarEqual: currentTerm, err = parser.expandOpAssign(scanner, tree, tk, allowVarRef) default: currentTerm, err = tree.addToken(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 // } func (parser *parser) expandOpAssign(scanner *scanner, tree *ast, tk *Token, allowVarRef bool) (t *term, err error) { var opSym Symbol var opString string if tree.root != nil { switch tk.Sym { case SymPlusEqual: opString = "+" opSym = SymPlus case SymMinusEqual: opString = "-" opSym = SymMinus case SymStarEqual: opString = "*" opSym = SymStar default: err = tk.Errorf("unsopported operator %q", tk.source) return } leftExpr := tree.root.Clone() leftExpr.setParent(nil) if t, err = tree.addToken(NewToken(tk.row, tk.col, SymEqual, "=")); err == nil { t = leftExpr if err = tree.addTerm(leftExpr); err == nil { if t, err = tree.addToken(NewToken(tk.row, tk.col, opSym, opString)); err == nil { var subTree *ast if subTree, err = parser.parseGeneral(scanner, false, allowVarRef, SymSemiColon, SymClosedRound, SymClosedBrace, SymClosedSquare); err == nil { if scanner.Previous().IsOneOfA(SymSemiColon, SymClosedRound, SymClosedBrace, SymClosedSquare) { if err = scanner.UnreadToken(); err != nil { return } } subTree.root.priority = priValue err = tree.addTerm(newExprTerm(subTree.root)) t = subTree.root } } } } } else { err = tk.Errorf("left operand of %q must be a variable or a variable expression", tk) } return }