drift/sqlparser/lib/src/ast/ast.dart

194 lines
5.5 KiB
Dart

import 'package:meta/meta.dart';
import 'package:source_span/source_span.dart';
import 'package:sqlparser/src/analysis/analysis.dart';
import 'package:sqlparser/src/reader/syntactic_entity.dart';
import 'package:sqlparser/src/reader/tokenizer/token.dart';
import 'package:sqlparser/src/utils/ast_equality.dart';
import 'package:sqlparser/src/utils/meta.dart';
part 'clauses/limit.dart';
part 'clauses/ordering.dart';
part 'clauses/upsert.dart';
part 'clauses/with.dart';
part 'common/queryables.dart';
part 'common/renamable.dart';
part 'common/tuple.dart';
part 'expressions/aggregate.dart';
part 'expressions/case.dart';
part 'expressions/cast.dart';
part 'expressions/expressions.dart';
part 'expressions/function.dart';
part 'expressions/literals.dart';
part 'expressions/reference.dart';
part 'expressions/simple.dart';
part 'expressions/subquery.dart';
part 'expressions/variables.dart';
part 'moor/declared_statement.dart';
part 'moor/import_statement.dart';
part 'moor/inline_dart.dart';
part 'moor/moor_file.dart';
part 'moor/nested_star_result_column.dart';
part 'schema/column_definition.dart';
part 'schema/table_definition.dart';
part 'statements/block.dart';
part 'statements/create_table.dart';
part 'statements/create_index.dart';
part 'statements/create_trigger.dart';
part 'statements/create_view.dart';
part 'statements/delete.dart';
part 'statements/insert.dart';
part 'statements/invalid.dart';
part 'statements/select.dart';
part 'statements/statement.dart';
part 'statements/update.dart';
part 'visitor.dart';
/// A node in the abstract syntax tree of an SQL statement.
abstract class AstNode with HasMetaMixin implements SyntacticEntity {
/// The parent of this node, or null if this is the root node. Will be set
/// by the analyzer after the tree has been parsed.
AstNode parent;
/// The first token that appears in this node. This information is not set for
/// all nodes.
Token first;
/// The last token that appears in this node. This information is not set for
/// all nodes.
Token last;
@override
bool synthetic = false;
@override
int get firstPosition => first.span.start.offset;
@override
int get lastPosition => last.span.end.offset;
@override
FileSpan get span {
if (!hasSpan) return null;
return first.span.expand(last.span);
}
@override
bool get hasSpan => first != null && last != null;
/// Sets the [AstNode.first] and [AstNode.last] property in one go.
void setSpan(Token first, Token last) {
this.first = first;
this.last = last;
}
/// Returns all parents of this node up to the root. If this node is the root,
/// the iterable will be empty.
Iterable<AstNode> get parents sync* {
var node = parent;
while (node != null) {
yield node;
node = node.parent;
}
}
/// Returns an iterable containing `this` node and all [parents].
Iterable<AstNode> get selfAndParents sync* {
yield this;
yield* parents;
}
/// Recursively returns all descendants of this node, e.g. its children, their
/// children and so on. The tree will be pre-order traversed.
Iterable<AstNode> get allDescendants sync* {
for (final child in childNodes) {
yield child;
yield* child.allDescendants;
}
}
/// Returns an iterable that fields yields this node, followed by
/// [allDescendants].
Iterable<AstNode> get selfAndDescendants sync* {
yield this;
yield* allDescendants;
}
/// Finds the first element in [selfAndParents] of the type [T].
///
/// Returns `null` if there's no node of type [T] surrounding this ast node.
T /*?*/ enclosingOfType<T extends AstNode>() {
for (final element in selfAndParents) {
if (element is T) {
return element;
}
}
return null;
}
/// The [ReferenceScope], which contains available tables, column references
/// and functions for this node.
ReferenceScope get scope {
var node = this;
while (node != null) {
final scope = node.meta<ReferenceScope>();
if (scope != null) return scope;
node = node.parent;
}
throw StateError('No reference scope found in this or any parent node');
}
/// Applies a [ReferenceScope] to this node. Variables declared in [scope]
/// will be visible to this node and to [allDescendants].
set scope(ReferenceScope scope) {
setMeta<ReferenceScope>(scope);
}
/// All direct children of this node.
Iterable<AstNode> get childNodes;
/// Calls the appropriate method on the [visitor] to make it recognize this
/// node.
R accept<A, R>(AstVisitor<A, R> visitor, A arg);
/// Like [accept], but without an argument.
///
/// Null will be used for the argument instead.
R acceptWithoutArg<R>(AstVisitor<void, R> visitor) {
return accept(visitor, null);
}
/// Transforms children of this node by invoking [transformer] with the
/// argument [arg].
void transformChildren<A>(Transformer<A> transformer, A arg);
/// Whether the content of this node is equal to the [other] node of the same
/// type. The "content" refers to anything stored only in this node, children
/// are ignored.
@nonVirtual
bool contentEquals(AstNode other) {
final checker = EqualityEnforcingVisitor(this, considerChildren: false);
try {
checker.visit(other, null);
return true;
} on NotEqualException {
return false;
}
}
@override
String toString() {
if (hasSpan) {
return '$runtimeType: ${span.text}';
}
return super.toString();
}
}
/// Common interface for every node that has a `where` clause.
abstract class HasWhereClause implements AstNode {
Expression get where;
}