diff options
Diffstat (limited to 'tools')
3 files changed, 734 insertions, 73 deletions
diff --git a/tools/slang-capability-generator/capability-generator-main.cpp b/tools/slang-capability-generator/capability-generator-main.cpp new file mode 100644 index 000000000..79582a8c5 --- /dev/null +++ b/tools/slang-capability-generator/capability-generator-main.cpp @@ -0,0 +1,674 @@ +// capabilities-generator-main.cpp + +#include <stdio.h> +#include "../../source/compiler-core/slang-lexer.h" +#include "../../source/compiler-core/slang-perfect-hash-codegen.h" +#include "../../source/core/slang-io.h" +#include "../../source/core/slang-secure-crt.h" +#include "../../source/core/slang-string-util.h" +#include "../../source/core/slang-file-system.h" + +using namespace Slang; + +namespace Diagnostics +{ +#define DIAGNOSTIC(id, severity, name, messageFormat) const DiagnosticInfo name = { id, Severity::severity, #name, messageFormat }; +#include "slang-capability-diagnostic-defs.h" +#undef DIAGNOSTIC +} + +enum class CapabilityFlavor +{ + Normal, + Abstract, + Alias +}; + +struct CapabilityDef; + +struct CapabilityConjunctionExpr +{ + List<CapabilityDef*> atoms; +}; + +struct CapabilityDisjunctionExpr +{ + List<CapabilityConjunctionExpr> conjunctions; +}; + +struct SerializedArrayView +{ + Index first; + Index count; +}; + +struct CapabilityDef : public RefObject +{ + Index enumValue; + String name; + CapabilityDisjunctionExpr expr; + CapabilityFlavor flavor; + int rank; + List<List<CapabilityDef*>> canonicalRepresentation; + SerializedArrayView serializedCanonicalRepresentation; + + CapabilityDef* getAbstractBase() + { + if (flavor != CapabilityFlavor::Normal) + return nullptr; + if (expr.conjunctions.getCount() != 1) + return nullptr; + if (expr.conjunctions[0].atoms.getCount() == 0) + return nullptr; + if (expr.conjunctions[0].atoms[0]->flavor != CapabilityFlavor::Abstract) + return nullptr; + return expr.conjunctions[0].atoms[0]; + } +}; + +struct CapabilityDefParser +{ + CapabilityDefParser(Lexer* lexer, DiagnosticSink* sink) + : m_lexer(lexer) + , m_sink(sink) + { + } + + Lexer* m_lexer; + DiagnosticSink* m_sink; + + Dictionary<String, CapabilityDef*> m_mapNameToCapability; + List<RefPtr<CapabilityDef>> m_defs; + + TokenReader m_tokenReader; + + bool advanceIf(TokenType type) + { + if (m_tokenReader.peekTokenType() == type) + { + m_tokenReader.advanceToken(); + return true; + } + return false; + } + + SlangResult readToken(TokenType type, Token& nextToken) + { + nextToken = m_tokenReader.advanceToken(); + if (nextToken.type != type) + { + m_sink->diagnose(nextToken.loc, Diagnostics::unexpectedTokenExpectedTokenType, nextToken, type); + return SLANG_FAIL; + } + return SLANG_OK; + } + + SlangResult readToken(TokenType type) + { + Token nextToken; + return readToken(type, nextToken); + } + + SlangResult parseConjunction(CapabilityConjunctionExpr& expr) + { + for (;;) + { + Token nameToken; + SLANG_RETURN_ON_FAIL(readToken(TokenType::Identifier, nameToken)); + CapabilityDef* def = nullptr; + if (m_mapNameToCapability.tryGetValue(nameToken.getContent(), def)) + { + expr.atoms.add(def); + } + else + { + m_sink->diagnose(nameToken.loc, Diagnostics::undefinedIdentifier, nameToken); + return SLANG_FAIL; + } + if (!(advanceIf(TokenType::OpAnd) || advanceIf(TokenType::OpAdd))) + break; + } + return SLANG_OK; + } + + SlangResult parseExpr(CapabilityDisjunctionExpr& expr) + { + for (;;) + { + CapabilityConjunctionExpr conjunction; + SLANG_RETURN_ON_FAIL(parseConjunction(conjunction)); + expr.conjunctions.add(conjunction); + if (!advanceIf(TokenType::OpBitOr)) + break; + } + return SLANG_OK; + } + + SlangResult parseDefs() + { + auto tokens = m_lexer->lexAllSemanticTokens(); + m_tokenReader = TokenReader(tokens); + for (;;) + { + RefPtr<CapabilityDef> def = new CapabilityDef(); + def->flavor = CapabilityFlavor::Normal; + auto nextToken = m_tokenReader.advanceToken(); + if (nextToken.getContent() == "alias") + { + def->flavor = CapabilityFlavor::Alias; + } + else if (nextToken.getContent() == "abstract") + { + def->flavor = CapabilityFlavor::Abstract; + } + else if (nextToken.getContent() == "def") + { + def->flavor = CapabilityFlavor::Normal; + } + else if (nextToken.type == TokenType::EndOfFile) + { + break; + } + else + { + m_sink->diagnose(nextToken.loc, Diagnostics::unexpectedToken, nextToken); + return SLANG_FAIL; + } + + Token nameToken; + SLANG_RETURN_ON_FAIL(readToken(TokenType::Identifier, nameToken)); + def->name = nameToken.getContent(); + + if (def->flavor == CapabilityFlavor::Normal) + { + if (advanceIf(TokenType::Colon)) + { + SLANG_RETURN_ON_FAIL(parseExpr(def->expr)); + } + if (advanceIf(TokenType::OpAssign)) + { + Token rankToken; + SLANG_RETURN_ON_FAIL(readToken(TokenType::IntegerLiteral, rankToken)); + def->rank = stringToInt(rankToken.getContent()); + } + } + else if (def->flavor == CapabilityFlavor::Alias) + { + SLANG_RETURN_ON_FAIL(readToken(TokenType::OpAssign)); + SLANG_RETURN_ON_FAIL(parseExpr(def->expr)); + } + else if (def->flavor == CapabilityFlavor::Abstract) + { + if (advanceIf(TokenType::Colon)) + { + SLANG_RETURN_ON_FAIL(parseExpr(def->expr)); + } + } + SLANG_RETURN_ON_FAIL(readToken(TokenType::Semicolon)); + m_defs.add(def); + if (!m_mapNameToCapability.addIfNotExists(def->name, def)) + { + m_sink->diagnose(nextToken.loc, Diagnostics::redefinition, def->name); + return SLANG_FAIL; + } + } + return SLANG_OK; + } +}; + +struct CapabilityConjunction +{ + HashSet<CapabilityDef*> atoms; + bool implies(const CapabilityConjunction& c) const + { + for (auto& atom : c.atoms) + { + if (!atoms.contains(atom)) + return false; + } + return true; + } + + bool isImpossible() const + { + // Keep a map from an abstract base to the concrete atom defined in this conjunction that implements the base. + Dictionary<CapabilityDef*, CapabilityDef*> abstractKV; + + for (auto& atom : atoms) + { + auto abstractBase = atom->getAbstractBase(); + if (!abstractBase) + continue; + + // Have we already seen another concrete atom that implements the same abstract base of the current atom? + // If so, we have a conflict and the conjunction is impossible. + // + CapabilityDef* value = nullptr; + if (abstractKV.tryGetValue(abstractBase, value)) + { + if (value != atom) + return true; + } + else + { + abstractKV[abstractBase] = atom; + } + } + return false; + } +}; + +struct CapabilityDisjunction +{ + List<CapabilityConjunction> conjunctions; + + void addConjunction(const CapabilityConjunction& c) + { + if (c.isImpossible()) + return; + for (auto& conjunction : conjunctions) + { + if (c.implies(conjunction)) + return; + } + for (Index i = 0; i < conjunctions.getCount();) + { + if (conjunctions[i].implies(c)) + { + conjunctions.fastRemoveAt(i); + } + else + { + i++; + } + } + conjunctions.add(_Move(c)); + } + + CapabilityDisjunction joinWith(const CapabilityDisjunction& other) + { + if (conjunctions.getCount() == 0) + { + return other; + } + if (other.conjunctions.getCount() == 0) + { + return *this; + } + + CapabilityDisjunction result; + + for (auto& thisC : conjunctions) + { + for (auto& thatC : other.conjunctions) + { + CapabilityConjunction newC; + for (auto atom : thisC.atoms) + newC.atoms.add(atom); + for (auto atom : thatC.atoms) + newC.atoms.add(atom); + result.addConjunction(_Move(newC)); + } + } + return result; + } + + List<List<CapabilityDef*>> canonicalize() + { + List<List<CapabilityDef*>> result; + for (auto& c : conjunctions) + { + List<CapabilityDef*> atoms; + for (auto& atom : c.atoms) + atoms.add(atom); + atoms.sort([](CapabilityDef* c1, CapabilityDef* c2) {return c1->enumValue < c2->enumValue; }); + result.add(_Move(atoms)); + } + result.sort([](const List<CapabilityDef*>& c1, const List<CapabilityDef*>& c2) + { + for (Index i = 0; i < Math::Min(c1.getCount(), c2.getCount()); i++) + { + if (c1[i]->enumValue < c2[i]->enumValue) + return true; + else if (c1[i]->enumValue > c2[i]->enumValue) + return false; + } + return c1.getCount() < c2.getCount(); + }); + return result; + } +}; + +CapabilityDisjunction getCanonicalRepresentation(CapabilityDef* def) +{ + CapabilityDisjunction result; + for (auto& c : def->canonicalRepresentation) + { + CapabilityConjunction conj; + for (auto& atom : c) + conj.atoms.add(atom); + result.conjunctions.add(conj); + } + return result; +} + +CapabilityDisjunction evaluateConjunction(const List<CapabilityDef*>& atoms) +{ + CapabilityDisjunction result; + for (auto& def : atoms) + { + CapabilityDisjunction defCanonical = getCanonicalRepresentation(def); + result = result.joinWith(defCanonical); + } + return result; +} + +void calcCanonicalRepresentation(CapabilityDef* def, const List<CapabilityDef*>& mapEnumValueToDef) +{ + CapabilityDisjunction disjunction; + if (def->flavor == CapabilityFlavor::Normal) + { + CapabilityConjunction c; + c.atoms.add(def); + disjunction.conjunctions.add(c); + } + CapabilityDisjunction exprVal; + for (auto& c : def->expr.conjunctions) + { + CapabilityDisjunction evalD = evaluateConjunction(c.atoms); + for (auto& cc : evalD.conjunctions) + exprVal.addConjunction(cc); + } + disjunction = disjunction.joinWith(exprVal); + def->canonicalRepresentation = disjunction.canonicalize(); +} + +void calcCanonicalRepresentations(const List<RefPtr<CapabilityDef>>& defs, const List<CapabilityDef*>& mapEnumValueToDef) +{ + for (auto def : defs) + calcCanonicalRepresentation(def, mapEnumValueToDef); +} + +SlangResult generateDefinitions(const List<RefPtr<CapabilityDef>>& defs, StringBuilder& sbHeader, StringBuilder& sbCpp) +{ + sbHeader << "enum class CapabilityAtom\n{\n"; + sbHeader << " Invalid,\n"; + for (auto def : defs) + { + if (def->flavor == CapabilityFlavor::Normal) + { + sbHeader << " " << def->name << ",\n"; + } + } + sbHeader << " Count\n"; + sbHeader << "};\n"; + CapabilityDef* firstAbstractDef = nullptr; + CapabilityDef* firstAliasDef = nullptr; + sbHeader << "enum class CapabilityName\n{\n"; + sbHeader << " Invalid,\n"; + Index enumValueCounter = 1; + List<CapabilityDef*> mapEnumValueToDef; + mapEnumValueToDef.add(nullptr); // For Invalid. + for (auto def : defs) + { + if (def->flavor == CapabilityFlavor::Normal) + { + def->enumValue = enumValueCounter; + ++enumValueCounter; + mapEnumValueToDef.add(def); + sbHeader << " " << def->name << " = (int)CapabilityAtom::" << def->name << ",\n"; + } + } + for (auto def : defs) + { + if (def->flavor == CapabilityFlavor::Abstract) + { + if (firstAbstractDef == nullptr) + firstAbstractDef = def; + def->enumValue = enumValueCounter; + ++enumValueCounter; + mapEnumValueToDef.add(def); + sbHeader << " " << def->name << ",\n"; + } + } + for (auto def : defs) + { + if (def->flavor == CapabilityFlavor::Alias) + { + if (firstAliasDef == nullptr) + firstAliasDef = def; + def->enumValue = enumValueCounter; + ++enumValueCounter; + mapEnumValueToDef.add(def); + sbHeader << " " << def->name << ",\n"; + } + } + sbHeader << " Count\n"; + sbHeader << "};\n"; + + calcCanonicalRepresentations(defs, mapEnumValueToDef); + + List<String> capabiltiyNameArray; + List<SerializedArrayView> serializedCapabilityArrays; + + List<SerializedArrayView> serializedAtomDisjunctions; + auto serializeConjunction = [&](const List<CapabilityDef*>& capabilities) -> SerializedArrayView + { + // Do we already have a serialized capability array that is the same the one we are trying to serialize? + for (auto existingArray : serializedCapabilityArrays) + { + if (existingArray.count == capabilities.getCount()) + { + bool match = true; + for (Index i = 0; i < capabilities.getCount(); i++) + { + if (capabiltiyNameArray[existingArray.first+i] != capabilities[i]->name) + { + match = false; + break; + } + } + if (match) + return existingArray; + } + } + SerializedArrayView result; + result.first = capabiltiyNameArray.getCount(); + for (auto capability : capabilities) + { + capabiltiyNameArray.add(capability->name); + } + result.count = capabilities.getCount(); + serializedCapabilityArrays.add(result); + return result; + }; + auto serializeDisjunction = [&](const List<SerializedArrayView>& conjunctions) -> SerializedArrayView + { + SerializedArrayView result; + result.first = serializedAtomDisjunctions.getCount(); + for (auto c : conjunctions) + { + serializedAtomDisjunctions.add(c); + } + result.count = conjunctions.getCount(); + return result; + }; + for (auto& def : defs) + { + List<SerializedArrayView> conjunctions; + for (auto& c : def->canonicalRepresentation) + conjunctions.add(serializeConjunction(c)); + def->serializedCanonicalRepresentation = serializeDisjunction(conjunctions); + } + + sbCpp << "static CapabilityName kCapabilityArray[] = {\n"; + Index arrayIndex = 0; + sbCpp << " /* [0] @0: */ "; + for (Index i = 0; i < capabiltiyNameArray.getCount(); ++i) + { + sbCpp << " CapabilityName::" << capabiltiyNameArray[i] << ","; + if (i + 1 == serializedCapabilityArrays[arrayIndex].first + serializedCapabilityArrays[arrayIndex].count) + { + arrayIndex++; + if (arrayIndex == serializedCapabilityArrays.getCount()) + sbCpp << "\n"; + else + sbCpp << "\n /* [" << arrayIndex << "] @" << serializedCapabilityArrays[arrayIndex].first <<": */ "; + } + } + sbCpp << "};\n"; + sbCpp << "static ArrayView<CapabilityName> kCapabilityConjunctions[] = {\n"; + for (auto c : serializedAtomDisjunctions) + { + sbCpp << " { kCapabilityArray + " << c.first << ", " << c.count << " },\n"; + } + sbCpp << "};\n"; + + sbCpp << "static const CapabilityAtomInfo kCapabilityNameInfos[int(CapabilityName::Count)] = {\n"; + for (auto def : mapEnumValueToDef) + { + if (!def) + { + sbCpp << R"( { "Invalid", CapabilityNameFlavor::Concrete, CapabilityName::Invalid, 0, {nullptr, 0} },)" << "\n"; + continue; + } + + // name. + sbCpp << " { \"" << def->name << "\", "; + + // flavor. + switch (def->flavor) + { + case CapabilityFlavor::Normal: + sbCpp << "CapabilityNameFlavor::Concrete"; + break; + case CapabilityFlavor::Abstract: + sbCpp << "CapabilityNameFlavor::Abstract"; + break; + case CapabilityFlavor::Alias: + sbCpp << "CapabilityNameFlavor::Alias"; + break; + } + sbCpp << ", "; + + // abstract base. + auto abstractBase = def->getAbstractBase(); + if (abstractBase) + { + sbCpp << "CapabilityName::" << abstractBase->name; + } + else + { + sbCpp << "CapabilityName::Invalid"; + } + sbCpp << ", "; + + // canonnical representation. + sbCpp << def->rank << ", { kCapabilityConjunctions + " << def->serializedCanonicalRepresentation.first << ", " << def->serializedCanonicalRepresentation.count << "} },\n"; + } + + sbCpp << "};\n"; + return SLANG_OK; +} + + +SlangResult parseDefFile(DiagnosticSink* sink, String inputPath, List<RefPtr<CapabilityDef>>& outDefs) +{ + auto sourceManager = sink->getSourceManager(); + + String contents; + SLANG_RETURN_ON_FAIL(File::readAllText(inputPath, contents)); + PathInfo pathInfo = PathInfo::makeFromString(inputPath); + SourceFile* sourceFile = sourceManager->createSourceFileWithString(pathInfo, contents); + SourceView* sourceView = sourceManager->createSourceView(sourceFile, nullptr, SourceLoc()); + Lexer lexer; + NamePool namePool; + RootNamePool rootPool; + namePool.setRootNamePool(&rootPool); + lexer.initialize(sourceView, sink, &namePool, sourceManager->getMemoryArena()); + + CapabilityDefParser parser(&lexer, sink); + + SLANG_RETURN_ON_FAIL(parser.parseDefs()); + outDefs = _Move(parser.m_defs); + return SLANG_OK; +} + +void printDiagnostics(DiagnosticSink* sink) +{ + ComPtr<ISlangBlob> blob; + sink->getBlobIfNeeded(blob.writeRef()); + if (blob) + { + fprintf(stderr, "%s", (const char*)blob->getBufferPointer()); + } +} + +void writeIfChanged(String fileName, String content) +{ + if (File::exists(fileName)) + { + String existingContent; + File::readAllText(fileName, existingContent); + if (existingContent.getUnownedSlice().trim() == content.getUnownedSlice().trim()) + return; + } + File::writeAllText(fileName, content); +} + +int main(int argc, const char* const* argv) +{ + if (argc < 2) + { + fprintf( + stderr, + "Usage: %s\n", + argc >= 1 ? argv[0] : "slang-capabilities-generator"); + return 1; + } + String targetDir; + for (int i = 0; i < argc - 1; i++) + { + if (strcmp(argv[i], "--target-directory") == 0) + targetDir = argv[i + 1]; + } + + String inPath = argv[1]; + if (targetDir.getLength() == 0) + targetDir = Path::getParentDirectory(inPath); + + auto outCppPath = Path::combine(targetDir, "slang-generated-capability-defs-impl.h"); + auto outHeaderPath = Path::combine(targetDir, "slang-generated-capability-defs.h"); + auto outLookupPath = Path::combine(targetDir, "slang-lookup-capability-defs.cpp"); + SourceManager sourceManager; + sourceManager.initialize(nullptr, OSFileSystem::getExtSingleton()); + DiagnosticSink sink(&sourceManager, nullptr); + List<RefPtr<CapabilityDef>> defs; + if (SLANG_FAILED(parseDefFile(&sink, inPath, defs))) + { + printDiagnostics(&sink); + return 1; + } + + StringBuilder sbHeader, sbCpp; + if (SLANG_FAILED(generateDefinitions(defs, sbHeader, sbCpp))) + { + return 1; + } + + writeIfChanged(outHeaderPath, sbHeader.produceString()); + writeIfChanged(outCppPath, sbCpp.produceString()); + + List<String> opnames; + for (auto def : defs) + { + opnames.add(def->name); + } + + if (SLANG_FAILED(writePerfectHashLookupCppFile(outLookupPath, opnames, "CapabilityName", "CapabilityName::", "slang-capability.h", &sink))) + { + printDiagnostics(&sink); + return 1; + } + return 0; +} diff --git a/tools/slang-capability-generator/slang-capability-diagnostic-defs.h b/tools/slang-capability-generator/slang-capability-diagnostic-defs.h new file mode 100644 index 000000000..a9436cd9c --- /dev/null +++ b/tools/slang-capability-generator/slang-capability-diagnostic-defs.h @@ -0,0 +1,57 @@ +// + +// The file is meant to be included multiple times, to produce different +// pieces of declaration/definition code related to diagnostic messages +// +// Each diagnostic is declared here with: +// +// DIAGNOSTIC(id, severity, name, messageFormat) +// +// Where `id` is the unique diagnostic ID, `severity` is the default +// severity (from the `Severity` enum), `name` is a name used to refer +// to this diagnostic from code, and `messageFormat` is the default +// (non-localized) message for the diagnostic, with placeholders +// for any arguments. + +#ifndef DIAGNOSTIC +#error Need to #define DIAGNOSTIC(...) before including "DiagnosticDefs.h" +#define DIAGNOSTIC(id, severity, name, messageFormat) /* */ +#endif + +// +// -1 - Notes that decorate another diagnostic. +// + +DIAGNOSTIC(-1, Note, seeDefinitionOf, "see definition of '$0'") + +// +// 0xxxx - Command line and interaction with host platform APIs. +// + +DIAGNOSTIC( 1, Error, cannotOpenFile, "cannot open file '$0'.") +DIAGNOSTIC( 2, Error, cannotFindFile, "cannot find file '$0'.") +DIAGNOSTIC( 4, Error, cannotWriteOutputFile, "cannot write output file '$0'.") +DIAGNOSTIC( 5, Error, failedToLoadDynamicLibrary, "failed to load dynamic library '$0'") +DIAGNOSTIC( 6, Error, tooManyOutputPathsSpecified, "$0 output paths specified, but only $1 entry points given") + +// +// 2xxxx - Parsing +// + +DIAGNOSTIC(20003, Error, unexpectedToken, "unexpected $0") +DIAGNOSTIC(20001, Error, unexpectedTokenExpectedTokenType, "unexpected $0, expected $1") +DIAGNOSTIC(20001, Error, unexpectedTokenExpectedTokenName, "unexpected $0, expected '$1'") + +DIAGNOSTIC(0, Error, tokenNameExpectedButEOF, "\"$0\" expected but end of file encountered.") +DIAGNOSTIC(0, Error, tokenTypeExpectedButEOF, "$0 expected but end of file encountered.") +DIAGNOSTIC(20001, Error, tokenNameExpected, "\"$0\" expected") +DIAGNOSTIC(20001, Error, tokenNameExpectedButEOF2, "\"$0\" expected but end of file encountered.") +DIAGNOSTIC(20001, Error, tokenTypeExpected, "$0 expected") +DIAGNOSTIC(20001, Error, tokenTypeExpectedButEOF2, "$0 expected but end of file encountered.") +DIAGNOSTIC(20001, Error, typeNameExpectedBut, "unexpected $0, expected type name") +DIAGNOSTIC(20001, Error, typeNameExpectedButEOF, "type name expected but end of file encountered.") +DIAGNOSTIC(20001, Error, unexpectedEOF, " Unexpected end of file.") +DIAGNOSTIC(20002, Error, syntaxError, "syntax error.") +DIAGNOSTIC(20003, Error, undefinedIdentifier, "undefined identifier \"$0\".") +DIAGNOSTIC(20004, Error, redefinition, "capability redefinition: '$0'.") +#undef DIAGNOSTIC diff --git a/tools/slang-lookup-generator/lookup-generator-main.cpp b/tools/slang-lookup-generator/lookup-generator-main.cpp index a6f43c102..b99cf0e53 100644 --- a/tools/slang-lookup-generator/lookup-generator-main.cpp +++ b/tools/slang-lookup-generator/lookup-generator-main.cpp @@ -4,7 +4,7 @@ #include "../../source/compiler-core/slang-json-parser.h" #include "../../source/compiler-core/slang-json-value.h" #include "../../source/compiler-core/slang-lexer.h" -#include "../../source/compiler-core/slang-perfect-hash.h" +#include "../../source/compiler-core/slang-perfect-hash-codegen.h" #include "../../source/core/slang-io.h" #include "../../source/core/slang-secure-crt.h" #include "../../source/core/slang-string-util.h" @@ -69,46 +69,6 @@ static List<String> extractOpNames(UnownedStringSlice& error, const JSONValue& v return opnames; } -void writeHashFile( - const char* const outCppPath, - const char* valueType, - const char* valuePrefix, - const List<String> includes, - const HashParams& hashParams, - const List<String> values) -{ - StringBuilder sb; - StringWriter writer(&sb, WriterFlags(0)); - WriterHelper w(&writer); - - w.print("// Hash function for %s\n", valueType); - w.print("//\n"); - w.print("// This file was thoughtfully generated by a machine,\n"); - w.print("// don't even think about modifying it yourself!\n"); - w.print("//\n"); - w.print("\n"); - for (const auto& i : includes) - { - w.print("#include \"%s\"\n", i.getBuffer()); - } - w.print("\n"); - w.print("\n"); - w.print("namespace Slang\n"); - w.print("{\n"); - w.print("\n"); - - w.put(perfectHashToEmbeddableCpp( - hashParams, - UnownedStringSlice(valueType), - (String("lookup") + valueType).getUnownedSlice(), - values - ).getBuffer()); - - w.print("}\n"); - - File::writeAllTextIfChanged(outCppPath, sb.getUnownedSlice()); -} - int main(int argc, const char* const* argv) { using namespace Slang; @@ -166,38 +126,8 @@ int main(int argc, const char* const* argv) opnames.add(w); } - HashParams hashParams; - auto r = minimalPerfectHash(opnames, hashParams); - switch (r) - { - case HashFindResult::UnavoidableHashCollision: - { - sink.diagnoseRaw( - Severity::Error, - "Unable to find a non-overlapping hash function.\n" - "The hash function probably has a unavoidable " - "collision for some input words\n"); - return 1; - } - case HashFindResult::NonUniqueKeys: - { - sink.diagnoseRaw(Severity::Error, "Input word list has duplicates\n"); - return 1; - } - case HashFindResult::Success:; - } - - List<String> values; - values.reserve (hashParams.destTable.getCount()); - for(const auto& v : hashParams.destTable) - values.add(enumerantPrefix + v); - writeHashFile( - outCppPath, - enumName, - enumerantPrefix, - { "../core/slang-common.h", "../core/slang-string.h", enumHeader }, - hashParams, - values); + if (SLANG_FAILED(writePerfectHashLookupCppFile(outCppPath, opnames, enumName, enumerantPrefix, enumHeader, &sink))) + return -1; return 0; } |
