Skip to content

Commit

Permalink
Merge branch 'master' of github.com:ceylon/ceylon-spec into sin_natural
Browse files Browse the repository at this point in the history
  • Loading branch information
gavinking committed Dec 12, 2011
2 parents 33dac85 + 01036ae commit 62ddc83
Show file tree
Hide file tree
Showing 124 changed files with 641 additions and 201 deletions.
4 changes: 3 additions & 1 deletion src/Main.java
Expand Up @@ -19,7 +19,9 @@ public class Main {
public static void main(String[] args) throws Exception { public static void main(String[] args) throws Exception {
String path; String path;
if ( args.length==0 ) { if ( args.length==0 ) {
path = "corpus"; System.err.println("Usage Main <directoryName>");
System.exit(-1);
return;
} }
else { else {
path = args[0]; path = args[0];
Expand Down
12 changes: 10 additions & 2 deletions src/MainForTest.java
Expand Up @@ -19,7 +19,7 @@ public static void main(String[] args) throws Exception {


TypeChecker typeChecker = new TypeCheckerBuilder() TypeChecker typeChecker = new TypeCheckerBuilder()
.verbose(false) .verbose(false)
.addSrcDirectory( new File("test") ) .addSrcDirectory( new File("test/main") )
.getTypeChecker(); .getTypeChecker();
typeChecker.process(); typeChecker.process();
Tree.CompilationUnit compilationUnit = typeChecker.getPhasedUnitFromRelativePath("ceylon/language/Object.ceylon").getCompilationUnit(); Tree.CompilationUnit compilationUnit = typeChecker.getPhasedUnitFromRelativePath("ceylon/language/Object.ceylon").getCompilationUnit();
Expand All @@ -40,14 +40,22 @@ public static void main(String[] args) throws Exception {
} }
typeChecker = new TypeCheckerBuilder() typeChecker = new TypeCheckerBuilder()
.verbose(false) .verbose(false)
.addSrcDirectory( new File("test/capture") ) .addSrcDirectory( new File("test/main/capture") )
.getTypeChecker(); .getTypeChecker();
typeChecker.process(); typeChecker.process();
compilationUnit = typeChecker.getPhasedUnitFromRelativePath("Capture.ceylon").getCompilationUnit(); compilationUnit = typeChecker.getPhasedUnitFromRelativePath("Capture.ceylon").getCompilationUnit();
if ( compilationUnit == null ) { if ( compilationUnit == null ) {
throw new RuntimeException("Failed to pass getCompilationUnitFromRelativePath for top level files (no package) in real src dir"); throw new RuntimeException("Failed to pass getCompilationUnitFromRelativePath for top level files (no package) in real src dir");
} }


typeChecker = new TypeCheckerBuilder()
.verbose(false)
.addSrcDirectory( new File("test/moduledep1") )
.addSrcDirectory( new File("test/moduledep2") )
.addSrcDirectory( new File("test/moduletest") )
.getTypeChecker();
typeChecker.process();

ClosableVirtualFile latestZippedLanguageSourceFile = MainHelper.getLatestZippedLanguageSourceFile(); ClosableVirtualFile latestZippedLanguageSourceFile = MainHelper.getLatestZippedLanguageSourceFile();
typeChecker = new TypeCheckerBuilder() typeChecker = new TypeCheckerBuilder()
.verbose(false) .verbose(false)
Expand Down
13 changes: 11 additions & 2 deletions src/com/redhat/ceylon/compiler/typechecker/TypeChecker.java
Expand Up @@ -8,6 +8,7 @@
import com.redhat.ceylon.compiler.typechecker.context.PhasedUnits; import com.redhat.ceylon.compiler.typechecker.context.PhasedUnits;
import com.redhat.ceylon.compiler.typechecker.io.VFS; import com.redhat.ceylon.compiler.typechecker.io.VFS;
import com.redhat.ceylon.compiler.typechecker.io.VirtualFile; import com.redhat.ceylon.compiler.typechecker.io.VirtualFile;
import com.redhat.ceylon.compiler.typechecker.model.Module;
import com.redhat.ceylon.compiler.typechecker.util.AssertionVisitor; import com.redhat.ceylon.compiler.typechecker.util.AssertionVisitor;
import com.redhat.ceylon.compiler.typechecker.util.StatisticsVisitor; import com.redhat.ceylon.compiler.typechecker.util.StatisticsVisitor;


Expand All @@ -19,6 +20,8 @@
//TODO make an interface? //TODO make an interface?
public class TypeChecker { public class TypeChecker {


public static final String LANGUAGE_MODULE_VERSION = "0.1";

private final boolean verbose; private final boolean verbose;
private final List<VirtualFile> srcDirectories; private final List<VirtualFile> srcDirectories;
private final Context context; private final Context context;
Expand Down Expand Up @@ -107,8 +110,14 @@ public void process() throws RuntimeException {


private void executePhases(PhasedUnits phasedUnits, boolean forceSilence) { private void executePhases(PhasedUnits phasedUnits, boolean forceSilence) {
final List<PhasedUnit> listOfUnits = phasedUnits.getPhasedUnits(); final List<PhasedUnit> listOfUnits = phasedUnits.getPhasedUnits();
for (PhasedUnit pu : listOfUnits) {
pu.buildModuleImport(); phasedUnits.visitModules();

//By now le language module version should be known (as local)
//or we should use the default one.
Module languageModule = context.getModules().getLanguageModule();
if (languageModule.getVersion() == null) {
languageModule.setVersion(LANGUAGE_MODULE_VERSION);
} }


final ModuleValidator moduleValidator = new ModuleValidator(context, phasedUnits); final ModuleValidator moduleValidator = new ModuleValidator(context, phasedUnits);
Expand Down
Expand Up @@ -13,28 +13,32 @@
import java.util.Set; import java.util.Set;


import com.redhat.ceylon.compiler.typechecker.context.Context; import com.redhat.ceylon.compiler.typechecker.context.Context;
import com.redhat.ceylon.compiler.typechecker.context.PhasedUnit;
import com.redhat.ceylon.compiler.typechecker.context.PhasedUnits;
import com.redhat.ceylon.compiler.typechecker.io.VirtualFile;
import com.redhat.ceylon.compiler.typechecker.model.Module; import com.redhat.ceylon.compiler.typechecker.model.Module;
import com.redhat.ceylon.compiler.typechecker.model.ModuleImport;
import com.redhat.ceylon.compiler.typechecker.model.Modules; import com.redhat.ceylon.compiler.typechecker.model.Modules;
import com.redhat.ceylon.compiler.typechecker.model.Package; import com.redhat.ceylon.compiler.typechecker.model.Package;
import com.redhat.ceylon.compiler.typechecker.tree.Node; import com.redhat.ceylon.compiler.typechecker.tree.Node;
import com.redhat.ceylon.compiler.typechecker.tree.Tree;


/** /**
* Build modules and packages * Manager modules and packages (build, retrieve, handle errors etc)
* *
* @author Emmanuel Bernard <emmanuel@hibernate.org> * @author Emmanuel Bernard <emmanuel@hibernate.org>
*/ */
public class ModuleBuilder { public class ModuleManager {
public static final String MODULE_FILE = "module.ceylon"; public static final String MODULE_FILE = "module.ceylon";
public static final String PACKAGE_FILE = "package.ceylon"; public static final String PACKAGE_FILE = "package.ceylon";
private final Context context; private final Context context;
private final LinkedList<Package> packageStack = new LinkedList<Package>(); private final LinkedList<Package> packageStack = new LinkedList<Package>();
private Module currentModule; private Module currentModule;
private Modules modules; private Modules modules;
private final Map<Module,Set<Node>> missingModuleDependencies = new HashMap<Module, Set<Node>>(); private final Map<ModuleImport,Set<Node>> moduleImportToNode = new HashMap<ModuleImport, Set<Node>>();
private Map<List<String>, Set<String>> topLevelErrorsPerModuleName = new HashMap<List<String>,Set<String>>(); private Map<List<String>, Set<String>> topLevelErrorsPerModuleName = new HashMap<List<String>,Set<String>>();
private Map<Module, Node> moduleToNode = new HashMap<Module, Node>();


public ModuleBuilder(Context context) { public ModuleManager(Context context) {
this.context = context; this.context = context;
} }


Expand All @@ -51,6 +55,7 @@ public void initCoreModules() {
final List<String> defaultModuleName = Collections.singletonList("<default module>"); final List<String> defaultModuleName = Collections.singletonList("<default module>");
final Module defaultModule = createModule(defaultModuleName); final Module defaultModule = createModule(defaultModuleName);
defaultModule.setAvailable(true); defaultModule.setAvailable(true);
defaultModule.setVersion("<unknown>");
bindPackageToModule(emptyPackage, defaultModule); bindPackageToModule(emptyPackage, defaultModule);
modules.getListOfModules().add(defaultModule); modules.getListOfModules().add(defaultModule);
modules.setDefaultModule(defaultModule); modules.setDefaultModule(defaultModule);
Expand All @@ -63,7 +68,7 @@ public void initCoreModules() {
languageModule.setAvailable(false); //not available yet languageModule.setAvailable(false); //not available yet
modules.setLanguageModule(languageModule); modules.setLanguageModule(languageModule);
modules.getListOfModules().add(languageModule); modules.getListOfModules().add(languageModule);
defaultModule.getDependencies().add(languageModule); defaultModule.getImports().add(new ModuleImport(languageModule, false, false));
defaultModule.setLanguageModule(languageModule); defaultModule.setLanguageModule(languageModule);
context.setModules(modules); context.setModules(modules);
} }
Expand Down Expand Up @@ -91,7 +96,12 @@ public Package getCurrentPackage() {
return packageStack.peekLast(); return packageStack.peekLast();
} }


public Module getOrCreateModule(List<String> moduleName) { /**
* Get or create a module.
* version == null is considered equal to any version.
* Likewise a module with no version will match any version passed
*/
public Module getOrCreateModule(List<String> moduleName, String version) {
if (moduleName.size() == 0) { if (moduleName.size() == 0) {
return null; return null;
} }
Expand All @@ -100,24 +110,31 @@ public Module getOrCreateModule(List<String> moduleName) {
for (Module current : moduleList) { for (Module current : moduleList) {
final List<String> names = current.getName(); final List<String> names = current.getName();
if ( names.size() == moduleName.size() if ( names.size() == moduleName.size()
&& moduleName.containsAll(names) ) { && moduleName.containsAll(names)
&& compareVersions(version, current.getVersion())) {
module = current; module = current;
break; break;
} }
} }
if (module == null) { if (module == null) {
module = createModule(moduleName); module = createModule(moduleName);
module.setVersion(version);
module.setLanguageModule(modules.getLanguageModule()); module.setLanguageModule(modules.getLanguageModule());
moduleList.add(module); moduleList.add(module);
} }
return module; return module;
} }


private boolean compareVersions(String version, String currentVersion) {
return currentVersion == null || version == null || currentVersion.equals(version);
}

public void visitModuleFile() { public void visitModuleFile() {
if ( currentModule == null ) { if ( currentModule == null ) {
final Package currentPkg = packageStack.peekLast(); final Package currentPkg = packageStack.peekLast();
final List<String> moduleName = currentPkg.getName(); final List<String> moduleName = currentPkg.getName();
currentModule = getOrCreateModule(moduleName); //we don't know the version at this stage, will be filled later
currentModule = getOrCreateModule(moduleName, null);
if ( currentModule != null ) { if ( currentModule != null ) {
currentModule.setAvailable(true); // TODO : not necessary anymore ? the phasedUnit will be added. And the buildModuleImport() currentModule.setAvailable(true); // TODO : not necessary anymore ? the phasedUnit will be added. And the buildModuleImport()
// function (which calls module.setAvailable()) will be called by the typeChecker // function (which calls module.setAvailable()) will be called by the typeChecker
Expand All @@ -126,7 +143,7 @@ public void visitModuleFile() {
bindPackageToModule(currentPkg, currentModule); bindPackageToModule(currentPkg, currentModule);
} }
else { else {
collectError(new ArrayList<String>(), "A module cannot be defined at the top level of the hierarchy"); addErrorToModule(new ArrayList<String>(), "A module cannot be defined at the top level of the hierarchy");
} }
} }
else { else {
Expand All @@ -135,20 +152,11 @@ public void visitModuleFile() {
.append( "' and '" ) .append( "' and '" )
.append( formatPath( packageStack.peekLast().getName() ) ) .append( formatPath( packageStack.peekLast().getName() ) )
.append("'"); .append("'");
collectError(currentModule.getName(), error.toString()); addErrorToModule(currentModule.getName(), error.toString());
collectError(packageStack.peekLast().getName(), error.toString()); addErrorToModule(packageStack.peekLast().getName(), error.toString());
} }
} }


private void collectError(List<String> moduleName, String error) {
Set<String> errors = topLevelErrorsPerModuleName.get(moduleName);
if (errors == null) {
errors = new HashSet<String>();
topLevelErrorsPerModuleName.put(moduleName, errors);
}
errors.add(error);
}

private void createPackageAndAddToModule(String path) { private void createPackageAndAddToModule(String path) {
Package pkg = new Package(); Package pkg = new Package();
final Package lastPkg = packageStack.peekLast(); final Package lastPkg = packageStack.peekLast();
Expand Down Expand Up @@ -186,33 +194,118 @@ private void bindPackageToModule(Package pkg, Module module) {
pkg.setModule(module); pkg.setModule(module);
} }


public void addModuleDependencyDefinition(Module module, Node definition) { public void addModuleDependencyDefinition(ModuleImport moduleImport, Node definition) {
Set<Node> moduleDepError = missingModuleDependencies.get(module); Set<Node> moduleDepDefinition = moduleImportToNode.get(moduleImport);
if (moduleDepError == null) { if (moduleDepDefinition == null) {
moduleDepError = new HashSet<Node>(); moduleDepDefinition = new HashSet<Node>();
missingModuleDependencies.put(module, moduleDepError); moduleImportToNode.put(moduleImport, moduleDepDefinition);
} }
moduleDepError.add(definition); moduleDepDefinition.add(definition);
} }


public void addMissingDependencyError(Module module, String error) { public void attachErrorToDependencyDeclaration(ModuleImport moduleImport, String error) {
Set<Node> moduleDepError = missingModuleDependencies.get(module); Set<Node> moduleDepError = moduleImportToNode.get(moduleImport);
if (moduleDepError != null) { if (moduleDepError != null) {
for ( Node definition : moduleDepError ) { for ( Node definition : moduleDepError ) {
definition.addError(error); definition.addError(error);
} }
} }
else { else {
System.err.println("This is a type checker bug, please report. \nExpecting to add missing dependency error on non present definition: " + error); //This probably can happen if the missing dependency is found deep in the dependency structure (ie the binary version of a module)
//TODO find the nearest src module that triggered the issue
System.err.println("This might be a type checker bug, please report. \nExpecting to add missing dependency error on non present definition: " + error);
}
}

//must be used *after* addLinkBetweenModuleAndNode has been set ie post ModuleVisitor visit
public void addErrorToModule(Module module, String error) {
Node node = moduleToNode.get(module);
if (node != null) {
node.addError(error);
}
else {
//might happen if the faulty module is a compiled module
System.err.println("This is a type checker bug, please report. " +
"\nExpecting to add error on non present module node: " + module.toString() + ". Error " + error);
} }
} }


public void addErrorsToModule(Module module, Node unit) { //only used if we really don't know the version
private void addErrorToModule(List<String> moduleName, String error) {
Set<String> errors = topLevelErrorsPerModuleName.get(moduleName);
if (errors == null) {
errors = new HashSet<String>();
topLevelErrorsPerModuleName.put(moduleName, errors);
}
errors.add(error);
}

public void addLinkBetweenModuleAndNode(Module module, Node unit) {
//keep link and display errors on modules where we don't know the version of
Set<String> errors = topLevelErrorsPerModuleName.get(module.getName()); Set<String> errors = topLevelErrorsPerModuleName.get(module.getName());
if (errors != null) { if (errors != null) {
for(String error : errors) { for(String error : errors) {
unit.addError(error); unit.addError(error);
} }
errors.clear();
}
moduleToNode.put(module,unit);
}

public ModuleImport findImport(Module owner, Module dependency) {
for (ModuleImport modImprt : owner.getImports()) {
if (equalsForModules(modImprt.getModule(), dependency, true)) return modImprt;
} }
return null;
}

public boolean equalsForModules(Module left, Module right, boolean exactVersionMatch) {
if (left == right) return true;
List<String> leftName = left.getName();
List<String> rightName = right.getName();
if (leftName.size() != rightName.size()) return false;
for(int index = 0 ; index < leftName.size(); index++) {
if (!leftName.get(index).equals(rightName.get(index))) return false;
}
if (exactVersionMatch && left.getVersion()!=right.getVersion()) return false;
return true;
}

public Module findModule(Module module, List<Module> listOfModules, boolean exactVersionMatch) {
for(Module current : listOfModules) {
if (equalsForModules(module, current, exactVersionMatch)) return current;
}
return null;
}

public Module findLoadedModule(String moduleName, String searchedVersion) {
return findLoadedModule(moduleName, searchedVersion, modules);
}

public Module findLoadedModule(String moduleName, String searchedVersion, Modules modules) {
for(Module module : modules.getListOfModules()){
if(module.getNameAsString().equals(moduleName)) {
if (searchedVersion != null && searchedVersion.equals(module.getVersion())){
return module;
}
}
}
return null;
}

public void resolveModule(Module module, VirtualFile artifact, List<PhasedUnits> phasedUnitsOfDependencies) {
PhasedUnits modulePhasedUnit = new PhasedUnits(context);
phasedUnitsOfDependencies.add(modulePhasedUnit);
modulePhasedUnit.parseUnit(artifact);
//populate module.getDependencies()
modulePhasedUnit.visitModules();
}

public Iterable<String> getSearchedArtifactExtensions() {
return Arrays.asList("src");
}

public static List<String> splitModuleName(String moduleName) {
return Arrays.asList(moduleName.split("[\\.]"));
} }
} }

0 comments on commit 62ddc83

Please sign in to comment.