Current section
Files
Jump to
Current section
Files
src/xqerl_parser.hrl
%% -------------------------------------------------------------------
%%
%% xqerl - XQuery processor
%%
%% Copyright (c) 2017-2020 Zachary N. Dean All Rights Reserved.
%%
%% This file is provided to you under the Apache License,
%% Version 2.0 (the "License"); you may not use this file
%% except in compliance with the License. You may obtain
%% a copy of the License at
%%
%% http://www.apache.org/licenses/LICENSE-2.0
%%
%% Unless required by applicable law or agreed to in writing,
%% software distributed under the License is distributed on an
%% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
%% KIND, either express or implied. See the License for the
%% specific language governing permissions and limitations
%% under the License.
%%
%% -------------------------------------------------------------------
-include_lib("kernel/include/logger.hrl").
-include("xqerl_item.hrl").
-define(parse_err(Code, Anno), erlang:throw(xqerl_error:error(Code, Anno))).
-define(parse_dbg(A, B), ?LOG_DEBUG("STATIC: ~p: ~p", [A, B], #{domain => [xqerl]})).
-define(node(I),
(I == 'node' orelse
I == 'document' orelse
I == 'document-node' orelse
I == 'element' orelse
I == 'attribute' orelse
I == 'namespace' orelse
I == 'text' orelse I == 'comment' orelse I == 'processing-instruction')
).
-type anno() :: undefined | non_neg_integer().
-record(xqURILiteral, {
anno :: anno(),
str :: binary()
}).
-type xqURILiteral() :: #xqURILiteral{}.
-record(xqNCName, {
anno :: anno(),
str :: binary()
}).
-type xqNCName() :: #xqNCName{}.
-record(xqStringLiteral, {
anno :: anno(),
str :: binary()
}).
-type xqStringLiteral() :: #xqStringLiteral{}.
-record(xqQName, {
anno :: anno(),
namespace :: term(),
prefix :: term(),
local_name :: term()
}).
-record(xqSeqType, {
anno :: anno(),
%:: atom() | #xqKindTest{},
type = item :: term(),
occur = zero_or_many :: zero | one | zero_or_one | zero_or_many | one_or_many | none
}).
-record(xqValidateExpr, {
anno :: anno()
}).
-record(xqEntityRef, {
ref :: binary()
}).
-record(xqCharRef, {
ref :: binary()
}).
-record(xqDocumentNode, {
anno :: anno(),
id :: pos_integer(),
content :: term()
}).
-record(xqElementNode, {
anno :: anno(),
id :: pos_integer(),
type :: direct | comp,
name :: #xqQName{} | term(),
attributes :: term(),
content :: term()
}).
-record(xqAttributeNode, {
anno :: anno(),
id :: pos_integer(),
type :: direct | comp,
name :: #xqQName{} | term(),
text :: term()
}).
-record(xqNamespaceNode, {
anno :: anno(),
id :: pos_integer(),
type :: direct | comp,
uri :: term(),
prefix :: term()
}).
-record(xqProcessingInstructionNode, {
anno :: anno(),
id :: pos_integer(),
type :: direct | comp,
name :: #xqQName{} | term(),
data :: term()
}).
-record(xqCommentNode, {
anno :: anno(),
id :: pos_integer(),
type :: direct | comp,
text :: term()
}).
-record(xqTextNode, {
anno :: anno(),
id :: undefined | pos_integer(),
type :: direct | comp,
text :: term()
}).
-record(xqNodeConstructor, {
id :: pos_integer(),
type :: direct | comp,
cons :: term()
}).
-record(xqArgumentPlaceholder, {
anno :: anno(),
id :: pos_integer()
}).
-record(xqAnnotation, {
anno :: anno(),
name :: #xqQName{},
values :: [#xqAtomicValue{} | binary() | atom() | number()]
}).
-record(xqKindTest, {
anno :: anno(),
kind = node ::
node
| text
| comment
| 'namespace-node'
| namespace
| 'schema-element'
| element
| 'schema-attribute'
| attribute
| 'document-node'
| document
| 'processing-instruction',
name = undefined :: #xqQName{} | undefined | term(),
type
}).
-record(xqPosVar, {
anno :: anno(),
id = -1 :: integer(),
name = undefined :: #xqQName{}
}).
-record(xqFunTest, {
anno :: anno(),
kind = function :: function | map | array,
annotations = [] :: [#xqAnnotation{}],
name :: undefined | #xqQName{},
params = any :: [#xqSeqType{}] | [any] | any,
type = any :: #xqSeqType{} | #xqKindTest{} | any
}).
-record(xqNameTest, {
anno :: anno(),
name :: #xqQName{}
}).
-record(xqPathExpr, {
anno :: anno(),
id :: pos_integer(),
expr :: term()
}).
-record(xqVar, {
anno :: anno(),
id = -1 :: integer(),
annotations = [] :: [#xqAnnotation{}],
name :: #xqQName{},
type = undefined :: undefined | #xqSeqType{},
value = undefined :: term(),
expr = undefined :: term(),
external = false :: boolean(),
default = undefined :: term(),
position = undefined :: undefined | #xqPosVar{},
empty = false :: boolean()
}).
-record(xqFor, {
var = #xqVar{}
}).
-record(xqLet, {
var = #xqVar{}
}).
-record(xqWhere, {
anno :: anno(),
id :: integer(),
expr :: any()
}).
-record(xqCount, {
var :: #xqVar{}
}).
-record(xqVarRef, {
anno :: anno(),
name :: #xqQName{}
}).
-record(xqGroupBy, {
grp_variable :: #xqVarRef{} | {variable, atom()},
collation
}).
-record(xqGroup, {
anno :: anno(),
id :: integer(),
vars :: [#xqGroupBy{}]
}).
-record(xqFunctionDef, {
anno :: anno(),
id = -1 :: integer(),
annotations = [] :: [#xqAnnotation{}],
name = undefined :: #xqQName{} | undefined,
arity = 0 :: integer(),
params = [] :: [#xqSeqType{}] | [term()] | {any(), any()},
type = undefined :: undefined | any | #xqSeqType{},
body = undefined :: undefined | tuple(),
external = false :: boolean()
}).
-record(xqIfExpr, {
anno :: anno(),
condition :: term(),
if_true :: {pos_integer(), term()} | {error, anno(), any()},
if_false :: {pos_integer(), term()} | {error, anno(), any()}
}).
-record(xqQuantifiedExpr, {
which :: some | every,
in_expr :: [term()],
satisfies :: term()
}).
-record(xqQuery, {query :: list()}).
-type xqQuery() :: [] | #xqQuery{}.
-record(xqBoundarySpaceDecl, {
anno :: anno(),
mode :: strip | preserve
}).
-record(xqDefaultCollationDecl, {
anno :: anno(),
uri :: binary()
}).
-record(xqBaseURIDecl, {
anno :: anno(),
uri :: binary()
}).
-record(xqConstructionDecl, {
anno :: anno(),
mode :: strip | preserve
}).
-record(xqOrderingModeDecl, {
anno :: anno(),
mode :: ordered | unordered
}).
-record(xqEmptyOrderDecl, {
anno :: anno(),
mode :: least | greatest
}).
-record(xqCopyNamespacesDecl, {
anno :: anno(),
pre :: atom(),
inh :: atom()
}).
-record(xqDecimalFormatDecl, {
anno :: anno(),
name :: undefined | #xqQName{},
props :: [term()]
}).
-record(xqRevalidationDecl, {
anno :: anno(),
kind :: skip
}).
-type xqSetters() ::
#xqDecimalFormatDecl{}
| #xqCopyNamespacesDecl{}
| #xqEmptyOrderDecl{}
| #xqOrderingModeDecl{}
| #xqConstructionDecl{}
| #xqBaseURIDecl{}
| #xqDefaultCollationDecl{}
| #xqBoundarySpaceDecl{}
| #xqRevalidationDecl{}.
-record(xqImport, {
anno :: anno(),
kind :: module | schema,
uri :: binary(),
prefix :: binary(),
hints :: [term()]
}).
-record(xqNamespaceDecl, {
anno :: anno(),
uri :: binary(),
prefix :: binary()
}).
-record(xqDefaultNamespaceDecl, {
anno :: anno(),
kind :: function | element,
uri :: binary()
}).
-record(xqContextItemDecl, {
anno :: anno(),
type = #xqSeqType{} :: #xqSeqType{},
external :: boolean(),
default :: any()
}).
-record(xqOptionDecl, {
anno :: anno(),
name :: #xqQName{},
val :: #xqStringLiteral{}
}).
-type xqAnnotatedDecl() :: #xqVar{} | #xqFunctionDef{}.
-type xqProlog1() :: #xqDefaultNamespaceDecl{} | xqSetters() | #xqNamespaceDecl{} | #xqImport{}.
-type xqProlog2() :: #xqContextItemDecl{} | xqAnnotatedDecl() | #xqOptionDecl{}.
-record(xqProlog, {
sect_1 :: list(xqProlog1()),
sect_2 :: list(xqProlog2())
}).
-type xqProlog() :: undefined | #xqProlog{}.
-record(xqModuleDecl, {
namespace :: binary(),
prefix :: binary()
}).
-type xqModuleDecl() :: undefined | #xqModuleDecl{}.
-record(xqModule, {
version :: undefined | {binary(), binary()},
type :: library | main,
declaration :: xqModuleDecl(),
prolog :: xqProlog() | [xqProlog1() | xqProlog2()],
body = [] :: xqQuery(),
filename :: undefined | binary()
}).
-record(xqUnaryExpr, {
anno :: anno(),
sign :: '+' | '-',
expr :: term()
}).
-record(xqLookup, {
anno :: anno(),
key :: term(),
kind :: undefined | array | map
}).
-record(xqPredicate, {
anno :: anno(),
expr :: term(),
pos = false :: boolean()
}).
-record(xqTypingExpr, {
anno :: anno(),
kind ::
instance
| treat
| castable
| cast
| promote
| check
| ensure,
expr :: term(),
type :: term()
}).
-record(xqNodeSetExpr, {
anno :: anno(),
kind :: except | intersect,
lhs :: term(),
rhs :: term()
}).
-record(xqNodeUnionExpr, {
anno :: anno(),
expr :: [term()]
}).
-record(xqConcatExpr, {
anno :: anno(),
expr :: [term()]
}).
-record(xqRange, {
anno :: anno(),
from :: term(),
to :: term()
}).
-record(xqPostfixExpr, {
id :: pos_integer(),
part :: boolean(),
expr :: term(),
post :: term()
}).
-record(xqStringConstructor, {
anno :: anno(),
content :: term()
}).
-record(xqEnclosedExpr, {
anno :: anno(),
expr :: term()
}).
-record(xqArrayConst, {
anno :: anno(),
content :: term()
}).
-record(xqMapEntry, {
anno :: anno(),
key :: term(),
value :: term()
}).
-record(xqMapConst, {
anno :: anno(),
content :: list(#xqMapEntry{})
}).
-record(xqFunctionRef, {
anno :: anno(),
name :: #xqQName{},
arity :: term()
}).
-record(xqSequence, {
vals :: term()
}).
-type axis() ::
child
| descendant
| attribute
| self
| 'descendant-or-self'
| 'following-sibling'
| following
| namespace
| parent
| ancestor
| 'preceding-sibling'
| preceding
| 'ancestor-or-self'.
-record(xqAxisStep, {
anno :: anno(),
id :: pos_integer(),
direction = forward :: forward | reverse,
axis = child :: axis(),
node_test = #xqKindTest{},
predicates = []
}).
-record(xqPostfixStep, {
anno :: anno(),
predicates :: list()
}).
-record(xqFlwor, {
id = -1 :: integer(),
loop = undefined :: term(),
return = undefined :: term()
}).
-record(xqWindow, {
type :: tumbling | sliding,
win_variable :: #xqVar{},
s :: undefined | #xqVar{},
spos :: undefined | #xqPosVar{},
sprev :: undefined | #xqVar{},
snext :: undefined | #xqVar{},
e :: undefined | #xqVar{},
epos :: undefined | #xqPosVar{},
eprev :: undefined | #xqVar{},
enext :: undefined | #xqVar{},
only = false :: boolean(),
start_expr,
end_expr
}).
-record(xqSwitch, {
anno :: anno(),
id :: integer(),
operand :: any(),
clauses :: [any()],
default :: any()
}).
-record(xqSwitchClause, {
anno :: anno(),
operands :: [any()],
expr :: any()
}).
-record(xqOrderModifier, {
anno :: anno(),
direction = ascending :: ascending | descending,
empty = default :: default | least | greatest,
collation = default :: default | binary() | #xqURILiteral{}
}).
-record(xqOrderSpec, {
expr :: any(),
modifier :: #xqOrderModifier{}
}).
-record(xqOrderByClause, {
anno :: anno(),
id :: integer(),
spec :: [#xqOrderSpec{}]
}).
-record(xqTypeswitchCase, {
anno :: anno(),
types = default :: [any()] | default,
variable = undefined :: #xqVar{} | undefined,
expr :: any()
}).
-record(xqTypeswitch, {
anno :: anno(),
id :: integer(),
input :: any(),
cases :: [#xqTypeswitchCase{}],
default :: #xqTypeswitchCase{}
}).
-record(xqTryCatch, {
anno :: anno(),
id :: integer(),
expr :: any(),
catches :: [any()]
}).
-type valueComp() :: 'eq' | 'ne' | 'lt' | 'le' | 'gt' | 'gt'.
-type generalComp() :: '=' | '!=' | '<' | '<=' | '>' | '>='.
-type nodeComp() :: 'is' | '<<' | '>>'.
-record(xqComparisonExpr, {
anno :: anno(),
id :: integer(),
comp :: valueComp() | generalComp() | nodeComp(),
lhs :: term() | [term()],
rhs :: term() | [term()]
}).
-record(xqLogicalExpr, {
anno :: anno(),
id :: integer(),
comp :: 'and' | 'or',
lhs :: term() | [term()],
rhs :: term() | [term()]
}).
-type arithOp() :: '+' | '-' | '*' | 'div' | 'idiv' | 'mod'.
-record(xqArithExpr, {
anno :: anno(),
id :: integer(),
op :: arithOp(),
lhs :: term() | [term()],
rhs :: term() | [term()]
}).
-record(xqSimpleMap, {
anno :: anno(),
id :: integer(),
lhs :: term() | [term()],
rhs :: term() | [term()]
}).
-record(xqFunctionCall, {
anno :: anno(),
name :: undefined | #xqQName{},
arity :: undefined | integer(),
args :: undefined | [term()],
% after the static phase this is set
call :: undefined | #xqFunctionDef{}
}).
-record(xqPartialFunctionCall, {
anno :: anno(),
name :: undefined | #xqQName{},
arity :: undefined | integer(),
args :: undefined | [term()],
% after the static phase this is set
call :: undefined | #xqFunctionDef{}
}).
-record(xqArgumentList, {
anno :: anno(),
args :: [term()]
}).
-record(xqExtensionExpr, {
anno :: anno(),
pragmas :: [term()],
expr :: term()
}).
-type insert_type() :: 'after' | before | into_first | into_last | into.
-record(xqUpdateExpr, {
anno :: anno(),
id :: undefined | integer(),
kind :: insert_type() | delete | replace_value | replace | rename,
src :: term(),
tgt :: term()
}).
-record(xqModifyExpr, {
anno :: anno(),
id :: integer(),
vars :: [#xqVar{}],
expr :: term(),
return :: term()
}).
%% at = attributes
%% bu = base-uri (list of all xml:base atts to document)
%% ch = children
%% du = document-uri
%% id = node-identity (unique ID in document)
%% ii = is-id
%% ir = is-idrefs
%% hn = has namespaces, flag to look them up from an element
%% ns = namespace-nodes (in-scope namespaces)
%% nd = nilled
%% nk = node-kind
%% nn = node-name
%% pt = parent
%% sv = string-value
%% tn = type-name
%% tv = typed-value
%% pa = path id in DB