// Port of sqlglot/parser.py: data types, columns, column operators, primaries.
///|
pub fn Parser::parse_types(
self : Parser,
check_func? : Bool = false,
schema? : Bool = false,
allow_identifiers? : Bool = true,
with_collation? : Bool = false,
) -> Expr? raise SqlglotError {
match self.fns.hooks.parse_types {
Some(f) => f(self, check_func, schema, allow_identifiers, with_collation)
None =>
self.parse_types_base(
check_func~,
schema~,
allow_identifiers~,
with_collation~,
)
}
}
///|
pub fn Parser::parse_types_base(
self : Parser,
check_func? : Bool = false,
schema? : Bool = false,
allow_identifiers? : Bool = true,
with_collation? : Bool = false,
) -> Expr? raise SqlglotError {
let index = self.index
let mut this : Expr? = None
let mut type_token : TokenType? = None
if self.match_set(self.cfg.type_tokens) {
type_token = Some(self.prev.token_type)
} else {
let identifier = if allow_identifiers {
self.parse_id_var(any_token=false, tokens=TokenSet::new([VAR]))
} else {
None
}
match identifier {
Some(identifier) if identifier.kind == Identifier =>
if identifier.has("quoted") &&
self.cfg.quoted_types_to_preserve.contains(identifier.name()) {
this = Some(
mk(DataType, [("this", DType::USERDEFINED), ("kind", identifier)]),
)
} else {
let tokens = self.dialect.tokenize(identifier.name()) catch {
TokenError(_, ..) => []
e => raise e
}
if !tokens.is_empty() &&
self.cfg.type_tokens.contains(tokens[0].token_type) {
type_token = Some(tokens[0].token_type)
if tokens.length() > 1 {
return Some(
datatype_from_str(identifier.name(), dialect=self.dialect),
)
}
} else if self.dialect.cfg.supports_user_defined_types {
this = self.parse_user_defined_type(identifier)
} else {
self.retreat(self.index - 1)
return None
}
}
_ => return None
}
}
if type_token == Some(PSEUDO_TYPE) {
return Some(self.expression(mk1(PseudoType, self.prev_upper())))
}
if type_token == Some(OBJECT_IDENTIFIER) {
return Some(self.expression(mk1(ObjectIdentifier, self.prev_upper())))
}
if type_token == Some(MAP) && self.match_(L_BRACKET) {
let key_type = self.parse_types(check_func~, schema~, allow_identifiers~)
if !self.match_(FARROW) {
self.retreat(index)
return None
}
let value_type = self.parse_types(check_func~, schema~, allow_identifiers~)
if !self.match_(R_BRACKET) {
self.retreat(index)
return None
}
return Some(
mk(DataType, [
("this", DType::MAP),
("expressions", [key_type, value_type].filter_map(x => x)),
("nested", true),
]),
)
}
let in_set = fn(s : TokenSet) {
match type_token {
Some(t) => s.contains(t)
None => false
}
}
let nested = in_set(self.cfg.nested_type_tokens)
let is_struct = in_set(self.cfg.struct_type_tokens)
let is_aggregate = in_set(self.cfg.aggregate_type_tokens)
let mut expressions : Array[Expr]? = None
let mut maybe_func = false
if self.match_(L_PAREN) {
if is_struct {
expressions = Some(
self.parse_csv(() => self.parse_struct_types(type_required=true)),
)
} else if nested {
let exprs = self.parse_csv(() => {
self.parse_types(check_func~, schema~, allow_identifiers~)
})
expressions = Some(exprs)
if type_token == Some(NULLABLE) && exprs.length() == 1 {
let this = exprs[0]
this.set("nullable", true)
self.match_r_paren()
return Some(this)
}
} else if in_set(self.cfg.enum_type_tokens) {
expressions = Some(self.parse_csv(() => self.parse_equality()))
} else if type_token == Some(JSON) {
expressions = Some(self.parse_csv(() => self.parse_json_type_arg()))
} else if is_aggregate {
let func_or_ident = expr_or(self.parse_function(anonymous=true), () => {
self.parse_id_var(any_token=false, tokens=TokenSet::new([VAR, ANY]))
})
let foi = match func_or_ident {
Some(f) => f
None => return None
}
let exprs = [foi]
if self.match_(COMMA) {
exprs.append(
self.parse_csv(() => {
self.parse_types(check_func~, schema~, allow_identifiers~)
}),
)
}
expressions = Some(exprs)
} else {
let mut exprs = self.parse_csv(() => self.parse_type_size())
if type_token == Some(VECTOR) && exprs.length() == 2 {
exprs = self.parse_vector_expressions(exprs)
}
expressions = Some(exprs)
}
if !self.match_(R_PAREN) {
self.retreat(index)
return None
}
maybe_func = true
}
let mut values : Array[Expr]? = None
if nested && self.match_(LT) {
if is_struct {
expressions = Some(
self.parse_csv(() => self.parse_struct_types(type_required=true)),
)
} else {
expressions = Some(
self.parse_csv(() => {
self.parse_types(
check_func~,
schema~,
allow_identifiers~,
with_collation=true,
)
}),
)
}
if !self.match_(GT) {
self.raise_error("Expecting >")
}
if self.match_any([L_BRACKET, L_PAREN]) {
let vs = self.parse_csv(() => self.parse_disjunction())
if vs.is_empty() && is_struct {
values = None
self.retreat(self.index - 1)
} else {
values = Some(vs)
self.match_any([R_BRACKET, R_PAREN]) |> ignore
}
}
}
if in_set(self.cfg.timestamps) {
if self.match_text_seq(["WITH", "TIME", "ZONE"]) {
maybe_func = false
let tz_type = if in_set(self.cfg.times) {
DType::TIMETZ
} else {
DType::TIMESTAMPTZ
}
this = Some(
mk(DataType, [("this", tz_type), ("expressions", expressions)]),
)
} else if self.match_text_seq(["WITH", "LOCAL", "TIME", "ZONE"]) {
maybe_func = false
this = Some(
mk(DataType, [
("this", DType::TIMESTAMPLTZ),
("expressions", expressions),
]),
)
} else if self.match_text_seq(["WITHOUT", "TIME", "ZONE"]) {
maybe_func = false
}
} else if type_token == Some(INTERVAL) {
if self.dialect.cfg.valid_interval_units.contains(py_upper(self.curr.text)) {
let mut unit = self.parse_var(upper=true)
if self.match_text("TO") {
unit = Some(
mk(IntervalSpan, [
("this", unit),
("expression", self.parse_var(upper=true)),
]),
)
}
let interval = self.expression(mk(Interval, [("unit", unit)]))
this = Some(self.expression(mk1(DataType, interval)))
} else {
this = Some(self.expression(mk1(DataType, DType::INTERVAL)))
}
} else if type_token == Some(VOID) {
this = Some(mk1(DataType, DType::NULL))
}
if maybe_func && check_func {
let index2 = self.index
let peek = self.parse_string()
if peek is None {
self.retreat(index)
return None
}
self.retreat(index2)
}
let mut this = match this {
Some(t) => {
match expressions {
Some(e) if !e.is_empty() => t.set("expressions", e)
_ => ()
}
t
}
None => {
let mut tt = type_token.unwrap()
if self.match_text("UNSIGNED") {
match self.cfg.signed_to_unsigned_type_token.get(tt) {
Some(u) => tt = u
None => self.raise_error("Cannot convert \{tt.name()} to unsigned.")
}
}
let no_exprs = match expressions {
Some(e) => e.is_empty()
None => true
}
if tt == NULLABLE && no_exprs {
self.retreat(index)
return None
}
let dtype = match dtype_from_name(tt.name()) {
Some(d) => d
None => raise ValueError("No DType for \{tt.name()}")
}
let mut t = mk(DataType, [
("this", dtype),
("expressions", expressions),
("nested", nested),
])
match values {
Some(vs) => {
let cls = if is_struct { Struct } else { Array }
t = cast_to_type(mk(cls, [("expressions", vs)]), t)
}
None => ()
}
t
}
}
while self.match_(LIST) {
this = mk(DataType, [
("this", DType::LIST),
("expressions", [this]),
("nested", true),
])
}
let index = self.index
let mut matched_array = self.match_(ARRAY)
while self.curr.ok() {
let datatype_token = self.prev.token_type
let matched_l_bracket = self.match_(L_BRACKET)
if (!matched_l_bracket && !matched_array) ||
(datatype_token == ARRAY && self.match_(R_BRACKET)) {
break
}
matched_array = false
let vs = self.parse_csv(() => self.parse_disjunction())
let values = if vs.is_empty() { None } else { Some(vs) }
if values is Some(_) &&
!schema &&
(
!self.dialect.cfg.supports_fixed_size_arrays ||
datatype_token == ARRAY ||
!self.match_(R_BRACKET, advance=false)
) {
self.retreat(index)
break
}
this = mk(DataType, [
("this", DType::ARRAY),
("expressions", [this]),
("values", values),
("nested", true),
])
self.match_(R_BRACKET) |> ignore
}
if !self.fns.type_converters.is_empty() {
match this.args.get("this") {
Some(DT(d)) =>
match self.fns.type_converters.get(d) {
Some(converter) => this = converter(this)
None => ()
}
_ => ()
}
}
if with_collation && this.kind.is_a(DataType) && self.match_(COLLATE) {
this.set(
"collate",
expr_or(self.parse_identifier(), () => self.parse_column()),
)
}
Some(this)
}
///|
/// `exp.cast(expression, to, copy=False)` for an already-built DataType.
pub fn cast_to_type(expression : Expr, to : Expr) -> Expr {
let e = mk(Cast, [("this", expression), ("to", to)])
e.type_ = Some(to)
e
}
///|
pub fn Parser::parse_json_type_arg(self : Parser) -> Expr? raise SqlglotError {
if self.match_text("SKIP") {
let regexp = self.match_(RLIKE)
let mut arg = self.parse_column()
match arg {
Some(a) if a.kind.is_a(Column) => arg = Some(a.to_dot())
_ => ()
}
return Some(
self.expression(
mk(SkipJSONColumn, [("regexp", regexp), ("expression", arg)]),
),
)
}
let param_or_col = match self.parse_column() {
Some(p) if p.kind.is_a(Column) => p
_ => return None
}
if param_or_col.parts().length() == 1 && self.match_(EQ) {
let param = param_or_col.name()
let value = self.parse_primary()
return Some(
self.expression(mk(EQ, [("this", var_(param)), ("expression", value)])),
)
}
let col = param_or_col.to_dot()
let kind = self.parse_types(check_func=false, allow_identifiers=false)
Some(self.expression(mk(ColumnDef, [("this", col), ("kind", kind)])))
}
///|
pub fn Parser::parse_vector_expressions(
self : Parser,
expressions : Array[Expr],
) -> Array[Expr] raise SqlglotError {
match self.fns.hooks.parse_vector_expressions {
Some(f) => f(self, expressions)
None => {
let out = [datatype_from_str(expressions[0].name(), dialect=self.dialect)]
for i in 1.. Expr? raise SqlglotError {
match self.fns.hooks.parse_struct_types {
Some(f) => f(self, type_required)
None => self.parse_struct_types_base(type_required~)
}
}
///|
pub fn Parser::parse_struct_types_base(
self : Parser,
type_required? : Bool = false,
) -> Expr? raise SqlglotError {
let index = self.index
let this = if self.curr.ok() &&
self.next.ok() &&
self.cfg.type_tokens.contains(self.curr.token_type) &&
self.cfg.type_tokens.contains(self.next.token_type) {
self.parse_id_var()
} else {
expr_or(
self.parse_type(parse_interval=false, fallback_to_identifier=true),
() => self.parse_id_var(),
)
}
self.match_(COLON) |> ignore
if type_required &&
!(match this {
Some(t) => t.kind.is_a(DataType)
None => false
}) &&
!self.match_set(self.cfg.type_tokens, advance=false) {
self.retreat(index)
return self.parse_types()
}
self.parse_column_def(this)
}
///|
pub fn Parser::parse_at_time_zone(
self : Parser,
this : Expr?,
) -> Expr? raise SqlglotError {
if !self.match_text_seq(["AT", "TIME", "ZONE"]) {
return this
}
let e = self.expression(
mk(AtTimeZone, [("this", this), ("zone", self.parse_unary())]),
)
self.parse_at_time_zone(Some(e))
}
///|
pub fn Parser::parse_atom(self : Parser) -> Expr? raise SqlglotError {
if self.cfg.identifier_tokens.contains(self.curr.token_type) {
match self.parse_column() {
Some(column) => return Some(column)
None => ()
}
}
let token = self.curr
let token_type = token.token_type
let primary_parser = match self.fns.primary_parsers.get(token_type) {
Some(p) => p
None => return None
}
let next_type = self.next.token_type
if self.fns.column_operators.contains(next_type) ||
self.cfg.column_postfix_tokens.contains(next_type) ||
(token_type == STRING && next_type == STRING) {
return None
}
self.advance()
primary_parser(self, token)
}
///|
pub fn Parser::parse_column(self : Parser) -> Expr? raise SqlglotError {
match self.fns.hooks.parse_column {
Some(f) => f(self)
None => self.parse_column_base()
}
}
///|
pub fn Parser::parse_column_base(self : Parser) -> Expr? raise SqlglotError {
let mut column = self.parse_column_parts_fast()
if column is None {
let mut this = self.parse_column_reference()
if this is None {
this = self.parse_bracket(this)
}
column = match this {
Some(_) => self.parse_column_ops(this)
None => this
}
}
match column {
Some(c) => {
if self.dialect.cfg.supports_column_join_marks {
c.set("join_mark", self.match_(JOIN_MARKER))
}
if self.cfg.colon_is_variant_extract {
column = self.parse_colon_as_variant_extract(column)
}
}
None => ()
}
column
}
///|
pub fn Parser::parse_column_parts_fast(
self : Parser,
) -> Expr? raise SqlglotError {
let index = self.index
let mut parts : Array[Expr]? = None
let mut all_comments : Array[String]? = None
while self.match_set(self.cfg.identifier_tokens) {
let token = self.prev
let comments = self.prev_comments
if parts is None &&
self.fns.no_paren_function_parsers.contains(py_upper(token.text)) {
self.retreat(index)
return None
}
let has_dot = self.match_(DOT)
let curr_tt = self.curr.token_type
if !has_dot {
if self.fns.column_operators.contains(curr_tt) ||
self.cfg.column_postfix_tokens.contains(curr_tt) {
self.retreat(index)
return None
}
} else if !self.cfg.identifier_tokens.contains(curr_tt) {
self.retreat(index)
return None
}
if parts is None {
parts = Some([])
}
if !comments.is_empty() {
if all_comments is None {
all_comments = Some([])
}
all_comments.unwrap().append(comments)
self.prev_comments = []
}
parts
.unwrap()
.push(
self.expression(
mk(Identifier, [
("this", token.text),
("quoted", token.token_type == IDENTIFIER),
]),
token~,
),
)
if !has_dot {
break
}
}
let parts = match parts {
Some(p) => p
None => return None
}
let n = parts.length()
let mut column = if n == 1 {
mk1(Column, parts[0])
} else if n == 2 {
mk(Column, [("this", parts[1]), ("table", parts[0])])
} else if n == 3 {
mk(Column, [("this", parts[2]), ("table", parts[1]), ("db", parts[0])])
} else {
mk(Column, [
("this", parts[3]),
("table", parts[2]),
("db", parts[1]),
("catalog", parts[0]),
])
}
for i in 4.. column.add_comments(Some(c))
_ => ()
}
Some(column)
}
///|
pub fn Parser::parse_column_reference(
self : Parser,
) -> Expr? raise SqlglotError {
let mut this = self.parse_field()
if this is None &&
self.match_(VALUES, advance=false) &&
self.cfg.values_followed_by_paren &&
(!self.next.ok() || self.next.token_type != L_PAREN) {
this = self.parse_id_var()
}
match this {
Some(t) if t.kind == Identifier => {
let comments = t.pop_comments()
this = Some(self.expression(mk1(Column, t), comments~))
}
_ => ()
}
this
}
///|
pub fn Parser::build_json_extract(
self : Parser,
this : Expr?,
path_parts : Array[Expr],
) -> (Expr?, Array[Expr]) raise SqlglotError {
if path_parts.length() > 1 {
let e = self.expression(
mk(JSONExtract, [
("this", this),
("expression", mk(JSONPath, [("expressions", path_parts)])),
("variant_extract", true),
("requires_json", self.cfg.json_extract_requires_json_expression),
]),
)
return (Some(e), [mk0(JSONPathRoot)])
}
(this, path_parts)
}
///|
pub fn Parser::parse_colon_as_variant_extract(
self : Parser,
this : Expr?,
) -> Expr? raise SqlglotError {
let mut this = this
let mut path_parts : Array[Expr] = [mk0(JSONPathRoot)]
while self.match_(COLON) {
if !self.cfg.colon_chain_is_single_extract {
let (t, p) = self.build_json_extract(this, path_parts)
this = t
path_parts = p
}
let key = self.parse_id_var(any_token=true, tokens=TokenSet::new([SELECT]))
match key {
Some(k) => {
let quoted = k.kind == Identifier && k.has("quoted")
path_parts.push(
mk(JSONPathKey, [("this", k.name()), ("quoted", quoted)]),
)
}
None => ()
}
while true {
if self.match_(DOT) {
match
self.parse_id_var(any_token=true, tokens=TokenSet::new([SELECT])) {
Some(next_key) => {
let quoted = next_key.kind == Identifier && next_key.has("quoted")
path_parts.push(
mk(JSONPathKey, [("this", next_key.name()), ("quoted", quoted)]),
)
}
None => ()
}
} else if self.match_(L_BRACKET) {
let bracket_expr = self.parse_bracket_key_value()
if !self.match_(R_BRACKET) {
self.raise_error("Expected ]")
}
match bracket_expr {
Some(be) =>
if be.is_string() {
path_parts.push(
mk(JSONPathKey, [("this", be.name()), ("quoted", true)]),
)
} else if be.is_star() {
path_parts.push(mk1(JSONPathSubscript, mk0(JSONPathWildcard)))
} else if be.is_number() {
path_parts.push(mk1(JSONPathSubscript, number_value(be)))
} else {
let (t, p) = self.build_json_extract(this, path_parts)
this = t
path_parts = p
this = Some(
self.expression(
mk(Bracket, [
("this", this),
("expressions", [be]),
("json_access", true),
]),
),
)
}
None => ()
}
} else if self.match_(DCOLON) {
let (t, p) = self.build_json_extract(this, path_parts)
this = t
path_parts = p
match self.parse_types() {
Some(cast_type) =>
this = Some(
self.expression(mk(Cast, [("this", this), ("to", cast_type)])),
)
None => self.raise_error("Expected type after '::'")
}
} else {
break
}
}
}
let (t, _) = self.build_json_extract(this, path_parts)
t
}
///|
/// Python `literal.to_py()` for a numeric literal, as an argument value (int when
/// integral, else the textual decimal).
pub fn number_value(e : Expr) -> Value {
match e.to_py_int() {
Some(i) => Int(i)
None => Str(decimal_str(e))
}
}
///|
pub fn Parser::parse_dcolon(self : Parser) -> Expr? raise SqlglotError {
match self.fns.hooks.parse_dcolon {
Some(f) => f(self)
None => self.parse_types()
}
}
///|
pub fn Parser::parse_column_ops(
self : Parser,
this : Expr?,
) -> Expr? raise SqlglotError {
match self.fns.hooks.parse_column_ops {
Some(f) => f(self, this)
None => self.parse_column_ops_base(this)
}
}
///|
pub fn Parser::parse_column_ops_base(
self : Parser,
this : Expr?,
) -> Expr? raise SqlglotError {
let mut this = this
while self.cfg.brackets.contains(self.curr.token_type) {
this = self.parse_bracket(this)
}
let column_operators = self.fns.column_operators
let cast_column_operators = self.cfg.cast_column_operators
while self.curr.ok() {
let op_token = self.curr.token_type
let op = match column_operators.get(op_token) {
Some(o) => o
None => break
}
self.advance()
let mut field : Expr? = None
if cast_column_operators.contains(op_token) {
field = self.parse_dcolon()
if field is None {
self.raise_error("Expected type")
}
} else if op is Some(_) && self.curr.ok() {
field = expr_or(self.parse_column_reference(), () => self.parse_bitwise())
match field {
Some(f) if f.kind.is_a(Column) && self.match_(DOT, advance=false) =>
field = self.parse_column_ops(field)
_ => ()
}
} else {
let dot = self.is_connected() && self.prev.token_type == DOT
field = self.parse_field(any_token=true, anonymous_func=true)
match field {
Some(f) if dot && f.kind.is_any([Null, Boolean]) =>
field = Some(
self.expression(
mk1(Identifier, self.prev.text),
comments=f.comments.unwrap_or([]),
),
)
_ => ()
}
}
match (field, this) {
(Some(f), Some(t)) if f.kind.is_any([Func, Window]) =>
this = Some(
t.transform(n => {
if n.kind.is_a(Column) {
Some(n.to_dot(include_dots=false))
} else {
Some(n)
}
}),
)
_ => ()
}
match op {
Some(op) => this = op(self, this, field)
None =>
match this {
Some(t) if t.kind.is_a(Column) && !t.has("catalog") =>
this = Some(
self.expression(
mk(Column, [
("this", field),
("table", t.this()),
("db", t.arg("table")),
("catalog", t.arg("db")),
]),
comments=t.comments.unwrap_or([]),
),
)
_ =>
match field {
Some(f) if f.kind.is_a(Window) => {
let window_func = self.expression(
mk(Dot, [("this", this), ("expression", f.this())]),
)
f.set("this", window_func)
this = Some(f)
}
_ =>
this = Some(
self.expression(
mk(Dot, [("this", this), ("expression", field)]),
),
)
}
}
}
match field {
Some(f) =>
match f.comments {
Some(c) if !c.is_empty() =>
match this {
Some(t) => t.add_comments(Some(f.pop_comments()))
None => ()
}
_ => ()
}
None => ()
}
this = self.parse_bracket(this)
}
this
}
///|
pub fn Parser::parse_paren(self : Parser) -> Expr? raise SqlglotError {
if !self.match_(L_PAREN) {
return None
}
let comments = self.prev_comments
let query = self.parse_select()
let expressions = match query {
Some(q) => [q]
None => self.parse_expressions()
}
let mut this : Expr? = if expressions.is_empty() {
None
} else {
Some(expressions[0])
}
if this is None && self.match_(R_PAREN, advance=false) {
this = Some(self.expression(mk0(Tuple)))
} else if expressions.length() > 1 || self.prev.token_type == COMMA {
this = Some(self.expression(mk(Tuple, [("expressions", expressions)])))
} else {
match this {
Some(t) if t.kind.is_any([Select, SetOperation]) =>
this = self.parse_subquery(this, parse_alias=false)
Some(t) if t.kind.is_any([Subquery, Values]) =>
this = self.parse_subquery(
self.parse_query_modifiers(self.parse_set_operations(this)),
parse_alias=false,
)
_ => this = Some(self.expression(mk1(Paren, this)))
}
}
match this {
Some(t) => t.add_comments(Some(comments))
None => ()
}
self.match_r_paren(expression?=this)
match this {
Some(t) if t.kind == Paren &&
(match t.this() {
Some(x) => x.kind.is_a(AggFunc)
None => false
}) => return self.parse_window(this)
_ => ()
}
this
}
///|
pub fn Parser::parse_primary(self : Parser) -> Expr? raise SqlglotError {
match self.fns.hooks.parse_primary {
Some(f) => f(self)
None => self.parse_primary_base()
}
}
///|
pub fn Parser::parse_primary_base(self : Parser) -> Expr? raise SqlglotError {
if self.match_keys(self.fns.primary_parsers) {
let token_type = self.prev.token_type
let primary = self.fns.primary_parsers[token_type](self, self.prev)
if token_type == STRING {
let expressions = [primary].filter_map(x => x)
while self.match_(STRING, advance=false) {
if self.is_connected() && self.cfg.adjacent_strings_cannot_be_connected {
self.raise_error(
"Adjacent string literals need to be separated by whitespace or comments",
)
}
self.advance()
expressions.push(literal_string(self.prev.text))
}
if expressions.length() > 1 {
return Some(
self.expression(
mk(Concat, [
("expressions", expressions),
("coalesce", self.dialect.cfg.concat_coalesce),
]),
),
)
}
}
return primary
}
if self.match_pair(DOT, NUMBER) {
return Some(literal_number("0.\{self.prev.text}"))
}
self.parse_paren()
}
///|
pub fn Parser::parse_field(
self : Parser,
any_token? : Bool = false,
tokens? : TokenSet,
anonymous_func? : Bool = false,
) -> Expr? raise SqlglotError {
let after_dot = self.cfg.supports_digit_prefixed_field_names &&
self.prev.token_type == DOT
let mut field = if anonymous_func {
expr_or(self.parse_function(anonymous=anonymous_func, any_token~), () => {
self.parse_primary()
})
} else {
expr_or(self.parse_primary(), () => {
self.parse_function(anonymous=anonymous_func, any_token~)
})
}
if field is None {
field = self.parse_id_var(any_token~, tokens?)
}
match field {
Some(f) if after_dot && f.kind == Literal && f.is_number() => {
let mut name = f.name()
if self.is_connected() && self.parse_var(any_token=true) is Some(_) {
name += self.prev.text
}
field = Some(
mk(Identifier, [("this", name), ("quoted", true)]).update_positions(
Some(f),
),
)
}
_ => ()
}
field
}
///|
pub fn Parser::parse_function(
self : Parser,
functions? : Map[String, FuncBuilder],
anonymous? : Bool = false,
optional_parens? : Bool = true,
any_token? : Bool = false,
) -> Expr? raise SqlglotError {
match self.fns.hooks.parse_function {
Some(f) => f(self, functions, anonymous, optional_parens, any_token)
None =>
self.parse_function_base(
functions?,
anonymous~,
optional_parens~,
any_token~,
)
}
}
///|
pub fn Parser::parse_function_base(
self : Parser,
functions? : Map[String, FuncBuilder],
anonymous? : Bool = false,
optional_parens? : Bool = true,
any_token? : Bool = false,
) -> Expr? raise SqlglotError {
let mut fn_syntax = false
if self.match_(L_BRACE, advance=false) &&
self.next.ok() &&
py_upper(self.next.text) == "FN" {
self.advance(times=2)
fn_syntax = true
}
let func = self.parse_function_call(
functions?,
anonymous~,
optional_parens~,
any_token~,
)
if fn_syntax {
self.match_(R_BRACE) |> ignore
}
func
}