Skip to content
This repository has been archived by the owner on Aug 2, 2022. It is now read-only.

Commit

Permalink
Feature/analyzer (#464)
Browse files Browse the repository at this point in the history
* update

* update

* add doc

* change the package name from schema to symbol

* fix build issue
  • Loading branch information
penghuo authored May 11, 2020
1 parent 242ca1f commit e7e2ecb
Show file tree
Hide file tree
Showing 36 changed files with 1,392 additions and 36 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,4 @@ build/
# git mergetool artifact
*.orig
gen
*.tokens
7 changes: 7 additions & 0 deletions core/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ dependencies {
compile group: 'org.springframework', name: 'spring-beans', version: '5.2.5.RELEASE'

testImplementation('org.junit.jupiter:junit-jupiter:5.6.2')
testCompile group: 'org.hamcrest', name: 'hamcrest-library', version: '2.1'
testCompile group: 'org.springframework', name: 'spring-test', version: '5.2.5.RELEASE'
testCompile group: 'org.mockito', name: 'mockito-core', version: '3.3.3'
testCompile group: 'org.mockito', name: 'mockito-junit-jupiter', version: '3.3.3'
Expand All @@ -35,6 +36,12 @@ jacocoTestReport {
reports {
html.enabled true
}
afterEvaluate {
classDirectories.setFrom(files(classDirectories.files.collect {
fileTree(dir: it,
exclude: ['**/ast/**'])
}))
}
}
test.finalizedBy(project.tasks.jacocoTestReport)
jacocoTestCoverageVerification {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/*
* Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* or in the "license" file accompanying this file. This file 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.
*/

package com.amazon.opendistroforelasticsearch.sql.analysis;

import java.util.Objects;

/**
* The context used for Analyzer.
*/
public class AnalysisContext {
/** Environment stack for symbol scope management */
private TypeEnvironment environment;

public AnalysisContext() {
this.environment = new TypeEnvironment(null);
}

public AnalysisContext(TypeEnvironment environment) {
this.environment = environment;
}

/**
* Push a new environment
*/
public void push() {
environment = new TypeEnvironment(environment);
}

/**
* Return current environment
* @return current environment
*/
public TypeEnvironment peek() {
return environment;
}

/**
* Pop up current environment from environment chain
* @return current environment (before pop)
*/
public TypeEnvironment pop() {
Objects.requireNonNull(environment, "Fail to pop context due to no environment present");

TypeEnvironment curEnv = environment;
environment = curEnv.getParent();
return curEnv;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/*
* Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* or in the "license" file accompanying this file. This file 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.
*/

package com.amazon.opendistroforelasticsearch.sql.analysis;

import com.amazon.opendistroforelasticsearch.sql.ast.AbstractNodeVisitor;
import com.amazon.opendistroforelasticsearch.sql.ast.tree.Filter;
import com.amazon.opendistroforelasticsearch.sql.ast.tree.Relation;
import com.amazon.opendistroforelasticsearch.sql.ast.tree.UnresolvedPlan;
import com.amazon.opendistroforelasticsearch.sql.expression.DSL;
import com.amazon.opendistroforelasticsearch.sql.expression.Expression;
import com.amazon.opendistroforelasticsearch.sql.planner.logical.LogicalFilter;
import com.amazon.opendistroforelasticsearch.sql.planner.logical.LogicalPlan;
import com.amazon.opendistroforelasticsearch.sql.planner.logical.LogicalRelation;
import com.amazon.opendistroforelasticsearch.sql.storage.StorageEngine;
import com.amazon.opendistroforelasticsearch.sql.storage.Table;
import lombok.RequiredArgsConstructor;

/**
* Analyze the {@link UnresolvedPlan} in the {@link AnalysisContext} to construct the {@link LogicalPlan}
*/
@RequiredArgsConstructor
public class Analyzer extends AbstractNodeVisitor<LogicalPlan, AnalysisContext> {
private final ExpressionAnalyzer expressionAnalyzer;
private final StorageEngine storageEngine;

public LogicalPlan analyze(UnresolvedPlan unresolved, AnalysisContext context) {
return unresolved.accept(this, context);
}

@Override
public LogicalPlan visitRelation(Relation node, AnalysisContext context) {
context.push();
TypeEnvironment curEnv = context.peek();
Table table = storageEngine.getTable(node.getTableName());
table.getFieldTypes().forEach((k, v) -> curEnv.define(DSL.ref(k), v));
return new LogicalRelation(node.getTableName());
}

@Override
public LogicalPlan visitFilter(Filter node, AnalysisContext context) {
LogicalPlan child = node.getChild().get(0).accept(this, context);
Expression condition = expressionAnalyzer.analyze(node.getCondition(), context);
return new LogicalFilter(condition, child);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
/*
* Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* or in the "license" file accompanying this file. This file 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.
*/

package com.amazon.opendistroforelasticsearch.sql.analysis;

import com.amazon.opendistroforelasticsearch.sql.ast.AbstractNodeVisitor;
import com.amazon.opendistroforelasticsearch.sql.ast.expression.And;
import com.amazon.opendistroforelasticsearch.sql.ast.expression.EqualTo;
import com.amazon.opendistroforelasticsearch.sql.ast.expression.Literal;
import com.amazon.opendistroforelasticsearch.sql.ast.expression.UnresolvedAttribute;
import com.amazon.opendistroforelasticsearch.sql.ast.expression.UnresolvedExpression;
import com.amazon.opendistroforelasticsearch.sql.data.model.ExprValueUtils;
import com.amazon.opendistroforelasticsearch.sql.expression.DSL;
import com.amazon.opendistroforelasticsearch.sql.expression.Expression;
import com.amazon.opendistroforelasticsearch.sql.expression.ReferenceExpression;
import lombok.RequiredArgsConstructor;

/**
* Analyze the {@link UnresolvedExpression} in the {@link AnalysisContext} to construct the {@link Expression}
*/
@RequiredArgsConstructor
public class ExpressionAnalyzer extends AbstractNodeVisitor<Expression, AnalysisContext> {
private final DSL dsl;

public Expression analyze(UnresolvedExpression unresolved, AnalysisContext context) {
return unresolved.accept(this, context);
}

@Override
public Expression visitUnresolvedAttribute(UnresolvedAttribute node, AnalysisContext context) {
TypeEnvironment typeEnv = context.peek();
ReferenceExpression ref = DSL.ref(node.getAttr());
typeEnv.resolve(ref);
return ref;
}

@Override
public Expression visitEqualTo(EqualTo node, AnalysisContext context) {
Expression left = node.getLeft().accept(this, context);
Expression right = node.getRight().accept(this, context);

return dsl.equal(context.peek(), left, right);
}

@Override
public Expression visitLiteral(Literal node, AnalysisContext context) {
return DSL.literal(ExprValueUtils.fromObjectValue(node.getValue()));
}

@Override
public Expression visitAnd(And node, AnalysisContext context) {
Expression left = node.getLeft().accept(this, context);
Expression right = node.getRight().accept(this, context);

return dsl.and(context.peek(), left, right);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
/*
* Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* or in the "license" file accompanying this file. This file 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.
*/

package com.amazon.opendistroforelasticsearch.sql.analysis;

import com.amazon.opendistroforelasticsearch.sql.analysis.symbol.Namespace;
import com.amazon.opendistroforelasticsearch.sql.analysis.symbol.Symbol;
import com.amazon.opendistroforelasticsearch.sql.analysis.symbol.SymbolTable;
import com.amazon.opendistroforelasticsearch.sql.data.model.ExprType;
import com.amazon.opendistroforelasticsearch.sql.exception.SemanticCheckException;
import com.amazon.opendistroforelasticsearch.sql.expression.Expression;
import com.amazon.opendistroforelasticsearch.sql.expression.ReferenceExpression;
import com.amazon.opendistroforelasticsearch.sql.expression.env.Environment;
import lombok.Getter;

import java.util.Optional;

/**
* The definition of Type Environment.
*/
public class TypeEnvironment implements Environment<Expression, ExprType> {
@Getter
private final TypeEnvironment parent;
private final SymbolTable symbolTable;

public TypeEnvironment(TypeEnvironment parent) {
this.parent = parent;
this.symbolTable = new SymbolTable();
}

public TypeEnvironment(TypeEnvironment parent, SymbolTable symbolTable) {
this.parent = parent;
this.symbolTable = symbolTable;
}

/**
* Resolve the {@link Expression} from environment.
*
* @param var expression
* @return resolved {@link ExprType}
*/
@Override
public ExprType resolve(Expression var) {
if (var instanceof ReferenceExpression) {
ReferenceExpression ref = (ReferenceExpression) var;
for (TypeEnvironment cur = this; cur != null; cur = cur.parent) {
Optional<ExprType> typeOptional = cur.symbolTable.lookup(new Symbol(Namespace.FIELD_NAME,
ref.getAttr()));
if (typeOptional.isPresent()) {
return typeOptional.get();
}
}
}
throw new SemanticCheckException(String.format("can't resolve expression %s in type env", var));
}

/**
* Define symbol with the type
*
* @param var symbol to define
* @param type type
*/
public void define(Expression var, ExprType type) {
if (var instanceof ReferenceExpression) {
ReferenceExpression ref = (ReferenceExpression) var;
symbolTable.store(new Symbol(Namespace.FIELD_NAME, ref.getAttr()), type);
} else {
throw new IllegalArgumentException(String.format("only support define reference, unexpected expression %s"
, var));
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/*
* Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* or in the "license" file accompanying this file. This file 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.
*/

package com.amazon.opendistroforelasticsearch.sql.analysis.symbol;

/**
* Namespace of symbol to avoid naming conflict
*/
public enum Namespace {

FIELD_NAME("Field"),
FUNCTION_NAME("Function");

private final String name;

Namespace(String name) {
this.name = name;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*
* Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* or in the "license" file accompanying this file. This file 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.
*/

package com.amazon.opendistroforelasticsearch.sql.analysis.symbol;

import lombok.Getter;
import lombok.RequiredArgsConstructor;

/**
* Symbol in the scope
*/
@Getter
@RequiredArgsConstructor
public class Symbol {
private final Namespace namespace;
private final String name;
}
Loading

0 comments on commit e7e2ecb

Please sign in to comment.