Compare commits

...

8 Commits

11 changed files with 69 additions and 27 deletions

View File

@ -16,15 +16,6 @@ const (
paramEnd = "end"
paramValue = "value"
paramEllipsis = "..."
typeFilepath = "filepath"
typeDirpath = "dirpath"
paramFilepath = "filepath"
paramDirpath = "dirpath"
)
// const (
// typeInteger = "int"
// typeFloat = "float"
// typeString = "string"
// typeFraction = "fract"
// typeList = "list"
// typeDict = "dict"
// )

View File

@ -615,7 +615,10 @@ The table below shows all supported operators by decreasing priorities.
|===
== Functions
Functions in _Expr_ are very similar to functions in many programming languages.
Functions in _Expr_ are very similar to functions available in many programming languages. Actually, _Expr_ supports two types of function, _expr-functions_ and _go-functions_.
* _expr-functions_ are defined using _Expr_ syntax. They can be passed as arguments to other functions and can be returned from functions. Moreover, they bind themselves to the defining context, thus becoming closures.
* _go-functions_ are regular Golang functions callable from _Expr_ expressions. They are defined in Golang source file called _modules_ and compiled within the _Expr_ package. To make Golang functions available in _Expr_ contextes, it is required to _import_ the module within they are defined.
In _Expr_ functions compute values in a local context (scope) that do not make effects on the calling context. This is the normal behavior. Using the reference operator [blue]`@` it is possibile to export local definition to the calling context.

View File

@ -1609,7 +1609,7 @@ These operators have a high priority, in particular higher than the operator <co
<td class="tableblock halign-center valign-top"><p class="tableblock"><code class="blue">.</code></p></td>
<td class="tableblock halign-center valign-top"><p class="tableblock"><em>Infix</em></p></td>
<td class="tableblock halign-center valign-top"><p class="tableblock"><em>Dict item</em></p></td>
<td class="tableblock halign-center valign-top"><p class="tableblock"><em>dict</em> <code>""</code> <em>any</em> &#8594; <em>any</em></p></td>
<td class="tableblock halign-center valign-top"><p class="tableblock"><em>dict</em> <code>"."</code> <em>any</em> &#8594; <em>any</em></p></td>
</tr>
<tr>
<td class="tableblock halign-center valign-top" rowspan="2"><p class="tableblock"><strong>INC</strong></p></td>
@ -1834,7 +1834,17 @@ These operators have a high priority, in particular higher than the operator <co
<h2 id="_functions"><a class="anchor" href="#_functions"></a><a class="link" href="#_functions">6. Functions</a></h2>
<div class="sectionbody">
<div class="paragraph">
<p>Functions in <em>Expr</em> are very similar to functions in many programming languages.</p>
<p>Functions in <em>Expr</em> are very similar to functions available in many programming languages. Actually, <em>Expr</em> supports two types of function, <em>expr-functions</em> and <em>go-functions</em>.</p>
</div>
<div class="ulist">
<ul>
<li>
<p><em>expr-functions</em> are defined using <em>Expr</em> syntax. They can be passed as arguments to other functions and can be returned from functions. Moreover, they bind themselves to the defining context, thus becoming closures.</p>
</li>
<li>
<p><em>go-functions</em> are regular Golang functions callable from <em>Expr</em> expressions. They are defined in Golang source file called <em>modules</em> and compiled within the <em>Expr</em> package. To make Golang functions available in <em>Expr</em> contextes, it is required to <em>import</em> the module within they are defined.</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>In <em>Expr</em> functions compute values in a local context (scope) that do not make effects on the calling context. This is the normal behavior. Using the reference operator <code class="blue">@</code> it is possibile to export local definition to the calling context.</p>
@ -1874,7 +1884,7 @@ These operators have a high priority, in particular higher than the operator <co
</div>
<div id="footer">
<div id="footer-text">
Last updated 2024-05-20 09:40:23 +0200
Last updated 2024-06-02 10:44:09 +0200
</div>
</div>
</body>

36
func-fmt.go Normal file
View File

@ -0,0 +1,36 @@
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
// All rights reserved.
// func-fmt.go
package expr
import "fmt"
func printFunc(ctx ExprContext, name string, args []any) (result any, err error) {
var n int
if n, err = fmt.Print(args...); err == nil {
result = int64(n)
}
return
}
func printLnFunc(ctx ExprContext, name string, args []any) (result any, err error) {
var n int
if n, err = fmt.Println(args...); err == nil {
result = int64(n)
}
return
}
func ImportFmtFuncs(ctx ExprContext) {
ctx.RegisterFunc("print", newGolangFunctor(printFunc), typeInt, []ExprFuncParam{
newFuncParamFlag(paramItem, pfRepeat),
})
ctx.RegisterFunc("println", newGolangFunctor(printLnFunc), typeInt, []ExprFuncParam{
newFuncParamFlag(paramItem, pfRepeat),
})
}
func init() {
registerImport("fmt", ImportFmtFuncs, "String and console formatting functions")
}

View File

@ -138,10 +138,10 @@ func doImport(ctx ExprContext, name string, dirList []string, it Iterator) (resu
func ImportImportFuncs(ctx ExprContext) {
ctx.RegisterFunc("import", newGolangFunctor(importFunc), typeAny, []ExprFuncParam{
newFuncParamFlag(typeFilepath, pfRepeat),
newFuncParamFlag(paramFilepath, pfRepeat),
})
ctx.RegisterFunc("importAll", newGolangFunctor(importAllFunc), typeAny, []ExprFuncParam{
newFuncParamFlag(typeFilepath, pfRepeat),
newFuncParamFlag(paramFilepath, pfRepeat),
})
}

View File

@ -188,13 +188,13 @@ func readFileFunc(ctx ExprContext, name string, args []any) (result any, err err
func ImportOsFuncs(ctx ExprContext) {
ctx.RegisterFunc("openFile", newGolangFunctor(openFileFunc), typeHandle, []ExprFuncParam{
newFuncParam(typeFilepath),
newFuncParam(paramFilepath),
})
ctx.RegisterFunc("appendFile", newGolangFunctor(appendFileFunc), typeHandle, []ExprFuncParam{
newFuncParam(typeFilepath),
newFuncParam(paramFilepath),
})
ctx.RegisterFunc("createFile", newGolangFunctor(createFileFunc), typeHandle, []ExprFuncParam{
newFuncParam(typeFilepath),
newFuncParam(paramFilepath),
})
ctx.RegisterFunc("writeFile", newGolangFunctor(writeFileFunc), typeInt, []ExprFuncParam{
newFuncParam(typeHandle),

View File

@ -184,7 +184,7 @@ func splitStrFunc(ctx ExprContext, name string, args []any) (result any, err err
func ImportStringFuncs(ctx ExprContext) {
ctx.RegisterFunc("joinStr", newGolangFunctor(joinStrFunc), typeString, []ExprFuncParam{
newFuncParam(paramSeparator),
newFuncParamFlagDef(paramItem, pfOptional|pfRepeat, ""),
newFuncParamFlag(paramItem, pfRepeat),
})
ctx.RegisterFunc("subStr", newGolangFunctor(subStrFunc), typeString, []ExprFuncParam{
@ -205,12 +205,14 @@ func ImportStringFuncs(ctx ExprContext) {
ctx.RegisterFunc("startsWithStr", newGolangFunctor(startsWithStrFunc), typeBoolean, []ExprFuncParam{
newFuncParam(paramSource),
newFuncParamFlag(paramPrefix, pfRepeat),
newFuncParam(paramPrefix),
newFuncParamFlag("other "+paramPrefix, pfRepeat),
})
ctx.RegisterFunc("endsWithStr", newGolangFunctor(endsWithStrFunc), typeBoolean, []ExprFuncParam{
newFuncParam(paramSource),
newFuncParamFlag(paramSuffix, pfRepeat),
newFuncParam(paramSuffix),
newFuncParamFlag("other "+paramSuffix, pfRepeat),
})
}

View File

@ -168,6 +168,7 @@ func newFuncInfo(name string, functor Functor, returnType string, params []ExprF
return nil, fmt.Errorf("can't specify non-optional param after optional ones: %q", p.Name())
}
if p.IsRepeat() {
minArgs--
maxArgs = -1
}
}
@ -221,7 +222,7 @@ func (info *funcInfo) ToString(opt FmtOpt) string {
if info.maxArgs < 0 {
sb.WriteString(" ...")
}
sb.WriteString("): ")
sb.WriteString("):")
if len(info.returnType) > 0 {
sb.WriteString(info.returnType)
} else {

View File

@ -91,8 +91,6 @@ func funcsCtxToBuilder(sb *strings.Builder, ctx ExprContext, indent int) {
}
value, _ := ctx.GetFuncInfo(name)
sb.WriteString(strings.Repeat("\t", indent+1))
sb.WriteString(name)
//sb.WriteString("=")
if formatter, ok := value.(Formatter); ok {
sb.WriteString(formatter.ToString(0))
} else {

View File

@ -64,6 +64,6 @@ func TestFuncString(t *testing.T) {
//t.Setenv("EXPR_PATH", ".")
// parserTestSpec(t, "Func", inputs, 69)
// parserTestSpec(t, section, inputs, 19)
parserTest(t, section, inputs)
}

View File

@ -29,6 +29,7 @@ func TestFuncs(t *testing.T) {
/* 15 */ {`f=func(x,n=2){x+n}; f(3)`, int64(5), nil},
/* 16 */ {`f=func(x,n=2,y){x+n}`, nil, errors.New(`[1:16] can't mix default and non-default parameters`)},
/* 17 */ {`f=func(x,n){1}; f(3,4,)`, nil, errors.New(`[1:24] expected "function-param-value", got ")"`)},
// /* 18 */ {`f=func(a){a*2}`, nil, errors.New(`[1:24] expected "function-param-value", got ")"`)},
}
// t.Setenv("EXPR_PATH", ".")