Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion basex-api/src/main/java/org/basex/http/web/WebModule.java
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ void parse(final Context ctx) throws QueryException, IOException {
try(QueryContext qc = qc(ctx)) {
// loop through all functions
final String name = file.name();
for(final StaticFunc sf : qc.functions.funcs()) {
for(final StaticFunc sf : qc.functions) {
// only add functions that are defined in the same module (file)
if(sf.expr != null && name.equals(new IOFile(sf.info.path()).name())) {
final RestXqFunction rxf = new RestXqFunction(sf, this, qc);
Expand Down
4 changes: 2 additions & 2 deletions basex-core/src/main/java/org/basex/query/QueryContext.java
Original file line number Diff line number Diff line change
Expand Up @@ -259,14 +259,14 @@ public LibraryModule parseLibrary(final String query, final String uri) throws Q
* @throws QueryException query exception
*/
public void assign(final StaticFunc func, final Expr... args) throws QueryException {
for(final StaticFunc sf : functions.funcs()) {
for(final StaticFunc sf : functions) {
if(func.info.equals(sf.info)) {
// disable inlining of called function to ensure explicit locks are considered
if(!sf.anns.contains(Annotation._BASEX_INLINE)) {
sf.anns = sf.anns.attach(new Ann(sf.info, Annotation._BASEX_INLINE, Itr.ZERO));
}
// create and assign function call
final StaticFuncCall call = new StaticFuncCall(sf.name, args, null, sf.info, true);
final StaticFuncCall call = new StaticFuncCall(sf.name, args, null, sf.info);
call.setFunc(sf);
main = new MainModule(call, new VarScope(), sf.sc);
updating = sf.updating();
Expand Down
55 changes: 22 additions & 33 deletions basex-core/src/main/java/org/basex/query/QueryParser.java
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,6 @@ public class QueryParser extends InputParser {
SCHEMA_ELEMENT, PROCESSING_INSTRUCTION, TEXT, ARRAY, ENUM, FN, FUNCTION, GET, IF,
ITEM, MAP, RECORD, SWITCH, TYPE, TYPESWITCH);

/** URIs of modules loaded by the current file. */
public final TokenSet moduleURIs = new TokenSet();
/** Query context. */
public final QueryContext qc;
/** Static context. */
Expand All @@ -84,8 +82,6 @@ public class QueryParser extends InputParser {
private final ArrayList<StaticVar> vars = new ArrayList<>();
/** Parsed functions. */
private final ArrayList<StaticFunc> funcs = new ArrayList<>();
/** Function references. */
private final ArrayList<FuncRef> funcRefs = new ArrayList<>();
/** Types. */
private final QNmMap<SeqType> declaredTypes = new QNmMap<>();
/** Public types. */
Expand Down Expand Up @@ -161,7 +157,7 @@ final MainModule parseMain() throws QueryException {

final VarScope vs = localVars.popContext();
final MainModule mm = new MainModule(expr, vs, sc);
mm.set(funcs, vars, publicTypes, moduleURIs, namespaces, options, moduleDoc);
mm.set(funcs, vars, publicTypes, sc.imports, namespaces, options, moduleDoc);
finish(mm);
check(mm);
return mm;
Expand Down Expand Up @@ -211,7 +207,7 @@ final LibraryModule parseLibrary(final boolean root) throws QueryException {

qc.modStack.pop();
final LibraryModule lm = new LibraryModule(sc);
lm.set(funcs, vars, publicTypes, moduleURIs, namespaces, options, moduleDoc);
lm.set(funcs, vars, publicTypes, sc.imports, namespaces, options, moduleDoc);
return lm;
} catch(final QueryException expr) {
mark();
Expand Down Expand Up @@ -271,13 +267,6 @@ private void finish(final MainModule mm) throws QueryException {
qnames.assignURI(this, 0);
if(sc.elemNS != null) sc.ns.add(EMPTY, sc.elemNS, null);
RecordType.resolveRefs(recordTypeRefs, namedRecordTypes);

for(final FuncRef fr : funcRefs) fr.resolve();

if(qc.contextValue != null) {
final Expr ctx = qc.contextValue.expr;
if(!sc.mixUpdates && ctx.has(Flag.UPD)) throw error(UPCTX, ctx);
}
}

/**
Expand All @@ -288,15 +277,21 @@ private void finish(final MainModule mm) throws QueryException {
private void check(final MainModule main) throws QueryException {
// add record constructor functions for built-in record types
for(final RecordType rt : Records.BUILT_IN.values()) {
if(qc.functions.get(rt.name(), rt.minFields()) == null) {
if(qc.functions.get(sc, rt.name(), rt.minFields()) == null) {
declareRecordConstructor(rt, info());
}
}

// check function calls and variable references
qc.functions.check(qc);
// resolve function calls
qc.functions.resolve();
// check variable references
qc.vars.check();

if(qc.contextValue != null) {
final Expr ctx = qc.contextValue.expr;
if(!sc.mixUpdates && ctx.has(Flag.UPD)) throw error(UPCTX, ctx);
}

if(qc.updating) {
// check updating semantics if updating expressions exist
if(!sc.mixUpdates) {
Expand Down Expand Up @@ -738,8 +733,8 @@ private void moduleImport() throws QueryException {
final byte[] uri = trim(stringLiteral());
if(uri.length == 0) throw error(NSMODURI);
if(!Uri.get(uri).isValid()) throw error(INVURI_X, uri);
if(moduleURIs.contains(token(uri))) throw error(DUPLMODULE_X, uri);
moduleURIs.add(uri);
if(sc.imports.contains(token(uri))) throw error(DUPLMODULE_X, uri);
sc.imports.add(uri);

// add non-default namespace
if(prefix != EMPTY) {
Expand Down Expand Up @@ -943,7 +938,9 @@ private void functionDecl(final AnnList anns) throws QueryException {
if(reserved(name)) throw error(RESERVED_X, name.local());

wsCheck("(");
if(sc.module != null && !eq(name.uri(), sc.module.uri())) throw error(MODULENS_X, name);
if(!anns.contains(Annotation.PRIVATE)) {
if(sc.module != null && !eq(name.uri(), sc.module.uri())) throw error(MODULENS_X, name);
}

localVars.pushContext(false);
final Params params = paramList(true);
Expand All @@ -953,7 +950,7 @@ private void functionDecl(final AnnList anns) throws QueryException {
final byte[] uri = name.uri();
if(NSGlobal.reserved(uri) || Functions.builtIn(name) != null)
throw FNRESERVED_X.get(ii, name.string());
final StaticFunc func = qc.functions.declare(name, params, expr, anns, doc, vs, ii);
final StaticFunc func = qc.functions.declare(sc, name, params, expr, anns, doc, vs, ii);
funcs.add(func);
}

Expand Down Expand Up @@ -1079,7 +1076,8 @@ private void declareRecordConstructor(final RecordType rt, final InputInfo ii)
final Expr expr = new CRecord(ii, rt, args);
final String doc = docBuilder.toString();
final VarScope vs = localVars.popContext();
final StaticFunc func = qc.functions.declare(name, params, expr, rt.anns(), doc, vs, info());
final StaticFunc func = qc.functions.declare(sc, name, params, expr, rt.anns(), doc, vs,
info());
funcs.add(func);
}

Expand Down Expand Up @@ -2069,10 +2067,7 @@ private Expr arrow() throws QueryException {
expr = Functions.dynamic(ex, fb);
} else {
final QNm funcName = name;
final boolean hasImport = moduleURIs.contains(funcName.uri());
final FuncRef ref = new FuncRef(() -> Functions.get(funcName, fb, qc, hasImport));
funcRefs.add(ref);
expr = ref;
expr = qc.functions.newRef(() -> Functions.get(funcName, fb, qc));
}
if(mapping) {
expr = new GFLWOR(ii, fr, expr);
Expand Down Expand Up @@ -2747,10 +2742,7 @@ private Expr functionItem() throws QueryException {
if(num instanceof final Itr itr) {
final int i = (int) itr.itr();
final InputInfo info = info();
final boolean hasImport = moduleURIs.contains(name.uri());
final FuncRef fr = new FuncRef(() -> Functions.item(name, i, false, info, qc, hasImport));
funcRefs.add(fr);
return fr;
return qc.functions.newRef(() -> Functions.item(name, i, false, info, qc));
}
}
}
Expand Down Expand Up @@ -2975,10 +2967,7 @@ private Expr functionCall() throws QueryException {
skipWs();
if(current('(')) {
final FuncBuilder fb = argumentList(true, null);
final boolean hasImport = moduleURIs.contains(name.uri());
final FuncRef fr = new FuncRef(() -> Functions.get(name, fb, qc, hasImport));
funcRefs.add(fr);
return fr;
return qc.functions.newRef(() -> Functions.get(name, fb, qc));
}
}
pos = p;
Expand Down
2 changes: 2 additions & 0 deletions basex-core/src/main/java/org/basex/query/StaticContext.java
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ public final class StaticContext {
public byte[] funcNS;
/** Name of module (not assigned for main module). */
public QNm module;
/** URIs of modules loaded by the current file. */
public final TokenSet imports = new TokenSet();

/** Construction mode. */
public boolean strip;
Expand Down
62 changes: 0 additions & 62 deletions basex-core/src/main/java/org/basex/query/func/FuncRef.java

This file was deleted.

46 changes: 18 additions & 28 deletions basex-core/src/main/java/org/basex/query/func/Functions.java
Original file line number Diff line number Diff line change
Expand Up @@ -77,15 +77,14 @@ public static boolean staticURI(final byte[] uri) {
* @param qnm function name
* @param fb function arguments
* @param qc query context
* @param hasImport indicates whether a module import for the function name's URI was present
* @return function call
* @throws QueryException query exception
*/
public static Expr get(final QNm qnm, final FuncBuilder fb, final QueryContext qc,
final boolean hasImport) throws QueryException {
public static Expr get(final QNm qnm, final FuncBuilder fb, final QueryContext qc)
throws QueryException {

// partial function call?
if(fb.placeholders > 0) return dynamic(item(qnm, fb.arity, false, fb.info, qc, hasImport), fb);
if(fb.placeholders > 0) return dynamic(item(qnm, fb.arity, false, fb.info, qc), fb);

final QNm name = funcName(qnm, fb.arity, fb.info, qc);

Expand All @@ -103,7 +102,7 @@ public static Expr get(final QNm qnm, final FuncBuilder fb, final QueryContext q
}

// user-defined function
return staticCall(name, fb, qc, hasImport);
return staticCall(name, fb, qc);
}

/**
Expand Down Expand Up @@ -144,12 +143,11 @@ public static Expr dynamic(final Expr expr, final FuncBuilder fb) throws QueryEx
* @param runtime {@code true} if this method is called at runtime
* @param info input info (can be {@code null})
* @param qc query context
* @param hasImport indicates whether a module import for the function name's URI was present
* @return literal if found, {@code null} otherwise
* @throws QueryException query exception
*/
public static Expr item(final QNm qnm, final int arity, final boolean runtime,
final InputInfo info, final QueryContext qc, final boolean hasImport) throws QueryException {
final InputInfo info, final QueryContext qc) throws QueryException {

final FuncBuilder fb = new FuncBuilder(info, arity, runtime);
final QNm name = funcName(qnm, arity, info, qc);
Expand Down Expand Up @@ -181,9 +179,9 @@ public static Expr item(final QNm qnm, final int arity, final boolean runtime,
}

// user-defined function
final StaticFunc sf = qc.functions.get(name, arity);
final StaticFunc sf = qc.functions.get(info.sc(), name, arity);
if(sf != null) {
final Expr func = item(sf, fb, qc, hasImport);
final Expr func = item(sf, fb, qc);
if(sf.updating) qc.updating();
return func;
}
Expand All @@ -200,12 +198,7 @@ public static Expr item(final QNm qnm, final int arity, final boolean runtime,
}
if(runtime) return null;

// closure
final StaticFuncCall call = staticCall(name, fb, qc, hasImport);
// safe cast (no context dependency, no runtime evaluation)
final Closure closure = (Closure) item(call, fb, null, name, false, false);
qc.functions.register(closure);
return closure;
throw qc.functions.unknownFunctionError(name, arity, info);
}

/**
Expand All @@ -214,16 +207,16 @@ public static Expr item(final QNm qnm, final int arity, final boolean runtime,
* with no namespace.
* @param name function name
* @param arity number of arguments
* @param info input info (can be {@code null})
* @param info input info
* @param qc query context
* @return function name
*/
private static QNm funcName(final QNm name, final int arity, final InputInfo info,
final QueryContext qc) {

if(name.hasURI() || qc.functions.get(name, arity) != null) return name;
final StaticContext sc = info != null ? info.sc() : null;
return new QNm(name.local(), sc != null && sc.funcNS != null ? sc.funcNS : FN_URI);
final StaticContext sc = info.sc();
if(name.hasURI() || qc.functions.get(sc, name, arity) != null) return name;
return new QNm(name.local(), sc.funcNS != null ? sc.funcNS : FN_URI);
}

/**
Expand Down Expand Up @@ -322,20 +315,18 @@ private static Cast constructorCall(final QNm name, final FuncBuilder fb) throws
* @param name function name
* @param fb function arguments
* @param qc query context
* @param hasImport indicates whether a module import for the function name's URI was present
* @return function call
* @throws QueryException query exception
*/
private static StaticFuncCall staticCall(final QNm name, final FuncBuilder fb,
final QueryContext qc, final boolean hasImport) throws QueryException {
final QueryContext qc) throws QueryException {

if(NSGlobal.reserved(name.uri()) && !Records.BUILT_IN.contains(name)) {
throw qc.functions.similarError(name, fb.info);
}

final StaticFuncCall call = new StaticFuncCall(name, fb.args(), fb.keywords, fb.info,
hasImport);
qc.functions.register(call);
final StaticFuncCall call = new StaticFuncCall(name, fb.args(), fb.keywords, fb.info);
qc.functions.setFunc(call, qc);
return call;
}

Expand All @@ -344,19 +335,18 @@ private static StaticFuncCall staticCall(final QNm name, final FuncBuilder fb,
* @param sf static function
* @param fb function arguments
* @param qc query context
* @param hasImport indicates whether a module import for the function name's URI was present
* @return function item
* @throws QueryException query exception
*/
public static Expr item(final StaticFunc sf, final FuncBuilder fb, final QueryContext qc,
final boolean hasImport) throws QueryException {
public static Expr item(final StaticFunc sf, final FuncBuilder fb, final QueryContext qc)
throws QueryException {

final FuncType sft = sf.funcType();
final int arity = fb.params.length;
for(int a = 0; a < arity; a++) fb.add(sf.paramName(a), sft.argTypes[a], qc);
final FuncType ft = FuncType.get(fb.anns, sft.declType, Arrays.copyOf(sft.argTypes, arity));

final StaticFuncCall call = staticCall(sf.name, fb, qc, hasImport);
final StaticFuncCall call = staticCall(sf.name, fb, qc);
if(call.func != null) fb.anns = call.func.anns;
return item(call, fb, ft, sf.name, sf.updating, false);
}
Expand Down
Loading