first working implementation of iterators and some fixes to the parser around lists analysis

This commit is contained in:
2024-04-26 04:45:42 +02:00
parent 7a88449cd1
commit 750c660331
5 changed files with 318 additions and 13 deletions
+115 -12
View File
@@ -58,23 +58,72 @@ func (self *parser) parseFuncCall(scanner *scanner, allowVarRef bool, tk *Token)
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) 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)
lastSym := SymUnknown
itemExpected := false
tk := scanner.Previous()
for lastSym != SymClosedRound && lastSym != SymEos {
var subTree *ast
if subTree, err = self.parseItem(scanner, true, SymComma, SymClosedRound); err == nil {
if subTree.root != nil {
if subTree.root.symbol() == SymIdentifier {
args = append(args, subTree.root)
} else {
err = tk.Errorf("exptected identifier, got %q", subTree.root)
}
} else if itemExpected {
prev := scanner.Previous()
err = prev.Errorf("expected function parameter, got %q", prev)
break
}
} else {
err = tk.Errorf("invalid param %q, variable identifier expected", tk.source)
break
}
tk = scanner.Next()
lastSym = scanner.Previous().Sym
itemExpected = lastSym == SymComma
}
if err == nil && tk.Sym != SymClosedRound {
err = tk.Errorf("unterminate function params list")
if err == nil && lastSym != SymClosedRound {
err = tk.Errorf("unterminated function parameters list")
}
if err == nil {
tk = scanner.Next()
@@ -125,6 +174,51 @@ func (self *parser) parseList(scanner *scanner, allowVarRef bool) (subtree *term
return
}
func (self *parser) parseIterDef(scanner *scanner, allowVarRef bool) (subtree *term, err error) {
var ds *term
tk := scanner.Previous()
args := make([]*term, 0)
lastSym := SymUnknown
dsExpected := true
itemExpected := false
for lastSym != SymClosedRound && lastSym != SymEos {
var subTree *ast
if subTree, err = self.parseItem(scanner, allowVarRef, SymComma, SymClosedRound); err == nil {
if subTree.root != nil {
if dsExpected {
if sym := subTree.root.symbol(); sym == SymDict || sym == SymIdentifier {
ds = subTree.root
} else {
err = subTree.root.Errorf("data-source dictionary expected, got %q", subTree.root.source())
}
dsExpected = false
} else {
args = append(args, subTree.root)
}
} else if itemExpected {
prev := scanner.Previous()
err = prev.Errorf("expected iterator argument, got %q", prev)
break
}
} else {
break
}
lastSym = scanner.Previous().Sym
itemExpected = lastSym == SymComma
}
if err == nil {
// TODO Check arguments
if lastSym != SymClosedRound {
err = scanner.Previous().Errorf("unterminate iterator param list")
} else if ds != nil {
subtree = newIteratorTerm(tk, ds, args)
} else {
tk.Errorf("missing data-source param")
}
}
return
}
func (self *parser) parseDictKey(scanner *scanner, allowVarRef bool) (key any, err error) {
tk := scanner.Next()
if tk.Sym == SymError {
@@ -156,9 +250,12 @@ func (self *parser) parseDictionary(scanner *scanner, allowVarRef bool) (subtree
var key any
if key, err = self.parseDictKey(scanner, allowVarRef); err != nil {
break
} else if key == nil && itemExpected {
} else if key == nil {
tk := scanner.Previous()
err = tk.Errorf("expected dictionary key, got %q", tk)
lastSym = tk.Sym
if itemExpected {
err = tk.Errorf("expected dictionary key, got %q", tk)
}
break
}
if subTree, err = self.parseItem(scanner, allowVarRef, SymComma, SymClosedBrace); err == nil {
@@ -178,7 +275,7 @@ func (self *parser) parseDictionary(scanner *scanner, allowVarRef bool) (subtree
if err == nil {
// TODO Check arguments
if lastSym != SymClosedBrace {
err = scanner.Previous().Errorf("unterminate dictionary")
err = scanner.Previous().Errorf("unterminated dictionary")
} else {
subtree = newDictTerm(args)
}
@@ -324,6 +421,12 @@ func (self *parser) parseGeneral(scanner *scanner, allowForest bool, allowVarRef
err = tree.addTerm(funcDefTerm)
currentTerm = funcDefTerm
}
case SymDollarRound:
var iterDefTerm *term
if iterDefTerm, err = self.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)