diff --git a/.github/workflows/populate-deps.yml b/.github/workflows/populate-deps.yml index 38cdcaab8c2..a265714a9c1 100644 --- a/.github/workflows/populate-deps.yml +++ b/.github/workflows/populate-deps.yml @@ -1,40 +1,40 @@ -name: Populate dependencies - -on: - push: - branches: [ master ] - workflow_dispatch: - -permissions: - contents: write - -env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - VCPKG_FEATURE_FLAGS: dependencygraph - -jobs: - build: - - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v3 - with: - submodules: 'recursive' - - - name: Checkout vcpkg - run: | - git clone https://github.com/Microsoft/vcpkg.git - cd vcpkg - git checkout 56954f1db97f38635782d5ad7cdfd45d2731c854 - - - name: Bootstrap vcpkg - working-directory: vcpkg - run: ./bootstrap-vcpkg.sh - - # This will execute a dry-run, meaning that libraries will not be built and - # installed, but they will still be reported to the GitHub dependency graph. - # This step assumes `vcpkg` has been bootstrapped (run `./vcpkg/bootstrap-vcpkg`) - - name: Run vcpkg - run: ${{ github.workspace }}/vcpkg/vcpkg install --dry-run --debug - +name: Populate dependencies + +on: + push: + branches: [ master ] + workflow_dispatch: + +permissions: + contents: write + +env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + VCPKG_FEATURE_FLAGS: dependencygraph + +jobs: + build: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + with: + submodules: 'recursive' + + - name: Checkout vcpkg + run: | + git clone https://github.com/Microsoft/vcpkg.git + cd vcpkg + git checkout 56954f1db97f38635782d5ad7cdfd45d2731c854 + + - name: Bootstrap vcpkg + working-directory: vcpkg + run: ./bootstrap-vcpkg.sh + + # This will execute a dry-run, meaning that libraries will not be built and + # installed, but they will still be reported to the GitHub dependency graph. + # This step assumes `vcpkg` has been bootstrapped (run `./vcpkg/bootstrap-vcpkg`) + - name: Run vcpkg + run: ${{ github.workspace }}/vcpkg/vcpkg install --dry-run --debug + diff --git a/src/FunctorOps.cpp b/src/FunctorOps.cpp index 178dcd89782..394357b5724 100644 --- a/src/FunctorOps.cpp +++ b/src/FunctorOps.cpp @@ -48,6 +48,7 @@ char const* functorOpNameLegacy(FunctorOp op) { /** Binary Functor Operators */ case FunctorOp::ADD: case FunctorOp::FADD: + case FunctorOp::SSADD: case FunctorOp::UADD: return "+"; case FunctorOp::SUB: case FunctorOp::USUB: @@ -223,6 +224,9 @@ const std::vector FUNCTOR_INTRINSICS = { VARIADIC(CAT, Symbol), OP_1(STRLEN, Symbol, Signed), OP_3(SUBSTR, Symbol, Signed, Signed, Symbol, false), + + {functorOpNameSymbol(FOp::SSADD), {TAttr::Symbol, TAttr::Symbol}, TAttr::Symbol, FOp::SSADD, false, + false}, }; template diff --git a/src/FunctorOps.h b/src/FunctorOps.h index 2ad98950a99..6a831715ced 100644 --- a/src/FunctorOps.h +++ b/src/FunctorOps.h @@ -101,6 +101,7 @@ enum class FunctorOp { FMIN, // min of two floats SMAX, // max of two symbols SMIN, // min of two symbols + SSADD, // string-string concatenation // Produces values within a numeric range. Format is `range(bgn, endExcl, step = 1)`. // e.g. `range(0, 5)` produces the sequence `0, 1, 2, 3, 4`. diff --git a/src/interpreter/Engine.cpp b/src/interpreter/Engine.cpp index 69c6b09dcae..521f7f9fc8e 100644 --- a/src/interpreter/Engine.cpp +++ b/src/interpreter/Engine.cpp @@ -784,6 +784,14 @@ RamDomain Engine::execute(const Node* node, Context& ctxt) { case FunctorOp::URANGE: case FunctorOp::FRANGE: fatal("ICE: functor `%s` must map onto `NestedIntrinsicOperator`", cur.getOperator()); + + case FunctorOp::SSADD: { + auto sleft = execute(shadow.getChild(0), ctxt); + auto sright = execute(shadow.getChild(1), ctxt); + const std::string& strleft = getSymbolTable().decode(sleft); + const std::string& strright = getSymbolTable().decode(sright); + return getSymbolTable().encode(strleft + strright); + } } {UNREACHABLE_BAD_CASE_ANALYSIS} diff --git a/src/synthesiser/Synthesiser.cpp b/src/synthesiser/Synthesiser.cpp index fdc6c254f39..44bf3f2977a 100644 --- a/src/synthesiser/Synthesiser.cpp +++ b/src/synthesiser/Synthesiser.cpp @@ -1864,7 +1864,7 @@ void Synthesiser::emitCode(std::ostream& out, const Statement& stmt) { // strings case BinaryConstraintOp::MATCH: { - if (const StringConstant* str = dynamic_cast(&rel.getLHS()); str) { + if (const StringConstant* str = as(&rel.getLHS()); str) { const auto& regex = synthesiser.compileRegex(str->getConstant()); if (regex) { out << "std::regex_match(symTable.decode("; @@ -1884,7 +1884,7 @@ void Synthesiser::emitCode(std::ostream& out, const Statement& stmt) { break; } case BinaryConstraintOp::NOT_MATCH: { - if (const StringConstant* str = dynamic_cast(&rel.getLHS()); str) { + if (const StringConstant* str = as(&rel.getLHS()); str) { const auto& regex = synthesiser.compileRegex(str->getConstant()); if (regex) { out << "!std::regex_match(symTable.decode("; @@ -2313,6 +2313,35 @@ void Synthesiser::emitCode(std::ostream& out, const Statement& stmt) { case FunctorOp::URANGE: case FunctorOp::FRANGE: fatal("ICE: functor `%s` must map onto `NestedIntrinsicOperator`", op.getOperator()); + + case FunctorOp::SSADD: { + const StringConstant* lstr = as(args[0]); + const StringConstant* rstr = as(args[1]); + if (lstr && rstr) { + out << "RamSigned(" + << synthesiser.convertSymbol2Idx(lstr->getConstant() + rstr->getConstant()) + << ")"; + } else { + out << "symTable.encode("; + if (lstr) { + out << "R\"_(" << lstr->getConstant() << ")_\""; + } else { + out << "symTable.decode("; + dispatch(*args[0], out); + out << ")"; + } + out << " + "; + if (rstr) { + out << "R\"_(" << rstr->getConstant() << ")_\""; + } else { + out << "symTable.decode("; + dispatch(*args[1], out); + out << ")"; + } + out << ")"; + } + break; + } } PRINT_END_COMMENT(out); diff --git a/tests/evaluation/CMakeLists.txt b/tests/evaluation/CMakeLists.txt index b55517a4d05..63aa0b5a078 100644 --- a/tests/evaluation/CMakeLists.txt +++ b/tests/evaluation/CMakeLists.txt @@ -161,6 +161,7 @@ positive_test(subtype2) positive_test(subtype) positive_test(sum-aggregate) positive_test(sum-aggregate2) +positive_test(symbol_operations) positive_test(term) positive_test(unpacking) positive_test(unsigned_operations) diff --git a/tests/evaluation/symbol_operations/Add.csv b/tests/evaluation/symbol_operations/Add.csv new file mode 100644 index 00000000000..3c250ab4c18 --- /dev/null +++ b/tests/evaluation/symbol_operations/Add.csv @@ -0,0 +1,9 @@ +pre--post +pre-(a) +pre-(b) +(a)-post +(b)-post +(b)(a)(a) +(a)(b)(b) +one:1, pi:3.140000 + diff --git a/tests/evaluation/symbol_operations/symbol_operations.dl b/tests/evaluation/symbol_operations/symbol_operations.dl new file mode 100644 index 00000000000..345dd7ddf01 --- /dev/null +++ b/tests/evaluation/symbol_operations/symbol_operations.dl @@ -0,0 +1,23 @@ +// Souffle - A Datalog Compiler +// Copyright (c) 2023, The Souffle Developers. All rights reserved +// Licensed under the Universal Permissive License v 1.0 as shown at: +// - https://opensource.org/licenses/UPL +// - /licenses/SOUFFLE-UPL.txt + +.decl Add(s:symbol) +Add("pre-" + "-post"). +Add("pre-" + s) :- some_symbol(s). +Add(s + "-post") :- some_symbol(s). +Add(s1 + s2 + s3) :- + some_symbol(s1), + some_symbol(s2), + some_symbol(s3), + s1 != s2, + s1 != s3. +Add("one:" + to_string(1) + ", pi:" + to_string(3.14) + "\n"). + +.decl some_symbol(s:symbol) +some_symbol("(a)"). +some_symbol("(b)"). + +.output Add() diff --git a/tests/evaluation/symbol_operations/symbol_operations.err b/tests/evaluation/symbol_operations/symbol_operations.err new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/evaluation/symbol_operations/symbol_operations.out b/tests/evaluation/symbol_operations/symbol_operations.out new file mode 100644 index 00000000000..e69de29bb2d