package org.zwobble.hobgoblin.compiler; import org.zwobble.hobgoblin.compiler.ast.untyped.UntypedNamespaceNode; import org.zwobble.hobgoblin.compiler.builtins.NativeTypes; import org.zwobble.hobgoblin.compiler.config.ProjectConfig; import org.zwobble.hobgoblin.compiler.parser.Parser; import org.zwobble.hobgoblin.compiler.typechecker.TypeChecker; import org.zwobble.hobgoblin.compiler.typechecker.TypeCheckerGlobalContext; import org.zwobble.hobgoblin.compiler.types.NamespaceName; import org.zwobble.sourcetext.SourceText; import java.io.IOException; import java.nio.charset.StandardCharsets; import java.nio.file.FileVisitResult; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.SimpleFileVisitor; import java.nio.file.attribute.BasicFileAttributes; import java.util.ArrayList; import java.util.List; public class HobgoblinCompiler { public static final String FILE_NAME_EXTENSION = ".hob"; private HobgoblinCompiler() { } public static void compile(Path projectRoot) throws IOException { var config = ProjectConfig.read(projectRoot); var generators = config.createGenerators(); var sourceDirectory = projectRoot.resolve("src"); var sourceFiles = collectSourceFiles(sourceDirectory); var untypedNamespaceNodes = new ArrayList(); for (var sourceFile : sourceFiles) { var namespaceName = sourceFileNamespaceName(sourceDirectory, sourceFile); var sourceContents = Files.readString(sourceFile, StandardCharsets.UTF_8); var sourceText = SourceText.fromString(sourceFile.toString(), sourceContents); var untypedNamespaceNode = Parser.parseNamespace(sourceText, namespaceName); untypedNamespaceNodes.add(untypedNamespaceNode); } var typeCheckerContext = TypeCheckerGlobalContext.initial(); typeCheckerContext.addNativeType(NativeTypes.BOOL); typeCheckerContext.addNativeType(NativeTypes.FLOAT_64); typeCheckerContext.addNativeType(NativeTypes.INT_8); typeCheckerContext.addNativeType(NativeTypes.INT_32); typeCheckerContext.addNativeType(NativeTypes.INT_64); typeCheckerContext.addNativeType(NativeTypes.STRING); typeCheckerContext.addNativeTypeConstructor(NativeTypes.BOX); typeCheckerContext.addNativeTypeConstructor(NativeTypes.LIST); typeCheckerContext.addNativeTypeConstructor(NativeTypes.OPTION); typeCheckerContext.addNativeTypeConstructor(NativeTypes.SHARED); var typedNamespaceNodes = TypeChecker.typeCheckNamespaces(untypedNamespaceNodes, typeCheckerContext); var typesInfo = typeCheckerContext.toTypesInfo(); for (var generator : generators) { generator.generate(typedNamespaceNodes, typesInfo); } } static NamespaceName sourceFileNamespaceName(Path sourceDirectory, Path sourceFilePath) { var relativePath = sourceDirectory.relativize(sourceFilePath); var parts = new ArrayList(); for (var i = 0; i < relativePath.getNameCount() - 1; i++) { parts.add(relativePath.getName(i).toString()); } var fileName = relativePath.getName(relativePath.getNameCount() - 1).toString(); var lastPart = fileName.substring(0, fileName.length() - FILE_NAME_EXTENSION.length()); parts.add(lastPart); return new NamespaceName(parts); } private static List collectSourceFiles( Path sourceRoot ) throws IOException { var sourceFiles = new ArrayList(); Files.walkFileTree(sourceRoot, new SimpleFileVisitor() { @Override public FileVisitResult visitFile( Path file, BasicFileAttributes attrs ) { if (file.toString().endsWith(FILE_NAME_EXTENSION)) { sourceFiles.add(file); } return FileVisitResult.CONTINUE; } @Override public FileVisitResult postVisitDirectory( Path dir, IOException exc ) { return FileVisitResult.CONTINUE; } }); sourceFiles.sort(null); return sourceFiles; } }