2024-04-02 06:49:16 +02:00
|
|
|
// func-import.go
|
|
|
|
package expr
|
|
|
|
|
|
|
|
import (
|
|
|
|
"errors"
|
|
|
|
"fmt"
|
|
|
|
"io"
|
|
|
|
"os"
|
|
|
|
"path"
|
|
|
|
"path/filepath"
|
|
|
|
"strings"
|
|
|
|
)
|
|
|
|
|
|
|
|
const ENV_EXPR_PATH = "EXPR_PATH"
|
|
|
|
|
|
|
|
func importFunc(ctx exprContext, name string, args []any) (result any, err error) {
|
2024-04-06 03:06:07 +02:00
|
|
|
return importGeneral(ctx, name, args)
|
|
|
|
}
|
|
|
|
|
|
|
|
func includeFunc(ctx exprContext, name string, args []any) (result any, err error) {
|
|
|
|
enable(ctx, control_export_all)
|
|
|
|
return importGeneral(ctx, name, args)
|
|
|
|
}
|
|
|
|
|
|
|
|
func importGeneral(ctx exprContext, name string, args []any) (result any, err error) {
|
2024-04-02 06:49:16 +02:00
|
|
|
var dirList []string
|
|
|
|
|
|
|
|
dirList = addEnvImportDirs(dirList)
|
|
|
|
dirList = addPresetImportDirs(ctx, dirList)
|
|
|
|
result, err = doImport(ctx, name, dirList, NewFlatArrayIterator(args))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
func checkStringParamExpected(funcName string, paramValue any, paramPos int) (err error) {
|
|
|
|
if !(isString(paramValue) /*|| isList(paramValue)*/) {
|
|
|
|
err = fmt.Errorf("%s(): param nr %d has wrong type %T, string expected", funcName, paramPos+1, paramValue)
|
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
func addEnvImportDirs(dirList []string) []string {
|
|
|
|
if dirSpec, exists := os.LookupEnv(ENV_EXPR_PATH); exists {
|
|
|
|
dirs := strings.Split(dirSpec, ":")
|
|
|
|
if dirList == nil {
|
|
|
|
dirList = dirs
|
|
|
|
} else {
|
|
|
|
dirList = append(dirList, dirs...)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return dirList
|
|
|
|
}
|
|
|
|
|
|
|
|
func addPresetImportDirs(ctx exprContext, dirList []string) []string {
|
2024-04-06 03:06:07 +02:00
|
|
|
if dirSpec, exists := getControlString(ctx, control_import_path); exists {
|
2024-04-02 06:49:16 +02:00
|
|
|
dirs := strings.Split(dirSpec, ":")
|
|
|
|
if dirList == nil {
|
|
|
|
dirList = dirs
|
|
|
|
} else {
|
|
|
|
dirList = append(dirList, dirs...)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return dirList
|
|
|
|
}
|
|
|
|
|
|
|
|
func isFile(filePath string) bool {
|
|
|
|
info, err := os.Stat(filePath)
|
|
|
|
return (err == nil || errors.Is(err, os.ErrExist)) && info.Mode().IsRegular()
|
|
|
|
}
|
|
|
|
|
|
|
|
func searchAmongPath(filename string, dirList []string) (filePath string) {
|
|
|
|
for _, dir := range dirList {
|
|
|
|
if fullPath := path.Join(dir, filename); isFile(fullPath) {
|
|
|
|
filePath = fullPath
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
func isPathRelative(filePath string) bool {
|
|
|
|
unixPath := filepath.ToSlash(filePath)
|
|
|
|
return strings.HasPrefix(unixPath, "./") || strings.HasPrefix(unixPath, "../")
|
|
|
|
}
|
|
|
|
|
|
|
|
func makeFilepath(filename string, dirList []string) (filePath string, err error) {
|
|
|
|
if path.IsAbs(filename) || isPathRelative(filename) {
|
|
|
|
if isFile(filename) {
|
|
|
|
filePath = filename
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
filePath = searchAmongPath(filename, dirList)
|
|
|
|
}
|
|
|
|
if len(filePath) == 0 {
|
|
|
|
err = fmt.Errorf("source file %q not found", filename)
|
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
func doImport(ctx exprContext, name string, dirList []string, it Iterator) (result any, err error) {
|
|
|
|
var v any
|
|
|
|
var sourceFilepath string
|
|
|
|
|
|
|
|
for v, err = it.Next(); err == nil; v, err = it.Next() {
|
|
|
|
if err = checkStringParamExpected(name, v, it.Index()); err != nil {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
if sourceFilepath, err = makeFilepath(v.(string), dirList); err != nil {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
var file *os.File
|
|
|
|
if file, err = os.Open(sourceFilepath); err == nil {
|
|
|
|
defer file.Close()
|
|
|
|
var expr *ast
|
|
|
|
scanner := NewScanner(file, DefaultTranslations())
|
|
|
|
parser := NewParser(ctx)
|
2024-04-06 01:00:29 +02:00
|
|
|
if expr, err = parser.parseGeneral(scanner, true, true); err == nil {
|
2024-04-06 03:06:07 +02:00
|
|
|
result, err = expr.Eval(ctx, false)
|
2024-04-02 06:49:16 +02:00
|
|
|
}
|
2024-04-06 01:00:29 +02:00
|
|
|
if err != nil {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
break
|
2024-04-02 06:49:16 +02:00
|
|
|
}
|
|
|
|
}
|
2024-04-06 03:06:07 +02:00
|
|
|
if err != nil {
|
|
|
|
if err == io.EOF {
|
|
|
|
err = nil
|
|
|
|
} else {
|
|
|
|
result = nil
|
|
|
|
}
|
2024-04-02 06:49:16 +02:00
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
func importImportFunc(ctx exprContext) {
|
|
|
|
ctx.RegisterFunc("import", &simpleFunctor{f: importFunc}, 1, -1)
|
2024-04-06 03:06:07 +02:00
|
|
|
ctx.RegisterFunc("include", &simpleFunctor{f: includeFunc}, 1, -1)
|
2024-04-02 06:49:16 +02:00
|
|
|
}
|