mirror of
https://github.com/chaisql/chai.git
synced 2025-10-13 03:14:04 +08:00
Add functions packages support (#419)
* Add packaged functions support * Add tests for math.floor func * Export FunctionsTable * Extract func stuff into its own package * Rename stuff * Fix tests * Move doc package to cmd/genji * Adjust naming, typos
This commit is contained in:

committed by
GitHub

parent
c0861ed2c5
commit
e556fc3048
@@ -6,6 +6,7 @@ import (
|
||||
"github.com/genjidb/genji/document"
|
||||
"github.com/genjidb/genji/internal/environment"
|
||||
"github.com/genjidb/genji/internal/expr"
|
||||
"github.com/genjidb/genji/internal/expr/functions"
|
||||
"github.com/genjidb/genji/internal/sql/scanner"
|
||||
"github.com/genjidb/genji/internal/stringutil"
|
||||
)
|
||||
@@ -190,11 +191,30 @@ func (p *Parser) parseUnaryExpr(allowed ...scanner.Token) (expr.Expr, error) {
|
||||
p.Unscan()
|
||||
return p.parseCastExpression()
|
||||
case scanner.IDENT:
|
||||
// if the next token is a left parenthesis, this is a function
|
||||
if tok1, _, _ := p.Scan(); tok1 == scanner.LPAREN {
|
||||
tok1, _, _ := p.Scan()
|
||||
// if the next token is a left parenthesis, this is a global function
|
||||
if tok1 == scanner.LPAREN {
|
||||
p.Unscan()
|
||||
p.Unscan()
|
||||
return p.parseFunction()
|
||||
} else {
|
||||
// it may be a package function instead.
|
||||
if tok1 == scanner.DOT {
|
||||
if tok2, _, _ := p.Scan(); tok2 == scanner.IDENT {
|
||||
if tok3, _, _ := p.Scan(); tok3 == scanner.LPAREN {
|
||||
p.Unscan()
|
||||
p.Unscan()
|
||||
p.Unscan()
|
||||
p.Unscan()
|
||||
return p.parseFunction()
|
||||
} else {
|
||||
p.Unscan()
|
||||
p.Unscan()
|
||||
}
|
||||
} else {
|
||||
p.Unscan()
|
||||
}
|
||||
}
|
||||
}
|
||||
p.Unscan()
|
||||
p.Unscan()
|
||||
@@ -577,11 +597,23 @@ func (p *Parser) parseExprList(leftToken, rightToken scanner.Token) (expr.Litera
|
||||
// an optional coma-separated list of expressions and a closing parenthesis.
|
||||
func (p *Parser) parseFunction() (expr.Expr, error) {
|
||||
// Parse function name.
|
||||
fname, err := p.parseIdent()
|
||||
funcName, err := p.parseIdent()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Parse optional package name
|
||||
var pkgName string
|
||||
if tok, _, _ := p.Scan(); tok == scanner.DOT {
|
||||
pkgName = funcName
|
||||
funcName, err = p.parseIdent()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
p.Unscan()
|
||||
}
|
||||
|
||||
// Parse required ( token.
|
||||
if err := p.parseTokens(scanner.LPAREN); err != nil {
|
||||
return nil, err
|
||||
@@ -593,13 +625,17 @@ func (p *Parser) parseFunction() (expr.Expr, error) {
|
||||
return nil, newParseError(scanner.Tokstr(tok, lit), []string{")"}, pos)
|
||||
}
|
||||
|
||||
return &expr.CountFunc{Wildcard: true}, nil
|
||||
return &functions.Count{Wildcard: true}, nil
|
||||
}
|
||||
p.Unscan()
|
||||
|
||||
// Check if the function is called without arguments.
|
||||
if tok, _, _ := p.ScanIgnoreWhitespace(); tok == scanner.RPAREN {
|
||||
return p.functions.GetFunc(fname)
|
||||
def, err := p.packagesTable.GetFunc(pkgName, funcName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return def.Function()
|
||||
}
|
||||
p.Unscan()
|
||||
|
||||
@@ -625,7 +661,11 @@ func (p *Parser) parseFunction() (expr.Expr, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return p.functions.GetFunc(fname, exprs...)
|
||||
def, err := p.packagesTable.GetFunc(pkgName, funcName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return def.Function(exprs...)
|
||||
}
|
||||
|
||||
// parseCastExpression parses a string of the form CAST(expr AS type).
|
||||
@@ -657,7 +697,7 @@ func (p *Parser) parseCastExpression() (expr.Expr, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return expr.CastFunc{Expr: e, CastAs: tp}, nil
|
||||
return functions.Cast{Expr: e, CastAs: tp}, nil
|
||||
}
|
||||
|
||||
// tokenIsAllowed is a helper function that determines if a token is allowed.
|
||||
|
Reference in New Issue
Block a user