wyil.check.SignatureCheck Maven / Gradle / Ivy
// Copyright 2011 The Whiley Project Developers
//
// Licensed 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.
package wyil.check;
import wyil.lang.Compiler;
import wyil.lang.WyilFile;
import wyil.lang.WyilFile.*;
import wyil.util.AbstractConsumer;
import wyil.util.TypeMangler;
import wyc.util.ErrorMessages;
import java.util.HashSet;
import wycc.lang.Syntactic;
/**
*
* Responsible for checking no duplicate declarations exist. That is,
* declarations with the same signature. For example, the following is
* prohibited:
*
*
* function f(int x) -> (int r):
* return x+1
*
* function f(int x) -> (int r):
* return x-1
*
*
* There are a few special cases. For example, `export` declarations have no
* mangle information associated with them at all.
*
*
*
* @author David J. Pearce
*
*/
public class SignatureCheck extends AbstractConsumer implements Compiler.Check {
private static final TypeMangler mangler = new TypeMangler.Default();
private boolean status = true;
@Override
public boolean check(WyilFile file) {
visitModule(file, new Context());
return status;
}
@Override
public void visitExternalUnit(Decl.Unit unit, Context data) {
// NOTE: we override this to prevent unnecessarily traversing units
}
@Override
public void visitType(Decl.Type decl, Context data) {
if(!data.register(decl)) {
syntaxError(decl.getName(),WyilFile.DUPLICATE_DECLARATION);
}
}
@Override
public void visitProperty(Decl.Property decl, Context data) {
if(!data.register(decl)) {
syntaxError(decl.getName(),WyilFile.DUPLICATE_DECLARATION);
}
}
@Override
public void visitFunction(Decl.Function decl, Context data) {
if(!data.register(decl)) {
syntaxError(decl.getName(),WyilFile.DUPLICATE_DECLARATION);
}
}
@Override
public void visitMethod(Decl.Method decl, Context data) {
if(!data.register(decl)) {
syntaxError(decl.getName(),WyilFile.DUPLICATE_DECLARATION);
}
}
@Override
public void visitStaticVariable(Decl.StaticVariable decl, Context data) {
if(!data.register(decl)) {
syntaxError(decl.getName(),WyilFile.DUPLICATE_DECLARATION);
}
}
/**
* A simple store of name mangles used to identify any clashes.
*
* @author David J. Pearce
*
*/
public static final class Context {
private HashSet mangles = new HashSet<>();
/**
* Register a new named declaration, and check whether or not it clashes with a
* previously registered declaration.
*
* @param d
* @return true if this name was successfully registered without a clash.
*/
public boolean register(Decl.Named d) {
String mangle = toMangledName(d);
return mangles.add(mangle);
}
/**
* Determine the appropriate mangled string for a given named declaration. This
* is critical to ensuring that overloaded declarations do not clash.
*
* @param decl
* @return
*/
private String toMangledName(Decl.Named> decl) {
// Determine whether this is an exported symbol or not
boolean exported = decl.getModifiers().match(Modifier.Export.class) != null;
// Construct base name
String name = decl.getQualifiedName().toString().replace("::", "$");
// Add type mangles for non-exported symbols
if(!exported && decl instanceof Decl.Method) {
Decl.Method method = (Decl.Method) decl;
Type ret = method.getType().getReturn();
Type parameter = method.getType().getParameter();
name += getMangle(parameter);
name += getMangle(ret);
} else if(!exported && decl instanceof Decl.Callable) {
Decl.Callable callable = (Decl.Callable) decl;
Type ret = callable.getType().getReturn();
Type parameter = callable.getType().getParameter();
name += getMangle(parameter);
name += getMangle(ret);
} else if(decl instanceof Decl.Type) {
name += "$type";
} else if(decl instanceof Decl.StaticVariable) {
name += "$static";
}
return name;
}
private String getMangle(Type type) {
if (type.shape() == 0) {
return "";
} else {
return "$" + mangler.getMangle(type);
}
}
}
private void syntaxError(Syntactic.Item e, int code, Syntactic.Item... context) {
status = false;
ErrorMessages.syntaxError(e, code, context);
}
}