├── .clang-format ├── .gitattributes ├── .github ├── actions │ └── build-manylinux │ │ ├── Dockerfile │ │ ├── action.yml │ │ └── entrypoint.sh └── workflows │ └── ci.yml ├── .gitignore ├── CMakeLists.txt ├── CODEOWNERS ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── compiler ├── dsl │ ├── dsl.h │ ├── plugins.cpp │ └── plugins.h ├── parser │ ├── ast.h │ ├── ast │ │ ├── expr.cpp │ │ ├── expr.h │ │ ├── stmt.cpp │ │ ├── stmt.h │ │ ├── types.cpp │ │ └── types.h │ ├── cache.cpp │ ├── cache.h │ ├── common.cpp │ ├── common.h │ ├── ctx.h │ ├── parser.cpp │ ├── parser.h │ ├── peg │ │ ├── grammar.peg │ │ ├── openmp.peg │ │ ├── peg.cpp │ │ ├── peg.h │ │ └── rules.h │ └── visitors │ │ ├── doc │ │ ├── doc.cpp │ │ └── doc.h │ │ ├── format │ │ ├── format.cpp │ │ └── format.h │ │ ├── simplify │ │ ├── simplify.cpp │ │ ├── simplify.h │ │ ├── simplify_ctx.cpp │ │ ├── simplify_ctx.h │ │ ├── simplify_expr.cpp │ │ └── simplify_stmt.cpp │ │ ├── translate │ │ ├── translate.cpp │ │ ├── translate.h │ │ ├── translate_ctx.cpp │ │ └── translate_ctx.h │ │ ├── typecheck │ │ ├── typecheck.cpp │ │ ├── typecheck.h │ │ ├── typecheck_ctx.cpp │ │ ├── typecheck_ctx.h │ │ ├── typecheck_expr.cpp │ │ ├── typecheck_infer.cpp │ │ └── typecheck_stmt.cpp │ │ ├── visitor.cpp │ │ └── visitor.h ├── seq │ ├── pipeline.cpp │ ├── pipeline.h │ ├── revcomp.cpp │ ├── revcomp.h │ ├── seq.cpp │ └── seq.h ├── sir │ ├── analyze │ │ ├── analysis.cpp │ │ ├── analysis.h │ │ ├── dataflow │ │ │ ├── cfg.cpp │ │ │ ├── cfg.h │ │ │ ├── dominator.cpp │ │ │ ├── dominator.h │ │ │ ├── reaching.cpp │ │ │ └── reaching.h │ │ └── module │ │ │ ├── global_vars.cpp │ │ │ ├── global_vars.h │ │ │ ├── side_effect.cpp │ │ │ └── side_effect.h │ ├── attribute.cpp │ ├── attribute.h │ ├── base.cpp │ ├── base.h │ ├── const.cpp │ ├── const.h │ ├── dsl │ │ ├── codegen.h │ │ ├── nodes.cpp │ │ └── nodes.h │ ├── flow.cpp │ ├── flow.h │ ├── func.cpp │ ├── func.h │ ├── instr.cpp │ ├── instr.h │ ├── llvm │ │ ├── coro │ │ │ ├── CoroCleanup.cpp │ │ │ ├── CoroCleanup.h │ │ │ ├── CoroEarly.cpp │ │ │ ├── CoroEarly.h │ │ │ ├── CoroElide.cpp │ │ │ ├── CoroElide.h │ │ │ ├── CoroFrame.cpp │ │ │ ├── CoroInstr.h │ │ │ ├── CoroInternal.h │ │ │ ├── CoroSplit.cpp │ │ │ ├── CoroSplit.h │ │ │ ├── Coroutines.cpp │ │ │ └── Coroutines.h │ │ ├── llvisitor.cpp │ │ ├── llvisitor.h │ │ └── llvm.h │ ├── module.cpp │ ├── module.h │ ├── sir.h │ ├── transform │ │ ├── cleanup │ │ │ ├── canonical.cpp │ │ │ ├── canonical.h │ │ │ ├── dead_code.cpp │ │ │ ├── dead_code.h │ │ │ ├── global_demote.cpp │ │ │ ├── global_demote.h │ │ │ ├── replacer.cpp │ │ │ └── replacer.h │ │ ├── folding │ │ │ ├── const_fold.cpp │ │ │ ├── const_fold.h │ │ │ ├── const_prop.cpp │ │ │ ├── const_prop.h │ │ │ ├── folding.cpp │ │ │ ├── folding.h │ │ │ └── rule.h │ │ ├── lowering │ │ │ ├── imperative.cpp │ │ │ ├── imperative.h │ │ │ ├── pipeline.cpp │ │ │ └── pipeline.h │ │ ├── manager.cpp │ │ ├── manager.h │ │ ├── parallel │ │ │ ├── openmp.cpp │ │ │ ├── openmp.h │ │ │ ├── schedule.cpp │ │ │ └── schedule.h │ │ ├── pass.cpp │ │ ├── pass.h │ │ ├── pythonic │ │ │ ├── dict.cpp │ │ │ ├── dict.h │ │ │ ├── io.cpp │ │ │ ├── io.h │ │ │ ├── str.cpp │ │ │ └── str.h │ │ └── rewrite.h │ ├── types │ │ ├── types.cpp │ │ └── types.h │ ├── util │ │ ├── cloning.cpp │ │ ├── cloning.h │ │ ├── context.h │ │ ├── format.cpp │ │ ├── format.h │ │ ├── inlining.cpp │ │ ├── inlining.h │ │ ├── irtools.cpp │ │ ├── irtools.h │ │ ├── iterators.h │ │ ├── matching.cpp │ │ ├── matching.h │ │ ├── operator.h │ │ ├── outlining.cpp │ │ ├── outlining.h │ │ ├── packs.h │ │ ├── visitor.cpp │ │ └── visitor.h │ ├── value.cpp │ ├── value.h │ ├── var.cpp │ └── var.h └── util │ ├── common.cpp │ ├── common.h │ ├── fmt │ ├── chrono.h │ ├── color.h │ ├── compile.h │ ├── core.h │ ├── format-inl.h │ ├── format.cpp │ ├── format.h │ ├── locale.h │ ├── ostream.h │ ├── posix.h │ ├── printf.h │ └── ranges.h │ ├── peg2cpp.cpp │ └── peglib.h ├── docs ├── doxygen │ ├── Doxyfile │ ├── html │ │ └── .gitignore │ └── xml │ │ └── .gitignore ├── images │ └── prefetch.png ├── sphinx │ ├── Makefile │ ├── _ext │ │ └── seq.py │ ├── _static │ │ └── .gitkeep │ ├── _templates │ │ └── .gitkeep │ ├── build.rst │ ├── conf.py │ ├── cookbook.rst │ ├── docgen.py │ ├── embed.rst │ ├── index.rst │ ├── intro.rst │ ├── logo.png │ ├── make.bat │ ├── parallel.rst │ ├── python.rst │ ├── seqlex.py │ └── tutorial │ │ ├── index.rst │ │ ├── primer.rst │ │ ├── setup.rst │ │ ├── tutorial.rst │ │ └── workshop.rst └── workshop │ ├── section1.seq │ ├── section2.seq │ ├── section3.seq │ ├── section4.seq │ ├── section5.seq │ └── section6.seq ├── runtime ├── exc.cpp ├── lib.cpp ├── lib.h ├── main.cpp └── sw │ ├── intersw.cpp │ ├── intersw.h │ ├── ksw2.h │ ├── ksw2_extd2_sse.cpp │ ├── ksw2_exts2_sse.cpp │ ├── ksw2_extz2_sse.cpp │ └── ksw2_gg2_sse.cpp ├── scripts ├── backtrace-config.h.cmake ├── backtrace-support.h.cmake ├── backtrace-supported.h.cmake ├── deps.cmake ├── deps.sh ├── htslib-config.h.cmake └── install.sh ├── stdlib ├── algorithms │ ├── heapsort.seq │ ├── insertionsort.seq │ ├── pdqsort.seq │ ├── qsort.seq │ ├── strings.seq │ └── timsort.seq ├── bio │ ├── __init__.seq │ ├── align.seq │ ├── bam.seq │ ├── bed.seq │ ├── block.seq │ ├── builtin.seq │ ├── bwa.seq │ ├── bwt.seq │ ├── c_htslib.seq │ ├── fai.seq │ ├── fasta.seq │ ├── fastq.seq │ ├── fmindex.seq │ ├── intervals.seq │ ├── iter.seq │ ├── kmer.seq │ ├── locus.seq │ ├── prefetch.seq │ ├── pseq.seq │ ├── seq.seq │ ├── types.seq │ └── vcf.seq ├── bisect.seq ├── collections.seq ├── functools.seq ├── getopt.seq ├── gzip.seq ├── heapq.seq ├── internal │ ├── __init__.seq │ ├── __init_test__.seq │ ├── attributes.seq │ ├── box.seq │ ├── builtin.seq │ ├── c_stubs.seq │ ├── dlopen.seq │ ├── file.seq │ ├── gc.seq │ ├── internal.seq │ ├── khash.seq │ ├── python.seq │ ├── sort.seq │ ├── str.seq │ └── types │ │ ├── array.seq │ │ ├── bool.seq │ │ ├── byte.seq │ │ ├── collections │ │ ├── dict.seq │ │ ├── list.seq │ │ └── set.seq │ │ ├── error.seq │ │ ├── float.seq │ │ ├── generator.seq │ │ ├── int.seq │ │ ├── intn.seq │ │ ├── optional.seq │ │ ├── ptr.seq │ │ ├── range.seq │ │ ├── slice.seq │ │ └── str.seq ├── itertools.seq ├── math.seq ├── openmp.seq ├── operator.seq ├── os │ ├── __init__.seq │ └── path.seq ├── pickle.seq ├── python.seq ├── random.seq ├── sortedlist.seq ├── statistics.seq ├── string.seq ├── sys.seq ├── threading.seq └── time.seq ├── test ├── CMakeLists.txt.in ├── apps │ ├── avid │ │ └── avid.seq │ ├── bwa │ │ ├── example.seq │ │ ├── fastmap.seq │ │ └── fastmap_build.seq │ ├── cora │ │ ├── hom_exact.seq │ │ ├── hom_inexact.seq │ │ └── util.seq │ ├── gatk-splitncigar │ │ └── gatk-split.seq │ ├── minimap2 │ │ ├── sw.seq │ │ └── sw_simple.seq │ ├── mrsfast │ │ ├── exact.seq │ │ └── mrsfast.seq │ ├── snap │ │ ├── genomeindex.seq │ │ ├── hashtable.seq │ │ └── test.seq │ └── umi-tools │ │ └── whitelist.seq ├── bench │ ├── bedcov.seq │ ├── fastx.seq │ ├── fmindex.seq │ ├── fqcnt.seq │ ├── hamming.seq │ ├── hash.seq │ ├── kmercnt.seq │ ├── match.seq │ ├── rc.seq │ ├── rc_kmer.seq │ ├── rc_pipeline.seq │ └── sw.seq ├── core │ ├── align.seq │ ├── arguments.seq │ ├── arithmetic.seq │ ├── big.seq │ ├── bltin.seq │ ├── bwtsa.seq │ ├── containers.seq │ ├── empty.seq │ ├── exceptions.seq │ ├── exit.seq │ ├── formats.seq │ ├── generators.seq │ ├── generics.seq │ ├── helloworld.seq │ ├── kmers.seq │ ├── llvmops.seq │ ├── match.seq │ ├── parser.seq │ ├── proteins.seq │ ├── range.seq │ ├── serialization.seq │ ├── sort.seq │ └── trees.seq ├── data │ ├── MT-human.fa │ ├── MT-human.fa.fai │ ├── MT-orang.fa │ ├── MT-orang.fa.fai │ ├── invalid │ │ ├── invalid_fai_float.fai │ │ ├── invalid_fai_missing_col.fai │ │ ├── invalid_with_header.bed │ │ ├── seqs_bad_base.fasta │ │ ├── seqs_bad_base.fasta.fai │ │ ├── seqs_bad_base.fastq │ │ ├── seqs_bad_base.txt │ │ ├── seqs_bad_name.fastq │ │ ├── seqs_bad_qual.fastq │ │ └── seqs_bad_qual_len.fastq │ ├── sample_fasta_for_fai.fasta │ ├── sample_fasta_for_fai.fasta.fai │ ├── seqs.fasta │ ├── seqs.fasta.fai │ ├── seqs.fasta.gz │ ├── seqs.fastq │ ├── seqs.fastq.gz │ ├── seqs.txt │ ├── seqs.txt.gz │ ├── seqs2.fasta │ ├── seqs2.fasta.fai │ ├── toy.bam │ ├── toy.bam.bai │ ├── toy.bed │ ├── toy.cram │ ├── toy.cram.crai │ ├── toy.sam │ ├── toy.vcf │ ├── valid_fai.fai │ ├── valid_with_header.bed │ └── valid_without_header.bed ├── main.cpp ├── parser │ ├── a │ │ ├── __init__.seq │ │ └── b │ │ │ ├── __init__.seq │ │ │ ├── rec1.seq │ │ │ ├── rec1_err.seq │ │ │ ├── rec2.seq │ │ │ └── rec2_err.seq │ ├── llvm.seq │ ├── simplify_expr.seq │ ├── simplify_stmt.seq │ ├── typecheck_expr.seq │ ├── typecheck_stmt.seq │ └── types.seq ├── pipeline │ ├── canonical_opt.seq │ ├── interalign.seq │ ├── parallel.seq │ ├── prefetch.seq │ └── revcomp_opt.seq ├── python │ ├── __init__.py │ ├── find-python-library.py │ ├── mymodule.py │ └── pybridge.seq ├── sir │ ├── analyze │ │ ├── dominator.cpp │ │ └── reaching.cpp │ ├── base.cpp │ ├── constant.cpp │ ├── flow.cpp │ ├── func.cpp │ ├── instr.cpp │ ├── module.cpp │ ├── test.h │ ├── transform │ │ └── manager.cpp │ ├── types │ │ └── types.cpp │ ├── util │ │ └── matching.cpp │ ├── value.cpp │ └── var.cpp ├── stdlib │ ├── bisect_test.seq │ ├── heapq_test.seq │ ├── itertools_test.seq │ ├── math_test.seq │ ├── operator_test.seq │ ├── random_test.seq │ ├── sort_test.seq │ ├── statistics_test.seq │ └── str_test.seq ├── transform │ ├── canonical.seq │ ├── dict_opt.seq │ ├── folding.seq │ ├── for_lowering.seq │ ├── inlining.seq │ ├── io_opt.seq │ ├── omp.seq │ ├── outlining.seq │ └── str_opt.seq └── types.cpp └── util ├── jupyter ├── README.md ├── seq_kernel │ ├── __init__.py │ ├── __main__.py │ ├── install.py │ ├── kernel.js │ ├── kernel.py │ ├── redirector.py │ ├── seqlex.py │ └── wrapper.py ├── setup.py └── wrapper.py └── vscode ├── .gitignore ├── README.md ├── client ├── package.json ├── src │ └── extension.ts ├── tsconfig.json └── yarn.lock ├── language-configuration.json ├── package.json ├── server ├── package.json ├── src │ ├── server.ts │ └── wrapper.ts ├── tsconfig.json └── yarn.lock ├── syntaxes └── seq.tmLanguage.json ├── tsconfig.json ├── tslint.json └── yarn.lock /.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | BasedOnStyle: LLVM 3 | ColumnLimit: 88 4 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | *.png binary 2 | *.jpg binary 3 | *.jpeg binary 4 | *.gif binary 5 | *.ico binary 6 | *.mov binary 7 | *.mp4 binary 8 | *.mp3 binary 9 | *.flv binary 10 | *.fla binary 11 | *.swf binary 12 | *.gz binary 13 | *.zip binary 14 | *.7z binary 15 | *.ttf binary 16 | *.eot binary 17 | *.woff binary 18 | *.pyc binary 19 | *.pdf binary 20 | 21 | *.gz binary 22 | 23 | *.bam binary 24 | *.bam.bai binary 25 | *.cram binary 26 | *.cram.crai binary 27 | -------------------------------------------------------------------------------- /.github/actions/build-manylinux/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM quay.io/pypa/manylinux2014_x86_64 2 | COPY entrypoint.sh /entrypoint.sh 3 | ENTRYPOINT ["/entrypoint.sh"] 4 | -------------------------------------------------------------------------------- /.github/actions/build-manylinux/action.yml: -------------------------------------------------------------------------------- 1 | name: manylinux build 2 | description: Builds Seq on manylinux 3 | runs: 4 | using: docker 5 | image: Dockerfile 6 | -------------------------------------------------------------------------------- /.github/actions/build-manylinux/entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh -l 2 | set -e 3 | 4 | # setup 5 | cd /github/workspace 6 | yum -y update 7 | yum -y install python3 python3-devel 8 | 9 | # env 10 | export PYTHONPATH=$(pwd)/test/python 11 | export SEQ_PYTHON=$(python3 test/python/find-python-library.py) 12 | python3 -m pip install numpy 13 | 14 | # deps 15 | if [ ! -d ./llvm ]; then 16 | /bin/bash scripts/deps.sh 2; 17 | fi 18 | 19 | # build 20 | mkdir build 21 | export CC="$(pwd)/llvm/bin/clang" 22 | export CXX="$(pwd)/llvm/bin/clang++" 23 | export LLVM_DIR=$(llvm/bin/llvm-config --cmakedir) 24 | (cd build && cmake .. -DCMAKE_BUILD_TYPE=Release \ 25 | -DCMAKE_C_COMPILER=${CC} \ 26 | -DCMAKE_CXX_COMPILER=${CXX}) 27 | cmake --build build --config Release -- VERBOSE=1 28 | 29 | # test 30 | ln -s build/libseqrt.so . 31 | build/seqtest 32 | build/seqc run test/core/helloworld.seq 33 | build/seqc run test/core/exit.seq || if [[ $? -ne 42 ]]; then false; fi 34 | 35 | # package 36 | export SEQ_BUILD_ARCHIVE=seq-$(uname -s | awk '{print tolower($0)}')-$(uname -m).tar.gz 37 | mkdir -p seq-deploy/bin seq-deploy/lib/seq 38 | cp build/seqc seq-deploy/bin/ 39 | cp build/libseq*.so seq-deploy/lib/seq/ 40 | cp build/libomp.so seq-deploy/lib/seq/ 41 | cp -r stdlib seq-deploy/lib/seq/ 42 | tar -czf ${SEQ_BUILD_ARCHIVE} seq-deploy 43 | du -sh seq-deploy 44 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ###################### 2 | # Generic .gitignore # 3 | ###################### 4 | 5 | # Compiled source # 6 | ################### 7 | *.com 8 | *.class 9 | *.dll 10 | *.exe 11 | *.o 12 | *.obj 13 | *.so 14 | *.pyc 15 | build/ 16 | build_*/ 17 | deps/ 18 | 19 | # Packages # 20 | ############ 21 | # it's better to unpack these files and commit the raw source 22 | # git has its own built-in compression methods 23 | *.7z 24 | *.dmg 25 | *.iso 26 | *.jar 27 | *.rar 28 | *.tar 29 | *.zip 30 | 31 | # Logs and databases # 32 | ###################### 33 | *.log 34 | *.sql 35 | *.sqlite 36 | 37 | # OS generated files # 38 | ###################### 39 | .DS_Store 40 | .DS_Store? 41 | ._* 42 | .Spotlight-V100 43 | .Trashes 44 | ehthumbs.db 45 | Thumbs.db 46 | 47 | # IDE generated files # 48 | ####################### 49 | .idea 50 | .mypy_cache 51 | .vscode 52 | 53 | # Doxygen # 54 | ########### 55 | dox 56 | 57 | # Ocaml # 58 | ######### 59 | *.cm[iot] 60 | *.byte 61 | *.native 62 | *.dSYM 63 | *.conflicts 64 | .merlin 65 | 66 | # Testing playground # 67 | ###################### 68 | scratch.seq 69 | tmp 70 | _* 71 | gtest_parallel.py 72 | -------------------------------------------------------------------------------- /CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @arshajii @inumanag 2 | /compiler/ @arshajii 3 | /compiler/parser/ @inumanag 4 | /docs/ @markhend 5 | -------------------------------------------------------------------------------- /compiler/dsl/plugins.cpp: -------------------------------------------------------------------------------- 1 | #include "plugins.h" 2 | #include "util/common.h" 3 | #include 4 | 5 | namespace seq { 6 | 7 | PluginManager::~PluginManager() { 8 | for (auto &plugin : plugins) { 9 | dlclose(plugin.handle); 10 | } 11 | } 12 | 13 | PluginManager::Error PluginManager::load(const std::string &path) { 14 | void *handle = dlopen(path.c_str(), RTLD_LAZY); 15 | if (!handle) 16 | return Error::NOT_FOUND; 17 | 18 | auto *entry = (LoadFunc *)dlsym(handle, "load"); 19 | if (!entry) 20 | return Error::NO_ENTRYPOINT; 21 | 22 | auto dsl = (*entry)(); 23 | plugins.push_back({std::move(dsl), path, handle}); 24 | return load(plugins.back().dsl.get()); 25 | } 26 | 27 | PluginManager::Error PluginManager::load(DSL *dsl) { 28 | if (!dsl || 29 | !dsl->isVersionSupported(SEQ_VERSION_MAJOR, SEQ_VERSION_MINOR, SEQ_VERSION_PATCH)) 30 | return Error::UNSUPPORTED_VERSION; 31 | 32 | dsl->addIRPasses(pm, debug); 33 | // TODO: register new keywords 34 | 35 | return Error::NONE; 36 | } 37 | 38 | } // namespace seq 39 | -------------------------------------------------------------------------------- /compiler/dsl/plugins.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "dsl.h" 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | namespace seq { 10 | 11 | /// Plugin metadata 12 | struct Plugin { 13 | /// the associated DSL 14 | std::unique_ptr dsl; 15 | /// plugin load path 16 | std::string path; 17 | /// plugin dlopen handle 18 | void *handle; 19 | }; 20 | 21 | /// Manager for loading, applying and unloading plugins. 22 | class PluginManager { 23 | private: 24 | /// pass manager with which to register plugin IR passes 25 | ir::transform::PassManager *pm; 26 | /// vector of loaded plugins 27 | std::vector plugins; 28 | /// true if compiling in debug mode 29 | bool debug; 30 | 31 | public: 32 | using LoadFunc = std::function()>; 33 | 34 | /// Error codes when loading plugins 35 | enum Error { NONE = 0, NOT_FOUND, NO_ENTRYPOINT, UNSUPPORTED_VERSION }; 36 | 37 | /// Constructs a plugin manager from a given IR pass manager 38 | /// @param pm the IR pass manager to register IR passes with 39 | explicit PluginManager(ir::transform::PassManager *pm, bool debug = false) 40 | : pm(pm), plugins(), debug(debug) {} 41 | 42 | ~PluginManager(); 43 | 44 | /// Loads the plugin at the given load path. 45 | Error load(const std::string &path); 46 | /// Loads the given DSL 47 | Error load(DSL *dsl); 48 | }; 49 | 50 | } // namespace seq 51 | -------------------------------------------------------------------------------- /compiler/parser/ast.h: -------------------------------------------------------------------------------- 1 | /* 2 | * ast.h --- Seq AST infrastructure. 3 | * 4 | * (c) Seq project. All rights reserved. 5 | * This file is subject to the terms and conditions defined in 6 | * file 'LICENSE', which is part of this source code package. 7 | */ 8 | 9 | #pragma once 10 | 11 | #include "parser/ast/expr.h" 12 | #include "parser/ast/stmt.h" 13 | #include "parser/ast/types.h" 14 | -------------------------------------------------------------------------------- /compiler/parser/parser.h: -------------------------------------------------------------------------------- 1 | /* 2 | * parser.h --- Seq AST parser. 3 | * 4 | * (c) Seq project. All rights reserved. 5 | * This file is subject to the terms and conditions defined in 6 | * file 'LICENSE', which is part of this source code package. 7 | */ 8 | 9 | #pragma once 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | #include "sir/sir.h" 16 | #include "util/common.h" 17 | 18 | namespace seq { 19 | 20 | seq::ir::Module *parse(const std::string &argv0, const std::string &file, 21 | const std::string &code = "", bool isCode = false, 22 | int isTest = 0, int startLine = 0, 23 | const std::unordered_map &defines = 24 | std::unordered_map{}); 25 | 26 | void generateDocstr(const std::string &argv0); 27 | 28 | } // namespace seq 29 | -------------------------------------------------------------------------------- /compiler/parser/peg/openmp.peg: -------------------------------------------------------------------------------- 1 | # OpenMP PEG grammar 2 | 3 | %preamble { 4 | #include "parser/peg/rules.h" 5 | #include 6 | using namespace std; 7 | using namespace seq::ast; 8 | 9 | #define V0 VS[0] 10 | #define V1 VS[1] 11 | #define ac std::any_cast 12 | } 13 | 14 | pragma <- "omp"? _ "parallel"? _ (clause _)* { 15 | vector v; 16 | for (auto &i: VS) { 17 | auto vi = ac>(i); 18 | v.insert(v.end(), vi.begin(), vi.end()); 19 | } 20 | return v; 21 | } 22 | clause <- 23 | / "schedule" _ "(" _ schedule_kind (_ "," _ int)? _ ")" { 24 | vector v{{"schedule", make_shared(ac(V0))}}; 25 | if (VS.size() > 1) 26 | v.push_back({"chunk_size", make_shared(ac(V1))}); 27 | return v; 28 | } 29 | / "num_threads" _ "(" _ int _ ")" { 30 | return vector{{"num_threads", make_shared(ac(V0))}}; 31 | } 32 | / "ordered" { 33 | return vector{{"ordered", make_shared(true)}}; 34 | } 35 | schedule_kind <- ("static" / "dynamic" / "guided" / "auto" / "runtime") { 36 | return VS.token_to_string(); 37 | } 38 | int <- [1-9] [0-9]* { 39 | return stoi(VS.token_to_string()); 40 | } 41 | # ident <- [a-zA-Z_] [a-zA-Z_0-9]* { 42 | # return make_shared(VS.token_to_string()); 43 | # } 44 | ~SPACE <- [ \t]+ 45 | ~_ <- SPACE* 46 | -------------------------------------------------------------------------------- /compiler/parser/peg/peg.h: -------------------------------------------------------------------------------- 1 | /* 2 | * peg.h --- PEG parser interface. 3 | * 4 | * (c) Seq project. All rights reserved. 5 | * This file is subject to the terms and conditions defined in 6 | * file 'LICENSE', which is part of this source code package. 7 | */ 8 | 9 | #pragma once 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | #include "parser/ast.h" 16 | #include "parser/cache.h" 17 | #include "util/common.h" 18 | 19 | namespace seq { 20 | namespace ast { 21 | 22 | /// Parse a Seq code block with the appropriate file and position offsets. 23 | StmtPtr parseCode(const shared_ptr &cache, const string &file, 24 | const string &code, int line_offset = 0); 25 | /// Parse a Seq code expression. 26 | ExprPtr parseExpr(const shared_ptr &cache, const string &code, 27 | const seq::SrcInfo &offset); 28 | /// Parse a Seq file. 29 | StmtPtr parseFile(const shared_ptr &cache, const string &file); 30 | 31 | /// Parse a OpenMP clause. 32 | vector parseOpenMP(const shared_ptr &cache, const string &code, 33 | const seq::SrcInfo &loc); 34 | 35 | } // namespace ast 36 | } // namespace seq 37 | -------------------------------------------------------------------------------- /compiler/parser/peg/rules.h: -------------------------------------------------------------------------------- 1 | /* 2 | * peg.h --- PEG parser interface. 3 | * 4 | * (c) Seq project. All rights reserved. 5 | * This file is subject to the terms and conditions defined in 6 | * file 'LICENSE', which is part of this source code package. 7 | */ 8 | 9 | #pragma once 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | #include "parser/ast.h" 20 | #include "parser/cache.h" 21 | #include "parser/common.h" 22 | #include "util/peglib.h" 23 | 24 | namespace seq { 25 | namespace ast { 26 | 27 | struct ParseContext { 28 | shared_ptr cache; 29 | std::stack indent; 30 | int parens; 31 | int line_offset, col_offset; 32 | ParseContext(shared_ptr cache, int parens = 0, int line_offset = 0, 33 | int col_offset = 0) 34 | : cache(move(cache)), parens(parens), line_offset(line_offset), 35 | col_offset(col_offset) {} 36 | 37 | bool hasCustomStmtKeyword(const string &kwd, bool hasExpr) const { 38 | auto i = cache->customBlockStmts.find(kwd); 39 | if (i != cache->customBlockStmts.end()) 40 | return i->second.first == hasExpr; 41 | return false; 42 | } 43 | bool hasCustomExprStmt(const string &kwd) const { 44 | return in(cache->customExprStmts, kwd); 45 | } 46 | }; 47 | 48 | } // namespace ast 49 | } // namespace seq 50 | 51 | void init_seq_rules(peg::Grammar &); 52 | void init_seq_actions(peg::Grammar &); 53 | void init_omp_rules(peg::Grammar &); 54 | void init_omp_actions(peg::Grammar &); 55 | -------------------------------------------------------------------------------- /compiler/parser/visitors/typecheck/typecheck.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * typecheck.cpp --- Type inference and type-dependent AST transformations. 3 | * 4 | * (c) Seq project. All rights reserved. 5 | * This file is subject to the terms and conditions defined in 6 | * file 'LICENSE', which is part of this source code package. 7 | */ 8 | 9 | #include "util/fmt/format.h" 10 | #include 11 | #include 12 | #include 13 | 14 | #include "parser/ast.h" 15 | #include "parser/common.h" 16 | #include "parser/visitors/simplify/simplify_ctx.h" 17 | #include "parser/visitors/typecheck/typecheck.h" 18 | #include "parser/visitors/typecheck/typecheck_ctx.h" 19 | 20 | using fmt::format; 21 | using std::deque; 22 | using std::dynamic_pointer_cast; 23 | using std::get; 24 | using std::move; 25 | using std::ostream; 26 | using std::stack; 27 | using std::static_pointer_cast; 28 | 29 | namespace seq { 30 | namespace ast { 31 | 32 | using namespace types; 33 | 34 | TypecheckVisitor::TypecheckVisitor(shared_ptr ctx, 35 | const shared_ptr> &stmts) 36 | : ctx(move(ctx)), allowVoidExpr(false) { 37 | prependStmts = stmts ? stmts : make_shared>(); 38 | } 39 | 40 | StmtPtr TypecheckVisitor::apply(shared_ptr cache, StmtPtr stmts) { 41 | auto ctx = make_shared(cache); 42 | cache->typeCtx = ctx; 43 | TypecheckVisitor v(ctx); 44 | auto infer = v.inferTypes(stmts->clone(), true, ""); 45 | return move(infer.second); 46 | } 47 | 48 | TypePtr TypecheckVisitor::unify(TypePtr &a, const TypePtr &b) { 49 | if (!a) 50 | return a = b; 51 | seqassert(b, "rhs is nullptr"); 52 | types::Type::Unification undo; 53 | if (a->unify(b.get(), &undo) >= 0) 54 | return a; 55 | undo.undo(); 56 | // LOG("{} / {}", a->debugString(true), b->debugString(true)); 57 | a->unify(b.get(), &undo); 58 | error("cannot unify {} and {}", a->toString(), b->toString()); 59 | return nullptr; 60 | } 61 | 62 | } // namespace ast 63 | } // namespace seq 64 | -------------------------------------------------------------------------------- /compiler/seq/pipeline.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "sir/sir.h" 4 | #include "sir/transform/pass.h" 5 | 6 | namespace seq { 7 | 8 | class PipelineSubstitutionOptimization : public ir::transform::OperatorPass { 9 | static const std::string KEY; 10 | std::string getKey() const override { return KEY; } 11 | void handle(ir::PipelineFlow *) override; 12 | }; 13 | 14 | class PipelinePrefetchOptimization : public ir::transform::OperatorPass { 15 | const unsigned SCHED_WIDTH_PREFETCH = 16; 16 | static const std::string KEY; 17 | std::string getKey() const override { return KEY; } 18 | void handle(ir::PipelineFlow *) override; 19 | }; 20 | 21 | class PipelineInterAlignOptimization : public ir::transform::OperatorPass { 22 | const unsigned SCHED_WIDTH_INTERALIGN = 2048; 23 | static const std::string KEY; 24 | std::string getKey() const override { return KEY; } 25 | void handle(ir::PipelineFlow *) override; 26 | }; 27 | 28 | } // namespace seq 29 | -------------------------------------------------------------------------------- /compiler/seq/revcomp.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "sir/dsl/nodes.h" 4 | #include "sir/sir.h" 5 | #include "sir/transform/pass.h" 6 | 7 | namespace seq { 8 | 9 | class KmerRevcomp : public ir::AcceptorExtend { 10 | private: 11 | ir::Value *kmer; 12 | 13 | public: 14 | static const char NodeId; 15 | 16 | using AcceptorExtend::AcceptorExtend; 17 | 18 | explicit KmerRevcomp(ir::Value *kmer) : AcceptorExtend(), kmer(kmer) {} 19 | 20 | std::unique_ptr getBuilder() const override; 21 | std::unique_ptr getCFBuilder() const override; 22 | 23 | bool match(const ir::Value *v) const override; 24 | ir::Value *doClone(ir::util::CloneVisitor &cv) const override; 25 | std::ostream &doFormat(std::ostream &os) const override; 26 | }; 27 | 28 | class KmerRevcompInterceptor : public ir::transform::Pass { 29 | static const std::string KEY; 30 | std::string getKey() const override { return KEY; } 31 | void run(ir::Module *) override; 32 | }; 33 | 34 | } // namespace seq 35 | -------------------------------------------------------------------------------- /compiler/seq/seq.cpp: -------------------------------------------------------------------------------- 1 | #include "seq.h" 2 | #include "pipeline.h" 3 | #include "revcomp.h" 4 | 5 | #include "sir/transform/lowering/pipeline.h" 6 | 7 | namespace seq { 8 | 9 | void Seq::addIRPasses(ir::transform::PassManager *pm, bool debug) { 10 | pm->registerPass(std::make_unique()); 11 | if (debug) 12 | return; 13 | auto dep = ir::transform::lowering::PipelineLowering::KEY; 14 | pm->registerPass(std::make_unique(), dep); 15 | pm->registerPass(std::make_unique(), dep); 16 | pm->registerPass(std::make_unique(), dep); 17 | } 18 | 19 | } // namespace seq 20 | -------------------------------------------------------------------------------- /compiler/seq/seq.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "dsl/dsl.h" 4 | 5 | namespace seq { 6 | 7 | class Seq : public DSL { 8 | public: 9 | std::string getName() const override { return "Seq"; } 10 | void addIRPasses(ir::transform::PassManager *pm, bool debug) override; 11 | }; 12 | 13 | } // namespace seq 14 | -------------------------------------------------------------------------------- /compiler/sir/analyze/analysis.cpp: -------------------------------------------------------------------------------- 1 | #include "analysis.h" 2 | 3 | #include "sir/transform/manager.h" 4 | 5 | namespace seq { 6 | namespace ir { 7 | namespace analyze { 8 | 9 | const Result *Analysis::doGetAnalysis(const std::string &key) { 10 | return manager ? manager->getAnalysisResult(key) : nullptr; 11 | } 12 | 13 | } // namespace analyze 14 | } // namespace ir 15 | } // namespace seq 16 | -------------------------------------------------------------------------------- /compiler/sir/analyze/analysis.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "sir/module.h" 6 | #include "sir/transform/pass.h" 7 | 8 | namespace seq { 9 | namespace ir { 10 | namespace analyze { 11 | 12 | /// Analysis result base struct. 13 | struct Result { 14 | virtual ~Result() noexcept = default; 15 | }; 16 | 17 | /// Base class for IR analyses. 18 | class Analysis { 19 | private: 20 | transform::PassManager *manager = nullptr; 21 | 22 | public: 23 | virtual ~Analysis() noexcept = default; 24 | 25 | /// @return a unique key for this pass 26 | virtual std::string getKey() const = 0; 27 | 28 | /// Execute the analysis. 29 | /// @param module the module 30 | virtual std::unique_ptr run(const Module *module) = 0; 31 | 32 | /// Sets the manager. 33 | /// @param mng the new manager 34 | void setManager(transform::PassManager *mng) { manager = mng; } 35 | /// Returns the result of a given analysis. 36 | /// @param key the analysis key 37 | template 38 | const AnalysisType *getAnalysisResult(const std::string &key) { 39 | return static_cast(doGetAnalysis(key)); 40 | } 41 | 42 | private: 43 | const analyze::Result *doGetAnalysis(const std::string &key); 44 | }; 45 | 46 | } // namespace analyze 47 | } // namespace ir 48 | } // namespace seq 49 | -------------------------------------------------------------------------------- /compiler/sir/analyze/dataflow/dominator.cpp: -------------------------------------------------------------------------------- 1 | #include "dominator.h" 2 | 3 | namespace seq { 4 | namespace ir { 5 | namespace analyze { 6 | namespace dataflow { 7 | 8 | void DominatorInspector::analyze() { 9 | auto changed = true; 10 | while (changed) { 11 | changed = false; 12 | for (auto *blk : *cfg) { 13 | auto init = false; 14 | std::set old = sets[blk->getId()]; 15 | std::set working; 16 | 17 | for (auto it = blk->predecessors_begin(); it != blk->predecessors_end(); ++it) { 18 | auto &predDoms = sets[(*it)->getId()]; 19 | if (!init) { 20 | init = true; 21 | working = std::set(predDoms.begin(), predDoms.end()); 22 | } 23 | 24 | std::set newWorking; 25 | std::set_intersection(working.begin(), working.end(), predDoms.begin(), 26 | predDoms.end(), 27 | std::inserter(newWorking, newWorking.begin())); 28 | working = newWorking; 29 | } 30 | 31 | working.insert(blk->getId()); 32 | 33 | if (working != old) { 34 | changed = true; 35 | sets[blk->getId()] = working; 36 | } 37 | } 38 | } 39 | } 40 | 41 | bool DominatorInspector::isDominated(const Value *v, const Value *dominator) { 42 | auto *vBlock = cfg->getBlock(v); 43 | auto *dBlock = cfg->getBlock(dominator); 44 | 45 | if (vBlock->getId() == dBlock->getId()) { 46 | auto vDist = 47 | std::distance(vBlock->begin(), std::find(vBlock->begin(), vBlock->end(), v)); 48 | auto dDist = std::distance(vBlock->begin(), 49 | std::find(vBlock->begin(), vBlock->end(), dominator)); 50 | return dDist <= vDist; 51 | } 52 | 53 | return sets[vBlock->getId()].find(dBlock->getId()) != sets[vBlock->getId()].end(); 54 | } 55 | 56 | const std::string DominatorAnalysis::KEY = "core-analyses-dominator"; 57 | 58 | std::unique_ptr DominatorAnalysis::run(const Module *m) { 59 | auto *cfgResult = getAnalysisResult(cfAnalysisKey); 60 | auto ret = std::make_unique(cfgResult); 61 | for (const auto &graph : cfgResult->graphs) { 62 | auto inspector = std::make_unique(graph.second.get()); 63 | inspector->analyze(); 64 | ret->results[graph.first] = std::move(inspector); 65 | } 66 | return ret; 67 | } 68 | 69 | } // namespace dataflow 70 | } // namespace analyze 71 | } // namespace ir 72 | } // namespace seq 73 | -------------------------------------------------------------------------------- /compiler/sir/analyze/dataflow/dominator.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include "sir/analyze/analysis.h" 8 | #include "sir/analyze/dataflow/cfg.h" 9 | 10 | namespace seq { 11 | namespace ir { 12 | namespace analyze { 13 | namespace dataflow { 14 | 15 | /// Helper to query the dominators of a particular function. 16 | class DominatorInspector { 17 | private: 18 | std::unordered_map> sets; 19 | CFGraph *cfg; 20 | 21 | public: 22 | explicit DominatorInspector(CFGraph *cfg) : cfg(cfg) {} 23 | 24 | /// Do the analysis. 25 | void analyze(); 26 | 27 | /// Checks if one value dominates another. 28 | /// @param v the value 29 | /// @param dominator the dominator value 30 | bool isDominated(const Value *v, const Value *dominator); 31 | }; 32 | 33 | /// Result of a dominator analysis. 34 | struct DominatorResult : public Result { 35 | /// the corresponding control flow result 36 | const CFResult *cfgResult; 37 | /// the dominator inspectors 38 | std::unordered_map> results; 39 | 40 | explicit DominatorResult(const CFResult *cfgResult) : cfgResult(cfgResult) {} 41 | }; 42 | 43 | /// Dominator analysis. Must have control flow-graph available. 44 | class DominatorAnalysis : public Analysis { 45 | private: 46 | /// the control-flow analysis key 47 | std::string cfAnalysisKey; 48 | 49 | public: 50 | static const std::string KEY; 51 | 52 | /// Initializes a dominator analysis. 53 | /// @param cfAnalysisKey the control-flow analysis key 54 | explicit DominatorAnalysis(std::string cfAnalysisKey) 55 | : cfAnalysisKey(std::move(cfAnalysisKey)) {} 56 | 57 | std::string getKey() const override { return KEY; } 58 | 59 | std::unique_ptr run(const Module *m) override; 60 | }; 61 | 62 | } // namespace dataflow 63 | } // namespace analyze 64 | } // namespace ir 65 | } // namespace seq 66 | -------------------------------------------------------------------------------- /compiler/sir/analyze/dataflow/reaching.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "sir/analyze/analysis.h" 6 | #include "sir/analyze/dataflow/cfg.h" 7 | 8 | namespace seq { 9 | namespace ir { 10 | namespace analyze { 11 | namespace dataflow { 12 | 13 | /// Helper to query the reaching definitions of a particular function. 14 | class RDInspector { 15 | private: 16 | struct BlockData { 17 | std::unordered_map> in; 18 | std::unordered_map> out; 19 | std::unordered_set killed; 20 | std::unordered_map generated; 21 | bool initialized = false; 22 | 23 | BlockData() = default; 24 | }; 25 | std::unordered_set invalid; 26 | std::unordered_map sets; 27 | CFGraph *cfg; 28 | 29 | public: 30 | explicit RDInspector(CFGraph *cfg) : cfg(cfg) {} 31 | 32 | /// Do the analysis. 33 | void analyze(); 34 | 35 | /// Gets the reaching definitions at a particular location. 36 | /// @param var the variable being inspected 37 | /// @param loc the location 38 | /// @return an unordered set of value ids 39 | std::unordered_set getReachingDefinitions(Var *var, Value *loc); 40 | 41 | private: 42 | void initializeIfNecessary(CFBlock *blk); 43 | 44 | void calculateIn(CFBlock *blk); 45 | bool calculateOut(CFBlock *blk); 46 | }; 47 | 48 | /// Result of a reaching definition analysis. 49 | struct RDResult : public Result { 50 | /// the corresponding control flow result 51 | const CFResult *cfgResult; 52 | /// the reaching definition inspectors 53 | std::unordered_map> results; 54 | 55 | explicit RDResult(const CFResult *cfgResult) : cfgResult(cfgResult) {} 56 | }; 57 | 58 | /// Reaching definition analysis. Must have control flow-graph available. 59 | class RDAnalysis : public Analysis { 60 | private: 61 | /// the control-flow analysis key 62 | std::string cfAnalysisKey; 63 | 64 | public: 65 | static const std::string KEY; 66 | 67 | /// Initializes a reaching definition analysis. 68 | /// @param cfAnalysisKey the control-flow analysis key 69 | explicit RDAnalysis(std::string cfAnalysisKey) 70 | : cfAnalysisKey(std::move(cfAnalysisKey)) {} 71 | 72 | std::string getKey() const override { return KEY; } 73 | 74 | std::unique_ptr run(const Module *m) override; 75 | }; 76 | 77 | } // namespace dataflow 78 | } // namespace analyze 79 | } // namespace ir 80 | } // namespace seq 81 | -------------------------------------------------------------------------------- /compiler/sir/analyze/module/global_vars.cpp: -------------------------------------------------------------------------------- 1 | #include "global_vars.h" 2 | 3 | #include "sir/util/operator.h" 4 | 5 | namespace seq { 6 | namespace ir { 7 | namespace analyze { 8 | namespace module { 9 | namespace { 10 | struct GlobalVarAnalyzer : public util::Operator { 11 | std::unordered_map assignments; 12 | 13 | void handle(PointerValue *v) override { 14 | if (v->getVar()->isGlobal()) 15 | assignments[v->getVar()->getId()] = -1; 16 | } 17 | 18 | void handle(AssignInstr *v) override { 19 | auto *lhs = v->getLhs(); 20 | auto id = lhs->getId(); 21 | if (lhs->isGlobal()) { 22 | if (assignments.find(id) != assignments.end()) { 23 | assignments[id] = -1; 24 | } else { 25 | assignments[id] = v->getRhs()->getId(); 26 | } 27 | } 28 | } 29 | }; 30 | } // namespace 31 | 32 | const std::string GlobalVarsAnalyses::KEY = "core-analyses-global-vars"; 33 | 34 | std::unique_ptr GlobalVarsAnalyses::run(const Module *m) { 35 | GlobalVarAnalyzer gva; 36 | gva.visit(const_cast(m)); // TODO: any way around this cast? 37 | return std::make_unique(std::move(gva.assignments)); 38 | } 39 | 40 | } // namespace module 41 | } // namespace analyze 42 | } // namespace ir 43 | } // namespace seq 44 | -------------------------------------------------------------------------------- /compiler/sir/analyze/module/global_vars.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "sir/analyze/analysis.h" 6 | 7 | namespace seq { 8 | namespace ir { 9 | namespace analyze { 10 | namespace module { 11 | 12 | struct GlobalVarsResult : public Result { 13 | std::unordered_map assignments; 14 | explicit GlobalVarsResult(std::unordered_map assignments) 15 | : assignments(std::move(assignments)) {} 16 | }; 17 | 18 | class GlobalVarsAnalyses : public Analysis { 19 | static const std::string KEY; 20 | std::string getKey() const override { return KEY; } 21 | 22 | std::unique_ptr run(const Module *m) override; 23 | }; 24 | 25 | } // namespace module 26 | } // namespace analyze 27 | } // namespace ir 28 | } // namespace seq 29 | -------------------------------------------------------------------------------- /compiler/sir/analyze/module/side_effect.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "sir/analyze/analysis.h" 6 | 7 | namespace seq { 8 | namespace ir { 9 | namespace analyze { 10 | namespace module { 11 | 12 | struct SideEffectResult : public Result { 13 | /// mapping of ID to bool indicating whether the node has side effects 14 | std::unordered_map result; 15 | 16 | SideEffectResult(std::unordered_map result) : result(std::move(result)) {} 17 | 18 | /// @param v the value to check 19 | /// @return true if the node has side effects (false positives allowed) 20 | bool hasSideEffect(Value *v) const; 21 | }; 22 | 23 | class SideEffectAnalysis : public Analysis { 24 | private: 25 | /// true if assigning to a global variable automatically has side effects 26 | bool globalAssignmentHasSideEffects; 27 | 28 | public: 29 | static const std::string KEY; 30 | 31 | /// Constructs a side effect analysis. 32 | /// @param globalAssignmentHasSideEffects true if global variable assignment 33 | /// automatically has side effects 34 | explicit SideEffectAnalysis(bool globalAssignmentHasSideEffects = true) 35 | : Analysis(), globalAssignmentHasSideEffects(globalAssignmentHasSideEffects){}; 36 | 37 | std::string getKey() const override { return KEY; } 38 | 39 | std::unique_ptr run(const Module *m) override; 40 | }; 41 | 42 | } // namespace module 43 | } // namespace analyze 44 | } // namespace ir 45 | } // namespace seq 46 | -------------------------------------------------------------------------------- /compiler/sir/attribute.cpp: -------------------------------------------------------------------------------- 1 | #include "value.h" 2 | 3 | #include "util/fmt/ostream.h" 4 | 5 | namespace seq { 6 | namespace ir { 7 | 8 | const std::string KeyValueAttribute::AttributeName = "kvAttribute"; 9 | 10 | bool KeyValueAttribute::has(const std::string &key) const { 11 | return attributes.find(key) != attributes.end(); 12 | } 13 | 14 | std::string KeyValueAttribute::get(const std::string &key) const { 15 | auto it = attributes.find(key); 16 | return it != attributes.end() ? it->second : ""; 17 | } 18 | 19 | std::ostream &KeyValueAttribute::doFormat(std::ostream &os) const { 20 | std::vector keys; 21 | for (auto &val : attributes) 22 | keys.push_back(val.second); 23 | fmt::print(os, FMT_STRING("{}"), fmt::join(keys.begin(), keys.end(), ",")); 24 | return os; 25 | } 26 | 27 | const std::string MemberAttribute::AttributeName = "memberAttribute"; 28 | 29 | std::ostream &MemberAttribute::doFormat(std::ostream &os) const { 30 | std::vector strings; 31 | for (auto &val : memberSrcInfo) 32 | strings.push_back(fmt::format(FMT_STRING("{}={}"), val.first, val.second)); 33 | fmt::print(os, FMT_STRING("({})"), fmt::join(strings.begin(), strings.end(), ",")); 34 | return os; 35 | } 36 | 37 | const std::string SrcInfoAttribute::AttributeName = "srcInfoAttribute"; 38 | 39 | } // namespace ir 40 | } // namespace seq 41 | -------------------------------------------------------------------------------- /compiler/sir/base.cpp: -------------------------------------------------------------------------------- 1 | #include "base.h" 2 | 3 | #include "types/types.h" 4 | #include "util/format.h" 5 | #include "value.h" 6 | #include "var.h" 7 | 8 | namespace seq { 9 | namespace ir { 10 | 11 | id_t IdMixin::currentId = 0; 12 | 13 | void IdMixin::resetId() { currentId = 0; } 14 | 15 | const char Node::NodeId = 0; 16 | 17 | std::ostream &operator<<(std::ostream &os, const Node &other) { 18 | return util::format(os, &other); 19 | } 20 | 21 | int Node::replaceUsedValue(Value *old, Value *newValue) { 22 | return replaceUsedValue(old->getId(), newValue); 23 | } 24 | 25 | int Node::replaceUsedType(types::Type *old, types::Type *newType) { 26 | return replaceUsedType(old->getName(), newType); 27 | } 28 | 29 | int Node::replaceUsedVariable(Var *old, Var *newVar) { 30 | return replaceUsedVariable(old->getId(), newVar); 31 | } 32 | 33 | } // namespace ir 34 | } // namespace seq 35 | -------------------------------------------------------------------------------- /compiler/sir/const.cpp: -------------------------------------------------------------------------------- 1 | #include "const.h" 2 | 3 | namespace seq { 4 | namespace ir { 5 | 6 | const char Const::NodeId = 0; 7 | 8 | int Const::doReplaceUsedType(const std::string &name, types::Type *newType) { 9 | if (type->getName() == name) { 10 | type = newType; 11 | return 1; 12 | } 13 | return 0; 14 | } 15 | 16 | const char TemplatedConst::NodeId = 0; 17 | 18 | } // namespace ir 19 | } // namespace seq 20 | -------------------------------------------------------------------------------- /compiler/sir/dsl/codegen.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "sir/types/types.h" 6 | 7 | #include "sir/llvm/llvm.h" 8 | 9 | namespace seq { 10 | namespace ir { 11 | 12 | namespace analyze { 13 | namespace dataflow { 14 | class CFVisitor; 15 | } // namespace dataflow 16 | } // namespace analyze 17 | 18 | class LLVMVisitor; 19 | 20 | namespace dsl { 21 | namespace codegen { 22 | 23 | /// Builder for LLVM types. 24 | struct TypeBuilder { 25 | virtual ~TypeBuilder() noexcept = default; 26 | 27 | /// Construct the LLVM type. 28 | /// @param the LLVM visitor 29 | /// @return the LLVM type 30 | virtual llvm::Type *buildType(LLVMVisitor *visitor) = 0; 31 | /// Construct the LLVM debug type. 32 | /// @param the LLVM visitor 33 | /// @return the LLVM debug type 34 | virtual llvm::DIType *buildDebugType(LLVMVisitor *visitor) = 0; 35 | }; 36 | 37 | /// Builder for LLVM values. 38 | struct ValueBuilder { 39 | virtual ~ValueBuilder() noexcept = default; 40 | 41 | /// Construct the LLVM value. 42 | /// @param the LLVM visitor 43 | /// @return the LLVM value 44 | virtual llvm::Value *buildValue(LLVMVisitor *visitor) = 0; 45 | }; 46 | 47 | /// Builder for control flow graphs. 48 | struct CFBuilder { 49 | virtual ~CFBuilder() noexcept = default; 50 | 51 | /// Construct the control-flow nodes. 52 | /// @param graph the graph 53 | virtual void buildCFNodes(analyze::dataflow::CFVisitor *visitor) = 0; 54 | }; 55 | 56 | } // namespace codegen 57 | } // namespace dsl 58 | } // namespace ir 59 | } // namespace seq 60 | -------------------------------------------------------------------------------- /compiler/sir/dsl/nodes.cpp: -------------------------------------------------------------------------------- 1 | #include "nodes.h" 2 | 3 | namespace seq { 4 | namespace ir { 5 | namespace dsl { 6 | 7 | namespace types { 8 | const char CustomType::NodeId = 0; 9 | } 10 | 11 | const char CustomConst::NodeId = 0; 12 | 13 | const char CustomFlow::NodeId = 0; 14 | 15 | const char CustomInstr::NodeId = 0; 16 | 17 | } // namespace dsl 18 | } // namespace ir 19 | } // namespace seq 20 | -------------------------------------------------------------------------------- /compiler/sir/llvm/coro/CoroCleanup.h: -------------------------------------------------------------------------------- 1 | //===-- CoroCleanup.h - Lower all coroutine related intrinsics --*- C++ -*-===// 2 | // 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 | // See https://llvm.org/LICENSE.txt for license information. 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 | // 7 | //===----------------------------------------------------------------------===// 8 | // 9 | // \file 10 | // This file delcares a pass that lowers all remaining coroutine intrinsics. 11 | // 12 | //===----------------------------------------------------------------------===// 13 | 14 | #ifndef LLVM_TRANSFORMS_COROUTINES_COROCLEANUP_H 15 | #define LLVM_TRANSFORMS_COROUTINES_COROCLEANUP_H 16 | 17 | #include "llvm/IR/PassManager.h" 18 | 19 | namespace llvm { 20 | 21 | class Function; 22 | 23 | struct CoroCleanupPass : PassInfoMixin { 24 | PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM); 25 | static bool isRequired() { return true; } 26 | }; 27 | } // end namespace llvm 28 | 29 | #endif // LLVM_TRANSFORMS_COROUTINES_COROCLEANUP_H 30 | -------------------------------------------------------------------------------- /compiler/sir/llvm/coro/CoroEarly.h: -------------------------------------------------------------------------------- 1 | //===---- CoroEarly.h - Lower early coroutine intrinsics --------*- C++ -*-===// 2 | // 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 | // See https://llvm.org/LICENSE.txt for license information. 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 | // 7 | //===----------------------------------------------------------------------===// 8 | // 9 | // \file 10 | // This file provides the interface to the early coroutine intrinsic lowering 11 | // pass. This pass lowers coroutine intrinsics that hide the details of the 12 | // exact calling convention for coroutine resume and destroy functions and 13 | // details of the structure of the coroutine frame. 14 | // 15 | //===----------------------------------------------------------------------===// 16 | 17 | #ifndef LLVM_TRANSFORMS_COROUTINES_COROEARLY_H 18 | #define LLVM_TRANSFORMS_COROUTINES_COROEARLY_H 19 | 20 | #include "llvm/IR/PassManager.h" 21 | 22 | namespace llvm { 23 | 24 | class Function; 25 | 26 | struct CoroEarlyPass : PassInfoMixin { 27 | PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM); 28 | static bool isRequired() { return true; } 29 | }; 30 | } // end namespace llvm 31 | 32 | #endif // LLVM_TRANSFORMS_COROUTINES_COROEARLY_H 33 | -------------------------------------------------------------------------------- /compiler/sir/llvm/coro/CoroElide.h: -------------------------------------------------------------------------------- 1 | //===---- CoroElide.h - Coroutine frame allocation elision ------*- C++ -*-===// 2 | // 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 | // See https://llvm.org/LICENSE.txt for license information. 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 | // 7 | //===----------------------------------------------------------------------===// 8 | // 9 | // \file 10 | // This file declares a pass that replaces dynamic allocation of coroutine 11 | // frames with alloca and replaces calls to llvm.coro.resume and 12 | // llvm.coro.destroy with direct calls to coroutine sub-functions. 13 | // 14 | //===----------------------------------------------------------------------===// 15 | 16 | #ifndef LLVM_TRANSFORMS_COROUTINES_COROELIDE_H 17 | #define LLVM_TRANSFORMS_COROUTINES_COROELIDE_H 18 | 19 | #include "llvm/IR/PassManager.h" 20 | 21 | namespace llvm { 22 | 23 | class Function; 24 | 25 | struct CoroElidePass : PassInfoMixin { 26 | PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM); 27 | static bool isRequired() { return true; } 28 | }; 29 | } // end namespace llvm 30 | 31 | #endif // LLVM_TRANSFORMS_COROUTINES_COROELIDE_H 32 | -------------------------------------------------------------------------------- /compiler/sir/llvm/coro/CoroSplit.h: -------------------------------------------------------------------------------- 1 | //===- CoroSplit.h - Converts a coroutine into a state machine -*- C++ -*--===// 2 | // 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 | // See https://llvm.org/LICENSE.txt for license information. 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 | // 7 | //===----------------------------------------------------------------------===// 8 | // 9 | // \file 10 | // This file declares the pass that builds the coroutine frame and outlines 11 | // the resume and destroy parts of the coroutine into separate functions. 12 | // 13 | //===----------------------------------------------------------------------===// 14 | 15 | #ifndef LLVM_TRANSFORMS_COROUTINES_COROSPLIT_H 16 | #define LLVM_TRANSFORMS_COROUTINES_COROSPLIT_H 17 | 18 | #include "llvm/Analysis/CGSCCPassManager.h" 19 | #include "llvm/Analysis/LazyCallGraph.h" 20 | #include "llvm/IR/PassManager.h" 21 | 22 | namespace llvm { 23 | 24 | struct CoroSplitPass : PassInfoMixin { 25 | CoroSplitPass(bool ReuseFrameSlot = false) : ReuseFrameSlot(ReuseFrameSlot) {} 26 | 27 | PreservedAnalyses run(LazyCallGraph::SCC &C, CGSCCAnalysisManager &AM, 28 | LazyCallGraph &CG, CGSCCUpdateResult &UR); 29 | static bool isRequired() { return true; } 30 | 31 | // Would be true if the Optimization level isn't O0. 32 | bool ReuseFrameSlot; 33 | }; 34 | } // end namespace llvm 35 | 36 | #endif // LLVM_TRANSFORMS_COROUTINES_COROSPLIT_H 37 | -------------------------------------------------------------------------------- /compiler/sir/llvm/coro/Coroutines.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace llvm { 4 | class Pass; 5 | class PassManagerBuilder; 6 | } // namespace llvm 7 | 8 | namespace seq { 9 | namespace coro { 10 | 11 | /// Add all coroutine passes to appropriate extension points. 12 | void addCoroutinePassesToExtensionPoints(llvm::PassManagerBuilder &Builder); 13 | 14 | /// Lower coroutine intrinsics that are not needed by later passes. 15 | llvm::Pass *createCoroEarlyLegacyPass(); 16 | 17 | /// Split up coroutines into multiple functions driving their state machines. 18 | llvm::Pass *createCoroSplitLegacyPass(bool IsOptimizing = false); 19 | 20 | /// Analyze coroutines use sites, devirtualize resume/destroy calls and elide 21 | /// heap allocation for coroutine frame where possible. 22 | llvm::Pass *createCoroElideLegacyPass(); 23 | 24 | /// Lower all remaining coroutine intrinsics. 25 | llvm::Pass *createCoroCleanupLegacyPass(); 26 | 27 | } // namespace coro 28 | } // namespace seq 29 | -------------------------------------------------------------------------------- /compiler/sir/sir.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "const.h" 4 | #include "dsl/nodes.h" 5 | #include "flow.h" 6 | #include "func.h" 7 | #include "instr.h" 8 | #include "module.h" 9 | #include "types/types.h" 10 | #include "value.h" 11 | #include "var.h" 12 | -------------------------------------------------------------------------------- /compiler/sir/transform/cleanup/canonical.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "sir/transform/pass.h" 4 | #include "sir/transform/rewrite.h" 5 | 6 | namespace seq { 7 | namespace ir { 8 | namespace transform { 9 | namespace cleanup { 10 | 11 | /// Canonicalization pass that flattens nested series 12 | /// flows, puts operands in a predefined order, etc. 13 | class CanonicalizationPass : public OperatorPass, public Rewriter { 14 | private: 15 | std::string sideEffectsKey; 16 | 17 | public: 18 | /// Constructs a canonicalization pass 19 | /// @param sideEffectsKey the side effect analysis' key 20 | CanonicalizationPass(const std::string &sideEffectsKey) 21 | : OperatorPass(/*childrenFirst=*/true), sideEffectsKey(sideEffectsKey) {} 22 | 23 | static const std::string KEY; 24 | std::string getKey() const override { return KEY; } 25 | 26 | void run(Module *m) override; 27 | void handle(CallInstr *) override; 28 | void handle(SeriesFlow *) override; 29 | 30 | private: 31 | void registerStandardRules(Module *m); 32 | }; 33 | 34 | } // namespace cleanup 35 | } // namespace transform 36 | } // namespace ir 37 | } // namespace seq 38 | -------------------------------------------------------------------------------- /compiler/sir/transform/cleanup/dead_code.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "sir/transform/pass.h" 4 | 5 | namespace seq { 6 | namespace ir { 7 | namespace transform { 8 | namespace cleanup { 9 | 10 | /// Cleanup pass that removes dead code. 11 | class DeadCodeCleanupPass : public OperatorPass { 12 | private: 13 | std::string sideEffectsKey; 14 | int numReplacements; 15 | 16 | public: 17 | static const std::string KEY; 18 | 19 | /// Constructs a dead code elimination pass 20 | /// @param sideEffectsKey the side effect analysis' key 21 | DeadCodeCleanupPass(std::string sideEffectsKey) 22 | : OperatorPass(), sideEffectsKey(std::move(sideEffectsKey)), numReplacements(0) {} 23 | 24 | std::string getKey() const override { return KEY; } 25 | 26 | void run(Module *m) override; 27 | 28 | void handle(SeriesFlow *v) override; 29 | void handle(IfFlow *v) override; 30 | void handle(WhileFlow *v) override; 31 | void handle(ImperativeForFlow *v) override; 32 | void handle(TernaryInstr *v) override; 33 | 34 | /// @return the number of replacements 35 | int getNumReplacements() const { return numReplacements; } 36 | 37 | private: 38 | void doReplacement(Value *og, Value *v); 39 | }; 40 | 41 | } // namespace cleanup 42 | } // namespace transform 43 | } // namespace ir 44 | } // namespace seq 45 | -------------------------------------------------------------------------------- /compiler/sir/transform/cleanup/global_demote.cpp: -------------------------------------------------------------------------------- 1 | #include "global_demote.h" 2 | 3 | namespace seq { 4 | namespace ir { 5 | namespace transform { 6 | namespace cleanup { 7 | namespace { 8 | struct GetUsedGlobals : public util::Operator { 9 | std::vector vars; 10 | void preHook(Node *v) override { 11 | for (auto *var : v->getUsedVariables()) { 12 | if (!isA(var) && var->isGlobal()) 13 | vars.push_back(var); 14 | } 15 | } 16 | }; 17 | } // namespace 18 | 19 | const std::string GlobalDemotionPass::KEY = "core-cleanup-global-demote"; 20 | 21 | void GlobalDemotionPass::run(Module *M) { 22 | std::unordered_map localGlobals; 23 | 24 | std::vector worklist = {M->getMainFunc()}; 25 | for (auto *var : *M) { 26 | if (auto *func = cast(var)) 27 | worklist.push_back(func); 28 | } 29 | 30 | for (auto *var : worklist) { 31 | if (auto *func = cast(var)) { 32 | GetUsedGlobals globals; 33 | func->accept(globals); 34 | 35 | for (auto *g : globals.vars) { 36 | LOG_IR("[{}] global {} used in {}", KEY, *g, func->getName()); 37 | auto it = localGlobals.find(g); 38 | if (it == localGlobals.end()) { 39 | localGlobals.emplace(g, func); 40 | } else if (it->second && it->second != func) { 41 | it->second = nullptr; 42 | } 43 | } 44 | } 45 | } 46 | 47 | for (auto it : localGlobals) { 48 | if (!it.second) 49 | continue; 50 | seqassert(it.first->isGlobal(), "var was not global"); 51 | it.first->setGlobal(false); 52 | if (auto *func = cast(it.second)) { 53 | func->push_back(it.first); 54 | ++numDemotions; 55 | LOG_IR("[{}] demoted {} to a local of {}", KEY, *it.first, func->getName()); 56 | } 57 | } 58 | } 59 | 60 | } // namespace cleanup 61 | } // namespace transform 62 | } // namespace ir 63 | } // namespace seq 64 | -------------------------------------------------------------------------------- /compiler/sir/transform/cleanup/global_demote.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "sir/transform/pass.h" 4 | 5 | namespace seq { 6 | namespace ir { 7 | namespace transform { 8 | namespace cleanup { 9 | 10 | /// Demotes global variables that are used in only one 11 | /// function to locals of that function. 12 | class GlobalDemotionPass : public Pass { 13 | private: 14 | /// number of variables we've demoted 15 | int numDemotions; 16 | 17 | public: 18 | static const std::string KEY; 19 | 20 | /// Constructs a global variable demotion pass 21 | GlobalDemotionPass() : Pass(), numDemotions(0) {} 22 | 23 | std::string getKey() const override { return KEY; } 24 | void run(Module *v) override; 25 | 26 | /// @return number of variables we've demoted 27 | int getNumDemotions() const { return numDemotions; } 28 | }; 29 | 30 | } // namespace cleanup 31 | } // namespace transform 32 | } // namespace ir 33 | } // namespace seq 34 | -------------------------------------------------------------------------------- /compiler/sir/transform/cleanup/replacer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "sir/transform/pass.h" 4 | 5 | namespace seq { 6 | namespace ir { 7 | namespace transform { 8 | namespace cleanup { 9 | 10 | /// Cleanup pass that physically replaces nodes. 11 | class ReplaceCleanupPass : public Pass { 12 | public: 13 | static const std::string KEY; 14 | std::string getKey() const override { return KEY; } 15 | void run(Module *module) override; 16 | }; 17 | 18 | } // namespace cleanup 19 | } // namespace transform 20 | } // namespace ir 21 | } // namespace seq 22 | -------------------------------------------------------------------------------- /compiler/sir/transform/folding/const_fold.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include "rule.h" 7 | 8 | #include "sir/transform/pass.h" 9 | 10 | namespace seq { 11 | namespace ir { 12 | namespace transform { 13 | namespace folding { 14 | 15 | class FoldingPass : public OperatorPass, public Rewriter { 16 | public: 17 | /// Constructs a folding pass. 18 | FoldingPass() : OperatorPass(/*childrenFirst=*/true) {} 19 | 20 | static const std::string KEY; 21 | std::string getKey() const override { return KEY; } 22 | 23 | void run(Module *m) override; 24 | void handle(CallInstr *v) override; 25 | 26 | private: 27 | void registerStandardRules(Module *m); 28 | }; 29 | 30 | } // namespace folding 31 | } // namespace transform 32 | } // namespace ir 33 | } // namespace seq 34 | -------------------------------------------------------------------------------- /compiler/sir/transform/folding/const_prop.cpp: -------------------------------------------------------------------------------- 1 | #include "const_prop.h" 2 | 3 | #include "sir/analyze/dataflow/reaching.h" 4 | #include "sir/analyze/module/global_vars.h" 5 | #include "sir/util/cloning.h" 6 | 7 | namespace seq { 8 | namespace ir { 9 | namespace transform { 10 | namespace folding { 11 | namespace { 12 | bool okConst(Value *v) { 13 | return v && (isA(v) || isA(v) || isA(v)); 14 | } 15 | } // namespace 16 | 17 | const std::string ConstPropPass::KEY = "core-folding-const-prop"; 18 | 19 | void ConstPropPass::handle(VarValue *v) { 20 | auto *M = v->getModule(); 21 | 22 | auto *var = v->getVar(); 23 | 24 | Value *replacement; 25 | if (var->isGlobal()) { 26 | auto *r = getAnalysisResult(globalVarsKey); 27 | if (!r) 28 | return; 29 | 30 | auto it = r->assignments.find(var->getId()); 31 | if (it == r->assignments.end()) 32 | return; 33 | 34 | auto *constDef = M->getValue(it->second); 35 | if (!okConst(constDef)) 36 | return; 37 | 38 | util::CloneVisitor cv(M); 39 | replacement = cv.clone(constDef); 40 | } else { 41 | auto *r = getAnalysisResult(reachingDefKey); 42 | if (!r) 43 | return; 44 | auto *c = r->cfgResult; 45 | 46 | auto it = r->results.find(getParentFunc()->getId()); 47 | auto it2 = c->graphs.find(getParentFunc()->getId()); 48 | if (it == r->results.end() || it2 == c->graphs.end()) 49 | return; 50 | 51 | auto *rd = it->second.get(); 52 | auto *cfg = it2->second.get(); 53 | 54 | auto reaching = rd->getReachingDefinitions(var, v); 55 | 56 | if (reaching.size() != 1) 57 | return; 58 | 59 | auto def = *reaching.begin(); 60 | if (def == -1) 61 | return; 62 | 63 | auto *constDef = cfg->getValue(def); 64 | if (!okConst(constDef)) 65 | return; 66 | 67 | util::CloneVisitor cv(M); 68 | replacement = cv.clone(constDef); 69 | } 70 | 71 | v->replaceAll(replacement); 72 | } 73 | 74 | } // namespace folding 75 | } // namespace transform 76 | } // namespace ir 77 | } // namespace seq 78 | -------------------------------------------------------------------------------- /compiler/sir/transform/folding/const_prop.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "sir/transform/pass.h" 4 | 5 | namespace seq { 6 | namespace ir { 7 | namespace transform { 8 | namespace folding { 9 | 10 | /// Constant propagation pass. 11 | class ConstPropPass : public OperatorPass { 12 | private: 13 | /// Key of the reaching definition analysis 14 | std::string reachingDefKey; 15 | /// Key of the global variables analysis 16 | std::string globalVarsKey; 17 | 18 | public: 19 | static const std::string KEY; 20 | 21 | /// Constructs a constant propagation pass. 22 | /// @param reachingDefKey the reaching definition analysis' key 23 | ConstPropPass(const std::string &reachingDefKey, const std::string &globalVarsKey) 24 | : reachingDefKey(reachingDefKey), globalVarsKey(globalVarsKey) {} 25 | 26 | std::string getKey() const override { return KEY; } 27 | void handle(VarValue *v) override; 28 | }; 29 | 30 | } // namespace folding 31 | } // namespace transform 32 | } // namespace ir 33 | } // namespace seq 34 | -------------------------------------------------------------------------------- /compiler/sir/transform/folding/folding.cpp: -------------------------------------------------------------------------------- 1 | #include "folding.h" 2 | 3 | #include "const_fold.h" 4 | #include "const_prop.h" 5 | 6 | namespace seq { 7 | namespace ir { 8 | namespace transform { 9 | namespace folding { 10 | 11 | const std::string FoldingPassGroup::KEY = "core-folding-pass-group"; 12 | 13 | FoldingPassGroup::FoldingPassGroup(const std::string &sideEffectsPass, 14 | const std::string &reachingDefPass, 15 | const std::string &globalVarPass, 16 | bool runGlobalDemotion) { 17 | auto gdUnique = std::make_unique(); 18 | auto canonUnique = std::make_unique(sideEffectsPass); 19 | auto fpUnique = std::make_unique(); 20 | auto dceUnique = std::make_unique(sideEffectsPass); 21 | 22 | gd = gdUnique.get(); 23 | canon = canonUnique.get(); 24 | fp = fpUnique.get(); 25 | dce = dceUnique.get(); 26 | 27 | if (runGlobalDemotion) 28 | push_back(std::move(gdUnique)); 29 | push_back(std::make_unique(reachingDefPass, globalVarPass)); 30 | push_back(std::move(canonUnique)); 31 | push_back(std::move(fpUnique)); 32 | push_back(std::move(dceUnique)); 33 | } 34 | 35 | bool FoldingPassGroup::shouldRepeat() const { 36 | return gd->getNumDemotions() != 0 || canon->getNumReplacements() != 0 || 37 | fp->getNumReplacements() != 0 || dce->getNumReplacements() != 0; 38 | } 39 | 40 | } // namespace folding 41 | } // namespace transform 42 | } // namespace ir 43 | } // namespace seq 44 | -------------------------------------------------------------------------------- /compiler/sir/transform/folding/folding.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "sir/transform/pass.h" 4 | 5 | #include "sir/transform/cleanup/canonical.h" 6 | #include "sir/transform/cleanup/dead_code.h" 7 | #include "sir/transform/cleanup/global_demote.h" 8 | 9 | namespace seq { 10 | namespace ir { 11 | namespace transform { 12 | namespace folding { 13 | 14 | class FoldingPass; 15 | 16 | /// Group of constant folding passes. 17 | class FoldingPassGroup : public PassGroup { 18 | private: 19 | cleanup::GlobalDemotionPass *gd; 20 | cleanup::CanonicalizationPass *canon; 21 | FoldingPass *fp; 22 | cleanup::DeadCodeCleanupPass *dce; 23 | 24 | public: 25 | static const std::string KEY; 26 | std::string getKey() const override { return KEY; } 27 | 28 | /// @param sideEffectsPass the key of the side effects pass 29 | /// @param reachingDefPass the key of the reaching definitions pass 30 | /// @param globalVarPass the key of the global variables pass 31 | FoldingPassGroup(const std::string &sideEffectsPass, 32 | const std::string &reachingDefPass, const std::string &globalVarPass, 33 | bool runGlobalDemotion = true); 34 | 35 | bool shouldRepeat() const override; 36 | }; 37 | 38 | } // namespace folding 39 | } // namespace transform 40 | } // namespace ir 41 | } // namespace seq 42 | -------------------------------------------------------------------------------- /compiler/sir/transform/lowering/imperative.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "sir/transform/pass.h" 4 | 5 | namespace seq { 6 | namespace ir { 7 | namespace transform { 8 | namespace lowering { 9 | 10 | class ImperativeForFlowLowering : public OperatorPass { 11 | public: 12 | static const std::string KEY; 13 | std::string getKey() const override { return KEY; } 14 | void handle(ForFlow *v) override; 15 | }; 16 | 17 | } // namespace lowering 18 | } // namespace transform 19 | } // namespace ir 20 | } // namespace seq 21 | -------------------------------------------------------------------------------- /compiler/sir/transform/lowering/pipeline.cpp: -------------------------------------------------------------------------------- 1 | #include "pipeline.h" 2 | 3 | #include 4 | 5 | #include "sir/util/cloning.h" 6 | #include "sir/util/irtools.h" 7 | #include "sir/util/matching.h" 8 | 9 | namespace seq { 10 | namespace ir { 11 | namespace transform { 12 | namespace lowering { 13 | namespace { 14 | Value *callStage(Module *M, PipelineFlow::Stage *stage, Value *last) { 15 | std::vector args; 16 | for (auto *arg : *stage) { 17 | args.push_back(arg ? arg : last); 18 | } 19 | return M->N(stage->getCallee()->getSrcInfo(), stage->getCallee(), args); 20 | } 21 | 22 | Value *convertPipelineToForLoopsHelper(Module *M, BodiedFunc *parent, 23 | const std::vector &stages, 24 | unsigned idx = 0, Value *last = nullptr) { 25 | if (idx >= stages.size()) 26 | return last; 27 | 28 | auto *stage = stages[idx]; 29 | if (idx == 0) 30 | return convertPipelineToForLoopsHelper(M, parent, stages, idx + 1, 31 | stage->getCallee()); 32 | 33 | auto *prev = stages[idx - 1]; 34 | if (prev->isGenerator()) { 35 | auto *var = M->Nr(prev->getOutputElementType()); 36 | parent->push_back(var); 37 | auto *body = convertPipelineToForLoopsHelper( 38 | M, parent, stages, idx + 1, callStage(M, stage, M->Nr(var))); 39 | auto *loop = M->N(last->getSrcInfo(), last, util::series(body), var); 40 | if (stage->isParallel()) 41 | loop->setParallel(); 42 | return loop; 43 | } else { 44 | return convertPipelineToForLoopsHelper(M, parent, stages, idx + 1, 45 | callStage(M, stage, last)); 46 | } 47 | } 48 | 49 | Value *convertPipelineToForLoops(PipelineFlow *p, BodiedFunc *parent) { 50 | std::vector stages; 51 | for (auto &stage : *p) { 52 | stages.push_back(&stage); 53 | } 54 | return convertPipelineToForLoopsHelper(p->getModule(), parent, stages); 55 | } 56 | } // namespace 57 | 58 | const std::string PipelineLowering::KEY = "core-pipeline-lowering"; 59 | 60 | void PipelineLowering::handle(PipelineFlow *v) { 61 | v->replaceAll(convertPipelineToForLoops(v, cast(getParentFunc()))); 62 | } 63 | 64 | } // namespace lowering 65 | } // namespace transform 66 | } // namespace ir 67 | } // namespace seq 68 | -------------------------------------------------------------------------------- /compiler/sir/transform/lowering/pipeline.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "sir/transform/pass.h" 4 | 5 | namespace seq { 6 | namespace ir { 7 | namespace transform { 8 | namespace lowering { 9 | 10 | /// Converts pipelines to for-loops 11 | class PipelineLowering : public OperatorPass { 12 | public: 13 | static const std::string KEY; 14 | std::string getKey() const override { return KEY; } 15 | void handle(PipelineFlow *v) override; 16 | }; 17 | 18 | } // namespace lowering 19 | } // namespace transform 20 | } // namespace ir 21 | } // namespace seq 22 | -------------------------------------------------------------------------------- /compiler/sir/transform/parallel/openmp.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "sir/transform/pass.h" 4 | 5 | namespace seq { 6 | namespace ir { 7 | namespace transform { 8 | namespace parallel { 9 | 10 | class OpenMPPass : public OperatorPass { 11 | public: 12 | /// Constructs an OpenMP pass. 13 | OpenMPPass() : OperatorPass(/*childrenFirst=*/true) {} 14 | 15 | static const std::string KEY; 16 | std::string getKey() const override { return KEY; } 17 | 18 | void handle(ForFlow *) override; 19 | void handle(ImperativeForFlow *) override; 20 | }; 21 | 22 | } // namespace parallel 23 | } // namespace transform 24 | } // namespace ir 25 | } // namespace seq 26 | -------------------------------------------------------------------------------- /compiler/sir/transform/parallel/schedule.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "sir/value.h" 4 | 5 | namespace seq { 6 | namespace ir { 7 | 8 | class Value; 9 | 10 | namespace transform { 11 | namespace parallel { 12 | 13 | struct OMPSched { 14 | int code; 15 | bool dynamic; 16 | Value *threads; 17 | Value *chunk; 18 | bool ordered; 19 | 20 | explicit OMPSched(int code = -1, bool dynamic = false, Value *threads = nullptr, 21 | Value *chunk = nullptr, bool ordered = false); 22 | explicit OMPSched(const std::string &code, Value *threads = nullptr, 23 | Value *chunk = nullptr, bool ordered = false); 24 | OMPSched(const OMPSched &s) 25 | : code(s.code), dynamic(s.dynamic), threads(s.threads), chunk(s.chunk), 26 | ordered(s.ordered) {} 27 | 28 | std::vector getUsedValues() const; 29 | int replaceUsedValue(id_t id, Value *newValue); 30 | }; 31 | 32 | } // namespace parallel 33 | } // namespace transform 34 | } // namespace ir 35 | } // namespace seq 36 | -------------------------------------------------------------------------------- /compiler/sir/transform/pass.cpp: -------------------------------------------------------------------------------- 1 | #include "pass.h" 2 | 3 | #include "manager.h" 4 | 5 | namespace seq { 6 | namespace ir { 7 | namespace transform { 8 | 9 | const analyze::Result *Pass::doGetAnalysis(const std::string &key) { 10 | return manager ? manager->getAnalysisResult(key) : nullptr; 11 | } 12 | 13 | void PassGroup::run(Module *module) { 14 | for (auto &p : passes) 15 | p->run(module); 16 | } 17 | 18 | void PassGroup::setManager(PassManager *mng) { 19 | Pass::setManager(mng); 20 | for (auto &p : passes) 21 | p->setManager(mng); 22 | } 23 | 24 | } // namespace transform 25 | } // namespace ir 26 | } // namespace seq 27 | -------------------------------------------------------------------------------- /compiler/sir/transform/pass.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "sir/module.h" 4 | #include "sir/util/operator.h" 5 | 6 | namespace seq { 7 | namespace ir { 8 | 9 | namespace analyze { 10 | struct Result; 11 | } 12 | 13 | namespace transform { 14 | 15 | class PassManager; 16 | 17 | /// General pass base class. 18 | class Pass { 19 | private: 20 | PassManager *manager = nullptr; 21 | 22 | public: 23 | virtual ~Pass() noexcept = default; 24 | 25 | /// @return a unique key for this pass 26 | virtual std::string getKey() const = 0; 27 | 28 | /// Execute the pass. 29 | /// @param module the module 30 | virtual void run(Module *module) = 0; 31 | 32 | /// @return true if pass should repeat 33 | virtual bool shouldRepeat() const { return false; } 34 | 35 | /// Sets the manager. 36 | /// @param mng the new manager 37 | virtual void setManager(PassManager *mng) { manager = mng; } 38 | /// Returns the result of a given analysis. 39 | /// @param key the analysis key 40 | template 41 | const AnalysisType *getAnalysisResult(const std::string &key) { 42 | return static_cast(doGetAnalysis(key)); 43 | } 44 | 45 | private: 46 | const analyze::Result *doGetAnalysis(const std::string &key); 47 | }; 48 | 49 | class PassGroup : public Pass { 50 | private: 51 | std::vector> passes; 52 | 53 | public: 54 | explicit PassGroup(std::vector> passes = {}) 55 | : passes(std::move(passes)) {} 56 | 57 | virtual ~PassGroup() noexcept = default; 58 | 59 | void push_back(std::unique_ptr p) { passes.push_back(std::move(p)); } 60 | 61 | void run(Module *module) override; 62 | 63 | void setManager(PassManager *mng) override; 64 | }; 65 | 66 | /// Pass that runs a single Operator. 67 | class OperatorPass : public Pass, public util::Operator { 68 | public: 69 | /// Constructs an operator pass. 70 | /// @param childrenFirst true if children should be iterated first 71 | explicit OperatorPass(bool childrenFirst = false) : util::Operator(childrenFirst) {} 72 | 73 | void run(Module *module) override { 74 | reset(); 75 | process(module); 76 | } 77 | }; 78 | 79 | } // namespace transform 80 | } // namespace ir 81 | } // namespace seq 82 | -------------------------------------------------------------------------------- /compiler/sir/transform/pythonic/dict.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "sir/transform/pass.h" 4 | 5 | namespace seq { 6 | namespace ir { 7 | namespace transform { 8 | namespace pythonic { 9 | 10 | /// Pass to optimize calls of form d[x] = func(d[x], any). 11 | /// This will work on any dictionary-like object that implements _do_op and 12 | /// _do_op_throws as well as getters. 13 | class DictArithmeticOptimization : public OperatorPass { 14 | public: 15 | static const std::string KEY; 16 | std::string getKey() const override { return KEY; } 17 | void handle(CallInstr *v) override; 18 | }; 19 | 20 | } // namespace pythonic 21 | } // namespace transform 22 | } // namespace ir 23 | } // namespace seq 24 | -------------------------------------------------------------------------------- /compiler/sir/transform/pythonic/io.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "sir/transform/pass.h" 4 | 5 | namespace seq { 6 | namespace ir { 7 | namespace transform { 8 | namespace pythonic { 9 | 10 | /// Pass to optimize print str.cat(...) or file.write(str.cat(...)). 11 | class IOCatOptimization : public OperatorPass { 12 | public: 13 | static const std::string KEY; 14 | std::string getKey() const override { return KEY; } 15 | void handle(CallInstr *v) override; 16 | }; 17 | 18 | } // namespace pythonic 19 | } // namespace transform 20 | } // namespace ir 21 | } // namespace seq 22 | -------------------------------------------------------------------------------- /compiler/sir/transform/pythonic/str.cpp: -------------------------------------------------------------------------------- 1 | #include "str.h" 2 | 3 | #include 4 | 5 | #include "sir/util/cloning.h" 6 | #include "sir/util/irtools.h" 7 | 8 | namespace seq { 9 | namespace ir { 10 | namespace transform { 11 | namespace pythonic { 12 | namespace { 13 | struct InspectionResult { 14 | bool valid = true; 15 | std::vector args; 16 | }; 17 | 18 | bool isString(Value *v) { 19 | auto *M = v->getModule(); 20 | return v->getType()->is(M->getStringType()); 21 | } 22 | 23 | void inspect(Value *v, InspectionResult &r) { 24 | // check if add first then go from there 25 | if (isString(v)) { 26 | if (auto *c = cast(v)) { 27 | auto *func = util::getFunc(c->getCallee()); 28 | if (func && func->getUnmangledName() == "__add__" && 29 | std::distance(c->begin(), c->end()) == 2 && isString(c->front()) && 30 | isString(c->back())) { 31 | inspect(c->front(), r); 32 | inspect(c->back(), r); 33 | return; 34 | } 35 | } 36 | r.args.push_back(v); 37 | } else { 38 | r.valid = false; 39 | } 40 | } 41 | } // namespace 42 | 43 | const std::string StrAdditionOptimization::KEY = "core-pythonic-str-addition-opt"; 44 | 45 | void StrAdditionOptimization::handle(CallInstr *v) { 46 | auto *M = v->getModule(); 47 | 48 | auto *f = util::getFunc(v->getCallee()); 49 | if (!f || f->getUnmangledName() != "__add__") 50 | return; 51 | 52 | InspectionResult r; 53 | inspect(v, r); 54 | 55 | if (r.valid && r.args.size() > 2) { 56 | std::vector args; 57 | util::CloneVisitor cv(M); 58 | 59 | for (auto *arg : r.args) { 60 | args.push_back(cv.clone(arg)); 61 | } 62 | 63 | auto *arg = util::makeTuple(args, M); 64 | args = {arg}; 65 | auto *replacementFunc = 66 | M->getOrRealizeMethod(M->getStringType(), "cat", {arg->getType()}); 67 | seqassert(replacementFunc, "could not find cat function"); 68 | v->replaceAll(util::call(replacementFunc, args)); 69 | } 70 | } 71 | 72 | } // namespace pythonic 73 | } // namespace transform 74 | } // namespace ir 75 | } // namespace seq 76 | -------------------------------------------------------------------------------- /compiler/sir/transform/pythonic/str.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "sir/transform/pass.h" 4 | 5 | namespace seq { 6 | namespace ir { 7 | namespace transform { 8 | namespace pythonic { 9 | 10 | /// Pass to optimize str1 + str2 + ... 11 | class StrAdditionOptimization : public OperatorPass { 12 | public: 13 | static const std::string KEY; 14 | std::string getKey() const override { return KEY; } 15 | void handle(CallInstr *v) override; 16 | }; 17 | 18 | } // namespace pythonic 19 | } // namespace transform 20 | } // namespace ir 21 | } // namespace seq 22 | -------------------------------------------------------------------------------- /compiler/sir/transform/rewrite.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "sir/transform/pass.h" 4 | #include "sir/util/visitor.h" 5 | 6 | namespace seq { 7 | namespace ir { 8 | namespace transform { 9 | 10 | /// Base for rewrite rules. 11 | class RewriteRule : public util::Visitor { 12 | private: 13 | Value *result = nullptr; 14 | 15 | protected: 16 | void defaultVisit(Node *) override {} 17 | void setResult(Value *r) { result = r; } 18 | void resetResult() { setResult(nullptr); } 19 | Value *getResult() const { return result; } 20 | 21 | public: 22 | virtual ~RewriteRule() noexcept = default; 23 | 24 | /// Apply the rule. 25 | /// @param v the value to rewrite 26 | /// @return nullptr if no rewrite, the replacement otherwise 27 | Value *apply(Value *v) { 28 | v->accept(*this); 29 | auto *replacement = getResult(); 30 | resetResult(); 31 | return replacement; 32 | } 33 | }; 34 | 35 | /// A collection of rewrite rules. 36 | class Rewriter { 37 | private: 38 | std::unordered_map> rules; 39 | int numReplacements = 0; 40 | 41 | public: 42 | /// Adds a given rewrite rule with the given key. 43 | /// @param key the rule's key 44 | /// @param rule the rewrite rule 45 | void registerRule(const std::string &key, std::unique_ptr rule) { 46 | rules.emplace(std::make_pair(key, std::move(rule))); 47 | } 48 | 49 | /// Applies all rewrite rules to the given node, and replaces the given 50 | /// node with the result of the rewrites. 51 | /// @param v the node to rewrite 52 | void rewrite(Value *v) { 53 | Value *result = v; 54 | for (auto &r : rules) { 55 | if (auto *rep = r.second->apply(result)) { 56 | ++numReplacements; 57 | result = rep; 58 | } 59 | } 60 | if (v != result) 61 | v->replaceAll(result); 62 | } 63 | 64 | /// @return the number of replacements 65 | int getNumReplacements() const { return numReplacements; } 66 | 67 | /// Sets the replacement count to zero. 68 | void reset() { numReplacements = 0; } 69 | }; 70 | 71 | } // namespace transform 72 | } // namespace ir 73 | } // namespace seq 74 | -------------------------------------------------------------------------------- /compiler/sir/util/context.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace seq { 6 | namespace ir { 7 | namespace util { 8 | 9 | /// Base for SIR visitor contexts. 10 | template class SIRContext { 11 | private: 12 | std::vector frames; 13 | 14 | public: 15 | /// Emplaces a frame onto the stack. 16 | /// @param args a parameter pack of the arguments 17 | template void emplaceFrame(Args... args) { 18 | frames.emplace_back(args...); 19 | } 20 | /// Replaces a frame. 21 | /// @param newFrame the new frame 22 | void replaceFrame(Frame newFrame) { 23 | frames.pop_back(); 24 | frames.push_back(newFrame); 25 | } 26 | /// @return all frames 27 | std::vector &getFrames() { return frames; } 28 | /// @return the current frame 29 | Frame &getFrame() { return frames.back(); } 30 | /// Pops a frame. 31 | void popFrame() { return frames.pop_back(); } 32 | }; 33 | 34 | } // namespace util 35 | } // namespace ir 36 | } // namespace seq 37 | -------------------------------------------------------------------------------- /compiler/sir/util/format.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "sir/sir.h" 6 | 7 | namespace seq { 8 | namespace ir { 9 | namespace util { 10 | 11 | /// Formats an IR node. 12 | /// @param node the node 13 | /// @return the formatted node 14 | std::string format(const Node *node); 15 | 16 | /// Formats an IR node to an IO stream. 17 | /// @param os the output stream 18 | /// @param node the node 19 | /// @return the resulting output stream 20 | std::ostream &format(std::ostream &os, const Node *node); 21 | 22 | } // namespace util 23 | } // namespace ir 24 | } // namespace seq 25 | -------------------------------------------------------------------------------- /compiler/sir/util/inlining.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "sir/sir.h" 4 | 5 | namespace seq { 6 | namespace ir { 7 | namespace util { 8 | 9 | /// Result of an inlining operation. 10 | struct InlineResult { 11 | /// the result, either a SeriesFlow or FlowInstr 12 | Value *result; 13 | /// variables added by the inlining 14 | std::vector newVars; 15 | 16 | operator bool() const { return bool(result); } 17 | }; 18 | 19 | /// Inline the given function with the supplied arguments. 20 | /// @param func the function 21 | /// @param args the arguments 22 | /// @param callInfo the call information 23 | /// @param aggressive true if should inline complex functions 24 | /// @return the inlined result, nullptr if unsuccessful 25 | InlineResult inlineFunction(Func *func, std::vector args, 26 | bool aggressive = false, seq::SrcInfo callInfo = {}); 27 | 28 | /// Inline the given call. 29 | /// @param v the instruction 30 | /// @param aggressive true if should inline complex functions 31 | /// @return the inlined result, nullptr if unsuccessful 32 | InlineResult inlineCall(CallInstr *v, bool aggressive = false); 33 | 34 | } // namespace util 35 | } // namespace ir 36 | } // namespace seq 37 | -------------------------------------------------------------------------------- /compiler/sir/util/matching.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "sir/sir.h" 4 | 5 | namespace seq { 6 | namespace ir { 7 | namespace util { 8 | 9 | /// Base class for IR nodes that match anything. 10 | class Any {}; 11 | 12 | /// Any type. 13 | class AnyType : public AcceptorExtend, public Any { 14 | public: 15 | static const char NodeId; 16 | using AcceptorExtend::AcceptorExtend; 17 | 18 | private: 19 | bool doIsAtomic() const override { return true; } 20 | }; 21 | 22 | /// Any value. 23 | class AnyValue : public AcceptorExtend, public Any { 24 | public: 25 | static const char NodeId; 26 | using AcceptorExtend::AcceptorExtend; 27 | 28 | private: 29 | types::Type *doGetType() const override { return getModule()->getVoidType(); } 30 | }; 31 | 32 | /// Any flow. 33 | class AnyFlow : public AcceptorExtend, public Any { 34 | public: 35 | static const char NodeId; 36 | using AcceptorExtend::AcceptorExtend; 37 | }; 38 | 39 | /// Any variable. 40 | class AnyVar : public AcceptorExtend, public Any { 41 | public: 42 | static const char NodeId; 43 | using AcceptorExtend::AcceptorExtend; 44 | }; 45 | 46 | /// Any function. 47 | class AnyFunc : public AcceptorExtend, public Any { 48 | public: 49 | static const char NodeId; 50 | using AcceptorExtend::AcceptorExtend; 51 | 52 | AnyFunc() : AcceptorExtend() { setUnmangledName("any"); } 53 | }; 54 | 55 | /// Checks if IR nodes match. 56 | /// @param a the first IR node 57 | /// @param b the second IR node 58 | /// @param checkNames whether or not to check the node names 59 | /// @param varIdMatch whether or not variable ids must match 60 | /// @return true if the nodes are equal 61 | bool match(Node *a, Node *b, bool checkNames = false, bool varIdMatch = false); 62 | 63 | } // namespace util 64 | } // namespace ir 65 | } // namespace seq 66 | -------------------------------------------------------------------------------- /compiler/sir/util/packs.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace seq { 6 | namespace ir { 7 | namespace util { 8 | 9 | /// Utility function to strip parameter packs. 10 | /// @param dst the destination vector 11 | /// @param first the value 12 | template 13 | void stripPack(std::vector &dst, Desired &first) { 14 | dst.push_back(&first); 15 | } 16 | 17 | /// Utility function to strip parameter packs. 18 | /// @param dst the destination vector 19 | template void stripPack(std::vector &dst) {} 20 | 21 | /// Utility function to strip parameter packs. 22 | /// @param dst the destination vector 23 | /// @param first the value 24 | /// @param args the argument pack 25 | template 26 | void stripPack(std::vector &dst, Desired &first, Args &&...args) { 27 | dst.push_back(&first); 28 | stripPack(dst, std::forward(args)...); 29 | } 30 | 31 | } // namespace util 32 | } // namespace ir 33 | } // namespace seq 34 | -------------------------------------------------------------------------------- /compiler/sir/var.cpp: -------------------------------------------------------------------------------- 1 | #include "var.h" 2 | 3 | #include "module.h" 4 | 5 | namespace seq { 6 | namespace ir { 7 | 8 | const char Var::NodeId = 0; 9 | 10 | int Var::doReplaceUsedType(const std::string &name, types::Type *newType) { 11 | if (type->getName() == name) { 12 | type = newType; 13 | return 1; 14 | } 15 | return 0; 16 | } 17 | 18 | const char VarValue::NodeId = 0; 19 | 20 | int VarValue::doReplaceUsedVariable(id_t id, Var *newVar) { 21 | if (val->getId() == id) { 22 | val = newVar; 23 | return 1; 24 | } 25 | return 0; 26 | } 27 | 28 | const char PointerValue::NodeId = 0; 29 | 30 | types::Type *PointerValue::doGetType() const { 31 | return getModule()->getPointerType(val->getType()); 32 | } 33 | 34 | int PointerValue::doReplaceUsedVariable(id_t id, Var *newVar) { 35 | if (val->getId() == id) { 36 | val = newVar; 37 | return 1; 38 | } 39 | return 0; 40 | } 41 | 42 | } // namespace ir 43 | } // namespace seq 44 | -------------------------------------------------------------------------------- /compiler/util/common.cpp: -------------------------------------------------------------------------------- 1 | #include "common.h" 2 | #include 3 | #include 4 | 5 | namespace seq { 6 | namespace { 7 | void compilationMessage(const std::string &header, const std::string &msg, 8 | const std::string &file, int line, int col) { 9 | assert(!(file.empty() && (line > 0 || col > 0))); 10 | assert(!(col > 0 && line <= 0)); 11 | std::cerr << "\033[1m"; 12 | if (!file.empty()) 13 | std::cerr << file.substr(file.rfind('/') + 1); 14 | if (line > 0) 15 | std::cerr << ":" << line; 16 | if (col > 0) 17 | std::cerr << ":" << col; 18 | if (!file.empty()) 19 | std::cerr << ": "; 20 | std::cerr << header << "\033[1m " << msg << "\033[0m" << std::endl; 21 | } 22 | } // namespace 23 | 24 | void compilationError(const std::string &msg, const std::string &file, int line, 25 | int col, bool terminate) { 26 | compilationMessage("\033[1;31merror:\033[0m", msg, file, line, col); 27 | if (terminate) 28 | exit(EXIT_FAILURE); 29 | } 30 | 31 | void compilationWarning(const std::string &msg, const std::string &file, int line, 32 | int col, bool terminate) { 33 | compilationMessage("\033[1;33mwarning:\033[0m", msg, file, line, col); 34 | if (terminate) 35 | exit(EXIT_FAILURE); 36 | } 37 | } // namespace seq 38 | 39 | void _seqassert(const char *expr_str, const char *file, int line, 40 | const std::string &msg) { 41 | std::cerr << "Assert failed:\t" << msg << "\n" 42 | << "Expression:\t" << expr_str << "\n" 43 | << "Source:\t\t" << file << ":" << line << "\n"; 44 | abort(); 45 | } 46 | -------------------------------------------------------------------------------- /compiler/util/fmt/posix.h: -------------------------------------------------------------------------------- 1 | #include "os.h" 2 | #warning "fmt/posix.h is deprecated; use fmt/os.h instead" 3 | -------------------------------------------------------------------------------- /docs/doxygen/Doxyfile: -------------------------------------------------------------------------------- 1 | PROJECT_NAME = "seq" 2 | XML_OUTPUT = xml 3 | INPUT = ../../compiler/include ../../compiler/lang ../../compiler/types ../../compiler/util 4 | STRIP_FROM_PATH = ../.. 5 | GENERATE_LATEX = NO 6 | GENERATE_MAN = NO 7 | GENERATE_RTF = NO 8 | CASE_SENSE_NAMES = NO 9 | GENERATE_XML = YES 10 | GENERATE_HTML = YES 11 | RECURSIVE = YES 12 | QUIET = YES 13 | JAVADOC_AUTOBRIEF = YES 14 | WARN_IF_UNDOCUMENTED = NO 15 | 16 | -------------------------------------------------------------------------------- /docs/doxygen/html/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /docs/doxygen/xml/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /docs/images/prefetch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seq-lang/seq/0c275584163c172e5e7f20562c314991ed3bcf37/docs/images/prefetch.png -------------------------------------------------------------------------------- /docs/sphinx/Makefile: -------------------------------------------------------------------------------- 1 | # Minimal makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line. 5 | SPHINXOPTS = 6 | SPHINXBUILD = sphinx-build 7 | SPHINXPROJ = seq 8 | SOURCEDIR = . 9 | BUILDDIR = _build 10 | 11 | # Put it first so that "make" without argument is like "make help". 12 | help: 13 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 14 | 15 | .PHONY: help Makefile clean 16 | 17 | # Catch-all target: route all unknown targets to Sphinx using the new 18 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 19 | %: Makefile 20 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 21 | 22 | clean: 23 | rm -rf ../doxygen/xml/* api/ 24 | @$(SPHINXBUILD) -M clean "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 25 | -------------------------------------------------------------------------------- /docs/sphinx/_static/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seq-lang/seq/0c275584163c172e5e7f20562c314991ed3bcf37/docs/sphinx/_static/.gitkeep -------------------------------------------------------------------------------- /docs/sphinx/_templates/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seq-lang/seq/0c275584163c172e5e7f20562c314991ed3bcf37/docs/sphinx/_templates/.gitkeep -------------------------------------------------------------------------------- /docs/sphinx/build.rst: -------------------------------------------------------------------------------- 1 | Building from Source 2 | ==================== 3 | 4 | Unless you really need to build Seq for whatever reason, we strongly 5 | recommend using pre-built binaries if possible. 6 | 7 | Dependencies 8 | ------------ 9 | 10 | Seq depends on LLVM 12, which can be installed via most package managers. To 11 | build LLVM 12 yourself, you can do the following: 12 | 13 | .. code-block:: bash 14 | 15 | git clone --depth 1 -b release/12.x https://github.com/llvm/llvm-project 16 | mkdir -p llvm-project/llvm/build 17 | cd llvm-project/llvm/build 18 | cmake .. \ 19 | -DCMAKE_BUILD_TYPE=Release \ 20 | -DLLVM_INCLUDE_TESTS=OFF \ 21 | -DLLVM_ENABLE_RTTI=ON \ 22 | -DLLVM_ENABLE_ZLIB=OFF \ 23 | -DLLVM_ENABLE_TERMINFO=OFF \ 24 | -DLLVM_TARGETS_TO_BUILD=host 25 | make 26 | make install 27 | 28 | Build 29 | ----- 30 | 31 | The following can generally be used to build Seq. The build process will automatically 32 | download and build several smaller dependencies. 33 | 34 | .. code-block:: bash 35 | 36 | mkdir build 37 | (cd build && cmake .. -DCMAKE_BUILD_TYPE=Release \ 38 | -DLLVM_DIR=$(llvm-config --cmakedir) \ 39 | -DCMAKE_C_COMPILER=clang \ 40 | -DCMAKE_CXX_COMPILER=clang++) 41 | cmake --build build --config Release 42 | 43 | This should produce the ``seqc`` executable in the ``build`` directory, as well as 44 | ``seqtest`` which runs the test suite. 45 | -------------------------------------------------------------------------------- /docs/sphinx/embed.rst: -------------------------------------------------------------------------------- 1 | Calling Seq from C/C++ 2 | ====================== 3 | 4 | Calling C/C++ from Seq is quite easy with ``from C import``, but Seq can also be called from C/C++ code. To make a Seq function externally visible, simply annotate it with ``@export``: 5 | 6 | .. code-block:: seq 7 | 8 | @export 9 | def foo(n: int): 10 | for i in range(n): 11 | print(i * i) 12 | return n * n 13 | 14 | Note that only top-level, non-generic functions can be exported. Now we can create a shared library containing ``foo`` (assuming source file *foo.seq*): 15 | 16 | .. code-block:: bash 17 | 18 | seqc build -o foo.o foo.seq 19 | gcc -shared -lseqrt -lomp foo.o -o libfoo.so 20 | 21 | (The last command might require an additional ``-L/path/to/seqrt/lib/`` argument if ``libseqrt`` is not installed on a standard path.) 22 | 23 | Now we can call ``foo`` from a C program: 24 | 25 | .. code-block:: C 26 | 27 | #include 28 | #include 29 | 30 | int64_t foo(int64_t); 31 | 32 | int main() { 33 | printf("%llu\n", foo(10)); 34 | } 35 | 36 | Compile: 37 | 38 | .. code-block:: bash 39 | 40 | gcc -o foo -L. -lfoo foo.c 41 | 42 | Now running ``./foo`` should invoke ``foo()`` as defined in Seq, with an argument of ``10``. 43 | 44 | Converting types 45 | ---------------- 46 | 47 | The following table shows the conversions between Seq and C/C++ types: 48 | 49 | ============ ============ 50 | Seq C/C++ 51 | ------------ ------------ 52 | ``int`` ``int64_t`` 53 | ``float`` ``double`` 54 | ``bool`` ``bool`` 55 | ``byte`` ``int8_t`` 56 | ``str`` ``{int64_t, char*}`` 57 | ``seq`` ``{int64_t, char*}`` 58 | ``class`` Pointer to corresponding tuple 59 | ``@tuple`` Struct of fields 60 | ============ ============ 61 | -------------------------------------------------------------------------------- /docs/sphinx/intro.rst: -------------------------------------------------------------------------------- 1 | Getting Started 2 | =============== 3 | 4 | Install 5 | ------- 6 | 7 | Pre-built binaries 8 | ^^^^^^^^^^^^^^^^^^ 9 | 10 | Pre-built binaries for Linux and macOS on x86_64 are available alongside `each release `_. We also have a script for downloading and installing pre-built versions: 11 | 12 | .. code-block:: bash 13 | 14 | /bin/bash -c "$(curl -fsSL https://seq-lang.org/install.sh)" 15 | 16 | This will install Seq in a new ``.seq`` directory within your home directory. 17 | 18 | Building from source 19 | ^^^^^^^^^^^^^^^^^^^^ 20 | 21 | See `Building from Source `_. 22 | 23 | Usage 24 | ----- 25 | 26 | The ``seqc`` program can either directly run Seq source in JIT mode: 27 | 28 | .. code-block:: bash 29 | 30 | seqc run myprogram.seq 31 | 32 | The default compilation and run mode is *debug* (``-debug``). Compile and run with optimizations with the ``-release`` option: 33 | 34 | .. code-block:: bash 35 | 36 | seqc run -release myprogram.seq 37 | 38 | ``seqc`` can also produce executables (ensure you have ``clang`` installed, as it is used for linking): 39 | 40 | .. code-block:: bash 41 | 42 | # generate 'myprogram' executable 43 | seqc build -exe myprogram.seq 44 | 45 | # generate 'foo' executable 46 | seqc build -o foo myprogram.seq 47 | 48 | ``seqc`` can produce object files: 49 | 50 | .. code-block:: bash 51 | 52 | # generate 'myprogram.o' object file 53 | seqc build -obj myprogram.seq 54 | 55 | # generate 'foo.o' object file 56 | seqc build -o foo.o myprogram.seq 57 | 58 | ``seqc`` can produce LLVM IR: 59 | 60 | .. code-block:: bash 61 | 62 | # generate 'myprogram.ll' object file 63 | seqc build -llvm myprogram.seq 64 | 65 | # generate 'foo.ll' object file 66 | seqc build -o foo.ll myprogram.seq 67 | 68 | Compile-time definitions 69 | ------------------------ 70 | 71 | ``seqc`` allows for compile-time definitions via the ``-D`` flag. For example, in the following code: 72 | 73 | .. code-block:: seq 74 | 75 | from bio import * 76 | print(Kmer[SEED_LEN]()) 77 | 78 | ``SEED_LEN`` can be specified on the command line as such: ``seqc run -DSEED_LEN=10 myprogram.seq``. 79 | -------------------------------------------------------------------------------- /docs/sphinx/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seq-lang/seq/0c275584163c172e5e7f20562c314991ed3bcf37/docs/sphinx/logo.png -------------------------------------------------------------------------------- /docs/sphinx/make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | pushd %~dp0 4 | 5 | REM Command file for Sphinx documentation 6 | 7 | if "%SPHINXBUILD%" == "" ( 8 | set SPHINXBUILD=sphinx-build 9 | ) 10 | set SOURCEDIR=. 11 | set BUILDDIR=_build 12 | set SPHINXPROJ=seq 13 | 14 | if "%1" == "" goto help 15 | 16 | %SPHINXBUILD% >NUL 2>NUL 17 | if errorlevel 9009 ( 18 | echo. 19 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx 20 | echo.installed, then set the SPHINXBUILD environment variable to point 21 | echo.to the full path of the 'sphinx-build' executable. Alternatively you 22 | echo.may add the Sphinx directory to PATH. 23 | echo. 24 | echo.If you don't have Sphinx installed, grab it from 25 | echo.http://sphinx-doc.org/ 26 | exit /b 1 27 | ) 28 | 29 | %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% 30 | goto end 31 | 32 | :help 33 | %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% 34 | 35 | :end 36 | popd 37 | -------------------------------------------------------------------------------- /docs/sphinx/python.rst: -------------------------------------------------------------------------------- 1 | Calling Python from Seq 2 | ======================= 3 | 4 | Calling Python from Seq is possible in two ways: 5 | 6 | - ``from python import`` allows importing and calling Python functions from existing Python modules. 7 | - ``@python`` allows writing Python code directly in Seq. 8 | 9 | In order to use these features, the ``SEQ_PYTHON`` environment variable must be set to the appropriate 10 | Python shared library: 11 | 12 | .. code-block:: bash 13 | 14 | export SEQ_PYTHON=/path/to/libpython.X.Y.so 15 | 16 | For example, with a ``brew``-installed Python 3.9 on macOS, this might be 17 | 18 | .. code-block:: bash 19 | 20 | /usr/local/opt/python@3.9/Frameworks/Python.framework/Versions/3.9/lib/libpython3.9.dylib 21 | 22 | Note that only Python versions 3.6 and later are supported. 23 | 24 | ``from python import`` 25 | ---------------------- 26 | 27 | Let's say we have a Python function defined in *mymodule.py*: 28 | 29 | .. code-block:: python 30 | 31 | def multiply(a, b): 32 | return a * b 33 | 34 | We can call this function in Seq using ``from python import`` and indicating the appropriate 35 | call and return types: 36 | 37 | .. code-block:: seq 38 | 39 | from python import mymodule.multiply(int, int) -> int 40 | print(multiply(3, 4)) # 12 41 | 42 | (Be sure the ``PYTHONPATH`` environment variable includes the path of *mymodule.py*!) 43 | 44 | ``@python`` 45 | ----------- 46 | 47 | Seq programs can contain functions that will be executed by Python via ``pydef``: 48 | 49 | .. code-block:: seq 50 | 51 | @python 52 | def multiply(a: int, b: int) -> int: 53 | return a * b 54 | 55 | print(multiply(3, 4)) # 12 56 | 57 | This makes calling Python modules like NumPy very easy: 58 | 59 | .. code-block:: seq 60 | 61 | @python 62 | def myrange(n: int) -> List[int]: 63 | from numpy import arange 64 | return list(arange(n)) 65 | 66 | print(myrange(5)) # [0, 1, 2, 3, 4] 67 | -------------------------------------------------------------------------------- /docs/sphinx/tutorial/index.rst: -------------------------------------------------------------------------------- 1 | Tutorial 2 | ======== 3 | 4 | .. toctree:: 5 | :maxdepth: 1 6 | 7 | setup 8 | primer 9 | tutorial 10 | workshop 11 | -------------------------------------------------------------------------------- /docs/sphinx/tutorial/setup.rst: -------------------------------------------------------------------------------- 1 | Setup 2 | ===== 3 | 4 | Installation 5 | ------------ 6 | 7 | Simple! 8 | 9 | .. code:: bash 10 | 11 | /bin/bash -c "$(curl -fsSL https://seq-lang.org/install.sh)" 12 | 13 | If you want to use Python interop, you also need to point 14 | ``SEQ_PYTHON`` to the Python library (typically called 15 | ``libpython3.9m.so`` or similar). The Seq repository contains a 16 | `Python script `_ 17 | that will identify and print the path to this library. 18 | 19 | Usage 20 | ----- 21 | 22 | Assuming that Seq was properly installed, you can use it as follows: 23 | 24 | .. code:: bash 25 | 26 | seqc run foo.seq # Compile and run foo.seq 27 | seqc run -release foo.seq # Compile and run foo.seq with optimizations 28 | seqc build -exe file.seq # Compile foo.seq to executable "foo" 29 | 30 | Note that the ``-exe`` option requires ``clang`` to be installed, and 31 | the ``LIBRARY_PATH`` environment variable to point to the Seq runtime 32 | library (installed by default at ``~/.seq/lib/seq``). 33 | -------------------------------------------------------------------------------- /docs/workshop/section1.seq: -------------------------------------------------------------------------------- 1 | # SeqMap 2 | # Seq workshop -- Section 1 3 | # Reads and prints a FASTQ file. 4 | # Usage: seqc run section1.seq 5 | from sys import argv 6 | from bio import * 7 | for record in FASTQ(argv[1]): 8 | print(record.name, record.seq) 9 | -------------------------------------------------------------------------------- /docs/workshop/section2.seq: -------------------------------------------------------------------------------- 1 | # SeqMap 2 | # Seq workshop -- Section 2 3 | # Reads and constructs a hash table index from an input 4 | # FASTA file. 5 | # Usage: seqc run section2.seq 6 | from sys import argv 7 | from bio import * 8 | import pickle 9 | import gzip 10 | 11 | index = {} 12 | 13 | for record in FASTA(argv[1]): 14 | for pos,kmer in record.seq.kmers_with_pos(k=32, step=1): 15 | index[min(kmer, ~kmer)] = pos 16 | 17 | with gzip.open(argv[1] + '.index', 'wb') as jar: 18 | pickle.dump(index, jar) 19 | -------------------------------------------------------------------------------- /docs/workshop/section3.seq: -------------------------------------------------------------------------------- 1 | # SeqMap 2 | # Seq workshop -- Section 3 3 | # Reads index constructed in Section 2 and looks up k-mers from 4 | # input reads to find candidate mappings. 5 | # Usage: seqc run section3.seq 6 | from sys import argv 7 | from bio import * 8 | import pickle 9 | import gzip 10 | 11 | K: Static[int] = 32 12 | index = None 13 | 14 | with gzip.open(argv[1] + '.index', 'rb') as jar: 15 | index = pickle.load(jar, T=Dict[Kmer[K],int]) 16 | 17 | candidates = {} # position -> count mapping 18 | for record in FASTQ(argv[2]): 19 | for pos,kmer in record.read.kmers_with_pos(k=K, step=1): 20 | found = index.get(min(kmer, ~kmer), -1) 21 | if found > 0: 22 | loc = found - pos 23 | candidates[loc] = candidates.get(loc, 0) + 1 24 | 25 | for pos,count in candidates.items(): 26 | if count > 1: 27 | print(record.name, pos + 1) 28 | 29 | candidates.clear() 30 | -------------------------------------------------------------------------------- /docs/workshop/section4.seq: -------------------------------------------------------------------------------- 1 | # SeqMap 2 | # Seq workshop -- Section 4 3 | # Reads index constructed in Section 2 and looks up k-mers from 4 | # input reads to find candidate mappings, then performs alignment. 5 | # Usage: seqc run section4.seq 6 | from sys import argv 7 | from bio import * 8 | import pickle 9 | import gzip 10 | 11 | reference = s'' 12 | for record in FASTA(argv[1]): 13 | reference = record.seq 14 | 15 | K: Static[int] = 32 16 | index = None 17 | 18 | with gzip.open(argv[1] + '.index', 'rb') as jar: 19 | index = pickle.load(jar, T=Dict[Kmer[K],int]) 20 | 21 | candidates = {} # position -> count mapping 22 | for record in FASTQ(argv[2]): 23 | for pos,kmer in record.read.kmers_with_pos(k=K, step=1): 24 | found = index.get(min(kmer, ~kmer), -1) 25 | if found > 0: 26 | loc = found - pos 27 | candidates[loc] = candidates.get(loc, 0) + 1 28 | 29 | for pos,count in candidates.items(): 30 | if count > 1: 31 | query = record.read 32 | target = reference[pos:pos + len(query)] 33 | alignment = query.align(target) 34 | print(record.name, pos + 1, alignment.score, alignment.cigar) 35 | 36 | candidates.clear() 37 | -------------------------------------------------------------------------------- /docs/workshop/section5.seq: -------------------------------------------------------------------------------- 1 | # SeqMap 2 | # Seq workshop -- Section 5 3 | # Reads index constructed in Section 2 and looks up k-mers from 4 | # input reads to find candidate mappings, then performs alignment. 5 | # Implemented with Seq pipelines. 6 | # Usage: seqc run section5.seq 7 | from sys import argv 8 | from time import timing 9 | from bio import * 10 | import pickle 11 | import gzip 12 | 13 | reference = s'' 14 | for record in FASTA(argv[1]): 15 | reference = record.seq 16 | 17 | K: Static[int] = 32 18 | index = None 19 | 20 | with gzip.open(argv[1] + '.index', 'rb') as jar: 21 | index = pickle.load(jar, T=Dict[Kmer[K],int]) 22 | 23 | def find_candidates(record): 24 | candidates = {} # position -> count mapping 25 | for pos,kmer in record.read.kmers_with_pos(k=K, step=1): 26 | found = index.get(min(kmer, ~kmer), -1) 27 | if found > 0: 28 | loc = found - pos 29 | candidates[loc] = candidates.get(loc, 0) + 1 30 | for pos,count in candidates.items(): 31 | if count > 1: 32 | yield record, pos 33 | 34 | def align_and_output(t): 35 | record, pos = t 36 | query = record.read 37 | target = reference[pos:pos + len(query)] 38 | alignment = query.align(target) 39 | print(record.name, pos + 1, alignment.score, alignment.cigar) 40 | 41 | with timing('mapping'): 42 | FASTQ(argv[2]) |> iter |> find_candidates |> align_and_output 43 | -------------------------------------------------------------------------------- /docs/workshop/section6.seq: -------------------------------------------------------------------------------- 1 | # SeqMap 2 | # Seq workshop -- Section 6 3 | # Reads index constructed in Section 2 and looks up k-mers from 4 | # input reads to find candidate mappings, then performs alignment. 5 | # Implemented with Seq pipelines using inter-seq. alignment. 6 | # Usage: seqc run section6.seq 7 | from sys import argv 8 | from time import timing 9 | from bio import * 10 | import pickle 11 | import gzip 12 | 13 | reference = s'' 14 | for record in FASTA(argv[1]): 15 | reference = record.seq 16 | 17 | K: Static[int] = 32 18 | index = None 19 | 20 | with gzip.open(argv[1] + '.index', 'rb') as jar: 21 | index = pickle.load(jar, T=Dict[Kmer[K],int]) 22 | 23 | def find_candidates(record): 24 | candidates = {} # position -> count mapping 25 | for pos,kmer in record.read.kmers_with_pos(k=K, step=1): 26 | found = index.get(min(kmer, ~kmer), -1) 27 | if found > 0: 28 | loc = found - pos 29 | candidates[loc] = candidates.get(loc, 0) + 1 30 | for pos,count in candidates.items(): 31 | if count > 1: 32 | yield record, pos 33 | 34 | @inter_align 35 | def align_and_output(t): 36 | record, pos = t 37 | query = record.read 38 | target = reference[pos:pos + len(query)] 39 | alignment = query.align(target) 40 | print(record.name, pos + 1, alignment.score, alignment.cigar) 41 | 42 | with timing('mapping'): 43 | FASTQ(argv[2]) |> iter |> find_candidates |> align_and_output 44 | -------------------------------------------------------------------------------- /runtime/lib.h: -------------------------------------------------------------------------------- 1 | #ifndef SEQ_LIB_H 2 | #define SEQ_LIB_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #define SEQ_FUNC extern "C" 11 | 12 | typedef int64_t seq_int_t; 13 | 14 | struct seq_t { 15 | seq_int_t len; 16 | char *seq; 17 | }; 18 | 19 | struct seq_str_t { 20 | seq_int_t len; 21 | char *str; 22 | }; 23 | 24 | template struct seq_arr_t { 25 | seq_int_t len; 26 | T *arr; 27 | }; 28 | 29 | extern int debug; 30 | 31 | SEQ_FUNC void seq_init(int debug); 32 | SEQ_FUNC void seq_assert_failed(seq_str_t file, seq_int_t line); 33 | 34 | SEQ_FUNC void *seq_alloc(size_t n); 35 | SEQ_FUNC void *seq_alloc_atomic(size_t n); 36 | SEQ_FUNC void *seq_realloc(void *p, size_t n); 37 | SEQ_FUNC void seq_free(void *p); 38 | SEQ_FUNC void seq_register_finalizer(void *p, void (*f)(void *obj, void *data)); 39 | 40 | SEQ_FUNC void *seq_alloc_exc(int type, void *obj); 41 | SEQ_FUNC void seq_throw(void *exc); 42 | SEQ_FUNC _Unwind_Reason_Code seq_personality(int version, _Unwind_Action actions, 43 | uint64_t exceptionClass, 44 | _Unwind_Exception *exceptionObject, 45 | _Unwind_Context *context); 46 | SEQ_FUNC int64_t seq_exc_offset(); 47 | SEQ_FUNC uint64_t seq_exc_class(); 48 | 49 | SEQ_FUNC seq_str_t seq_str_int(seq_int_t n); 50 | SEQ_FUNC seq_str_t seq_str_uint(seq_int_t n); 51 | SEQ_FUNC seq_str_t seq_str_float(double f); 52 | SEQ_FUNC seq_str_t seq_str_bool(bool b); 53 | SEQ_FUNC seq_str_t seq_str_byte(char c); 54 | SEQ_FUNC seq_str_t seq_str_ptr(void *p); 55 | SEQ_FUNC seq_str_t seq_str_tuple(seq_str_t *strs, seq_int_t n); 56 | 57 | SEQ_FUNC void seq_print(seq_str_t str); 58 | SEQ_FUNC void seq_print_full(seq_str_t str, FILE *fo); 59 | 60 | template 61 | static seq_str_t string_conv(const char *fmt, const size_t size, T t) { 62 | auto *p = (char *)seq_alloc_atomic(size); 63 | int n = snprintf(p, size, fmt, t); 64 | if (n >= size) { 65 | auto n2 = (size_t)n + 1; 66 | p = (char *)seq_realloc((void *)p, n2); 67 | n = snprintf(p, n2, fmt, t); 68 | } 69 | return {(seq_int_t)n, p}; 70 | } 71 | 72 | #endif /* SEQ_LIB_H */ 73 | -------------------------------------------------------------------------------- /scripts/backtrace-support.h.cmake: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seq-lang/seq/0c275584163c172e5e7f20562c314991ed3bcf37/scripts/backtrace-support.h.cmake -------------------------------------------------------------------------------- /scripts/deps.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -e 3 | 4 | export INSTALLDIR="${PWD}/llvm" 5 | export SRCDIR="${PWD}/llvm-project" 6 | mkdir -p "${INSTALLDIR}" "${SRCDIR}" 7 | 8 | export JOBS=1 9 | if [ -n "${1}" ]; then export JOBS="${1}"; fi 10 | echo "Using ${JOBS} cores..." 11 | 12 | LLVM_BRANCH="release/12.x" 13 | if [ ! -f "${INSTALLDIR}/bin/llvm-config" ]; then 14 | git clone --depth 1 -b "${LLVM_BRANCH}" https://github.com/llvm/llvm-project "${SRCDIR}" 15 | 16 | # llvm 17 | mkdir -p "${SRCDIR}/llvm/build" 18 | cd "${SRCDIR}/llvm/build" 19 | cmake .. \ 20 | -DCMAKE_BUILD_TYPE=Release \ 21 | -DLLVM_INCLUDE_TESTS=OFF \ 22 | -DLLVM_ENABLE_RTTI=ON \ 23 | -DLLVM_ENABLE_ZLIB=OFF \ 24 | -DLLVM_ENABLE_TERMINFO=OFF \ 25 | -DLLVM_TARGETS_TO_BUILD=host \ 26 | -DCMAKE_INSTALL_PREFIX="${INSTALLDIR}" 27 | make -j "${JOBS}" 28 | make install 29 | 30 | # clang 31 | if ! command -v clang &> /dev/null; then 32 | mkdir -p "${SRCDIR}/clang/build" 33 | cd "${SRCDIR}/clang/build" 34 | cmake .. \ 35 | -DCMAKE_BUILD_TYPE=Release \ 36 | -DCMAKE_INSTALL_PREFIX="${INSTALLDIR}" 37 | make -j "${JOBS}" 38 | make install 39 | fi 40 | 41 | "${INSTALLDIR}/bin/llvm-config" --cmakedir 42 | fi 43 | -------------------------------------------------------------------------------- /scripts/install.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -e 3 | set -o pipefail 4 | 5 | SEQ_INSTALL_DIR=~/.seq 6 | OS=`uname -s | awk '{print tolower($0)}'` 7 | ARCH=`uname -m` 8 | 9 | if [ "$OS" != "linux" ] && [ "$OS" != "darwin" ]; then 10 | echo "error: Pre-built binaries only exist for Linux and macOS." >&2 11 | exit 1 12 | fi 13 | 14 | if [ "$ARCH" != "x86_64" ]; then 15 | echo "error: Pre-built binaries only exist for x86_64." >&2 16 | exit 1 17 | fi 18 | 19 | SEQ_BUILD_ARCHIVE=seq-$OS-$ARCH.tar.gz 20 | 21 | mkdir -p $SEQ_INSTALL_DIR 22 | cd $SEQ_INSTALL_DIR 23 | curl -L https://github.com/seq-lang/seq/releases/latest/download/$SEQ_BUILD_ARCHIVE | tar zxvf - --strip-components=1 24 | 25 | EXPORT_COMMAND="export PATH=`pwd`/bin:\$PATH" 26 | echo "PATH export command:" 27 | echo " $EXPORT_COMMAND" 28 | 29 | update_profile () { 30 | if ! grep -F -q "$EXPORT_COMMAND" $1; then 31 | read -p "Update PATH in $1? [y/n] " -n 1 -r 32 | echo 33 | 34 | if [[ $REPLY =~ ^[Yy]$ ]]; then 35 | echo "Updating $1" 36 | echo >> $1 37 | echo "# Seq compiler path (added by install script)" >> $1 38 | echo $EXPORT_COMMAND >> $1 39 | else 40 | echo "Skipping." 41 | fi 42 | else 43 | echo "PATH already updated in $1; skipping update." 44 | fi 45 | } 46 | 47 | if [[ "$SHELL" == *zsh ]]; then 48 | if [ -e ~/.zshenv ]; then 49 | update_profile ~/.zshenv 50 | elif [ -e ~/.zshrc ]; then 51 | update_profile ~/.zshrc 52 | else 53 | echo "Could not find zsh configuration file to update PATH" 54 | fi 55 | elif [[ "$SHELL" == *bash ]]; then 56 | if [ -e ~/.bash_profile ]; then 57 | update_profile ~/.bash_profile 58 | else 59 | echo "Could not find bash configuration file to update PATH" 60 | fi 61 | else 62 | echo "Don't know how to update configuration file for shell $SHELL" 63 | fi 64 | 65 | echo "Seq successfully installed at: `pwd`" 66 | echo "Open a new terminal session or update your PATH to use seqc" 67 | -------------------------------------------------------------------------------- /stdlib/algorithms/heapsort.seq: -------------------------------------------------------------------------------- 1 | def _heapify[S,T](arr: Array[T], begin: int, end: int, keyf: Callable[[T], S]): 2 | """ 3 | Makes the array a heap from [begin, end). 4 | """ 5 | root = begin 6 | left = 2 * begin + 1 7 | right = 2 * begin + 2 8 | 9 | if left < end and keyf(arr[root]) < keyf(arr[left]): 10 | root = left 11 | 12 | if right < end and keyf(arr[root]) < keyf(arr[right]): 13 | root = right 14 | 15 | if root != begin: 16 | arr[begin], arr[root] = arr[root], arr[begin] 17 | _heapify(arr, root, end, keyf) 18 | 19 | def _heap_sort[S,T](arr: Array[T], begin: int, end: int, keyf: Callable[[T], S]): 20 | if end - begin < 2: 21 | return 22 | 23 | arr = arr.slice(begin, end) 24 | end -= begin 25 | begin = 0 26 | 27 | i = end // 2 - 1 28 | while i >= 0: 29 | _heapify(arr, i, end, keyf) 30 | i -= 1 31 | 32 | i = end - 1 33 | while i >= 0: 34 | arr[i], arr[0] = arr[0], arr[i] 35 | _heapify(arr, 0, i, keyf) 36 | i -= 1 37 | 38 | def heap_sort_array[S,T](collection: Array[T], size: int, keyf: Callable[[T], S]): 39 | """ 40 | Heap Sort 41 | Sorts the array inplace. 42 | """ 43 | _heap_sort(collection, 0, size, keyf) 44 | 45 | def heap_sort_inplace[S,T](collection: List[T], keyf: Callable[[T], S]): 46 | """ 47 | Heap Sort 48 | Sorts the list inplace. 49 | """ 50 | heap_sort_array(collection.arr, collection.len, keyf) 51 | 52 | def heap_sort[S,T](collection: List[T], keyf: Callable[[T], S]) -> List[T]: 53 | """ 54 | Heap Sort 55 | Returns a sorted list. 56 | """ 57 | newlst = copy(collection) 58 | heap_sort_inplace(newlst, keyf) 59 | return newlst 60 | -------------------------------------------------------------------------------- /stdlib/algorithms/insertionsort.seq: -------------------------------------------------------------------------------- 1 | def _insertion_sort[S,T](arr: Array[T], begin: int, end: int, keyf: Callable[[T], S]): 2 | i = begin + 1 3 | while i < end: 4 | x = arr[i] 5 | j = i - 1 6 | while j >= begin and keyf(x) < keyf(arr[j]): 7 | arr[j+1] = arr[j] 8 | j -= 1 9 | arr[j+1] = x 10 | i += 1 11 | 12 | def insertion_sort_array[S,T](collection: Array[T], size: int, keyf: Callable[[T], S]): 13 | """ 14 | Insertion Sort 15 | Sorts the array inplace. 16 | """ 17 | _insertion_sort(collection, 0, size, keyf) 18 | 19 | def insertion_sort_inplace[S,T](collection: List[T], keyf: Callable[[T], S]): 20 | """ 21 | Insertion Sort 22 | Sorts the list inplace. 23 | """ 24 | insertion_sort_array(collection.arr, collection.len, keyf) 25 | 26 | def insertion_sort[S,T](collection: List[T], keyf: Callable[[T], S]) -> List[T]: 27 | """ 28 | Insertion Sort 29 | Returns the sorted list. 30 | """ 31 | newlst = copy(collection) 32 | insertion_sort_inplace(newlst, keyf) 33 | return newlst 34 | -------------------------------------------------------------------------------- /stdlib/bio/__init__.seq: -------------------------------------------------------------------------------- 1 | from bio.seq import * 2 | from bio.kmer import * 3 | from bio.pseq import * 4 | 5 | from bio.builtin import * 6 | 7 | from bio.block import Block, blocks 8 | from bio.locus import Locus 9 | from bio.iter import Seqs 10 | 11 | from bio.align import SubMat, CIGAR, Alignment 12 | from bio.pseq import pseq, translate 13 | from bio.bwt import _saisxx, _saisxx_bwt 14 | 15 | from bio.fasta import FASTARecord, FASTA, pFASTARecord, pFASTA 16 | from bio.fastq import FASTQRecord, FASTQ 17 | from bio.fai import FAIRecord, FAI 18 | from bio.bam import SAMRecord, SAM, BAM, CRAM 19 | from bio.bed import BEDRecord, BED 20 | from bio.vcf import VCFRecord, VCF, BCF 21 | 22 | from bio.prefetch import * 23 | from bio.types import * 24 | -------------------------------------------------------------------------------- /stdlib/bio/block.seq: -------------------------------------------------------------------------------- 1 | @tuple 2 | class Block[T]: 3 | ''' 4 | Represents a block of data; useful in parallelization to batch data 5 | ''' 6 | _data: Ptr[T] 7 | _size: int 8 | 9 | def __new__(size: int): 10 | return Block[T](Ptr[T](size), 0) 11 | 12 | def __iter__(self): 13 | data = self._data 14 | size = self._size 15 | i = 0 16 | while i < size: 17 | yield data[i] 18 | i += 1 19 | 20 | def __getitem__(self, idx: int): 21 | if not (0 <= idx < len(self)): 22 | raise ValueError("block index out of range") 23 | return self._data[idx] 24 | 25 | def __len__(self): 26 | return self._size 27 | 28 | def __bool__(self): 29 | return len(self) != 0 30 | 31 | def __str__(self): 32 | return f'' 33 | 34 | def _add(self, elem: T): 35 | self._data[self._size] = elem 36 | return Block[T](self._data, self._size + 1) 37 | 38 | def _blocks[T](g: Generator[T], size: int): 39 | b = Block[T](size) 40 | for a in g: 41 | if len(b) == size: 42 | yield b 43 | b = Block[T](size) 44 | b = b._add(a) 45 | if b: 46 | yield b 47 | 48 | def blocks(x, size: int): 49 | ''' 50 | Partitions the given object into blocks of the specified size 51 | by calling the `__blocks__` magic method. 52 | ''' 53 | if size <= 0: 54 | raise ValueError(f"invalid block size: {size}") 55 | if isinstance(x, Generator): 56 | return _blocks(x, size) 57 | else: 58 | return x.__blocks__(size) 59 | -------------------------------------------------------------------------------- /stdlib/bio/prefetch.seq: -------------------------------------------------------------------------------- 1 | @inline 2 | def _dynamic_coroutine_scheduler[A,B,T,C](value: A, coro: B, states: Array[Generator[T]], I: Ptr[int], N: Ptr[int], M: int, args: C): 3 | n = N[0] 4 | if n < M: 5 | states[n] = coro(value, *args) 6 | N[0] = n + 1 7 | else: 8 | i = I[0] 9 | while True: 10 | g = states[i] 11 | if g.done(): 12 | if not isinstance(T, void): 13 | yield g.next() 14 | g.destroy() 15 | states[i] = coro(value, *args) 16 | break 17 | i = (i + 1) & (M - 1) 18 | I[0] = i 19 | 20 | @inline 21 | def _dynamic_coroutine_scheduler_drain[T](states: Array[Generator[T]], N: int): 22 | i = 0 23 | while i < N: 24 | g = states[i] 25 | while not g.done(): 26 | g.next() 27 | if not isinstance(T, void): 28 | yield g.next() 29 | g.destroy() 30 | i += 1 31 | 32 | @inline 33 | def _dummy_prefetch_terminal_stage(x): 34 | pass 35 | -------------------------------------------------------------------------------- /stdlib/bio/types.seq: -------------------------------------------------------------------------------- 1 | @extend 2 | class byte: 3 | def comp(self) -> byte: 4 | _byte_comp_table = "NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN-.NNNNNNNNNNNNNNNNNNTVGHNNCDNNMNKNNNNYSAABWNRNNNNNNNtvghNNcdNNmNknNNNysaabwNrNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN" 5 | return _byte_comp_table.ptr[int(self)] 6 | 7 | @extend 8 | class Dict: 9 | def prefetch(self, key: K): 10 | if self._n_buckets: 11 | from internal.types.collections.dict import _dict_hash 12 | mask = self._n_buckets - 1 13 | k = _dict_hash(key) 14 | i = k & mask 15 | (self._keys + i).__prefetch_r1__() 16 | (self._vals + i).__prefetch_r1__() 17 | (self._flags + (i >> 4)).__prefetch_r1__() 18 | 19 | @extend 20 | class List: 21 | def prefetch(self, idx: int): 22 | (self.arr.ptr + idx).__prefetch_r3__() 23 | -------------------------------------------------------------------------------- /stdlib/functools.seq: -------------------------------------------------------------------------------- 1 | def partial(): # internal 2 | pass 3 | -------------------------------------------------------------------------------- /stdlib/gzip.seq: -------------------------------------------------------------------------------- 1 | def open(path: str, mode: str = 'r'): 2 | return gzFile(path, mode) 3 | -------------------------------------------------------------------------------- /stdlib/internal/__init__.seq: -------------------------------------------------------------------------------- 1 | # Core library 2 | 3 | from internal.attributes import * 4 | from internal.types.ptr import * 5 | from internal.types.str import * 6 | from internal.types.int import * 7 | from internal.types.bool import * 8 | from internal.types.array import * 9 | from internal.types.error import * 10 | from internal.types.intn import * 11 | from internal.types.float import * 12 | from internal.types.byte import * 13 | from internal.types.generator import * 14 | from internal.types.optional import * 15 | from internal.types.slice import * 16 | from internal.types.range import * 17 | from internal.internal import * 18 | 19 | from internal.types.collections.list import * 20 | from internal.types.collections.set import * 21 | from internal.types.collections.dict import * 22 | 23 | # Extended core library 24 | 25 | import internal.c_stubs as _C 26 | from internal.builtin import * 27 | from internal.box import Box 28 | from internal.str import * 29 | 30 | from internal.sort import sorted 31 | 32 | from openmp import Ident as __OMPIdent, for_par 33 | from internal.file import File, gzFile, open, gzopen 34 | from pickle import pickle, unpickle 35 | from internal.dlopen import dlsym as _dlsym 36 | import internal.python 37 | -------------------------------------------------------------------------------- /stdlib/internal/attributes.seq: -------------------------------------------------------------------------------- 1 | @__attribute__ 2 | def test(): 3 | pass 4 | 5 | @__attribute__ 6 | def export(): 7 | pass 8 | 9 | @__attribute__ 10 | def inline(): 11 | pass 12 | 13 | @__attribute__ 14 | def noinline(): 15 | pass 16 | 17 | @__attribute__ 18 | def pure(): 19 | pass 20 | 21 | @__attribute__ 22 | def nonpure(): 23 | pass 24 | 25 | @__attribute__ 26 | def commutative(): 27 | pass 28 | 29 | @__attribute__ 30 | def associative(): 31 | pass 32 | 33 | @__attribute__ 34 | def distributive(): 35 | pass 36 | 37 | @__attribute__ 38 | def C(): 39 | pass 40 | 41 | -------------------------------------------------------------------------------- /stdlib/internal/box.seq: -------------------------------------------------------------------------------- 1 | class Box[T]: 2 | val: T 3 | -------------------------------------------------------------------------------- /stdlib/internal/dlopen.seq: -------------------------------------------------------------------------------- 1 | @pure 2 | @C 3 | def seq_is_macos() -> bool: pass 4 | 5 | # 6 | from C import dlerror() -> cobj as c_dlerror 7 | from C import dlopen(cobj, int) -> cobj as c_dlopen 8 | from C import dlsym(cobj, cobj) -> cobj as c_dlsym 9 | from C import dlclose(cobj) -> i32 as c_dlclose 10 | RTLD_NOW = 2 11 | RTLD_GLOBAL = 8 if seq_is_macos() else 256 12 | 13 | def dlext(): 14 | if seq_is_macos(): 15 | return 'dylib' 16 | else: 17 | return 'so' 18 | 19 | @pure 20 | def dlerror(): 21 | return str.from_ptr(c_dlerror()) 22 | 23 | def dlopen(name: str, flag: int = RTLD_NOW | RTLD_GLOBAL) -> cobj: 24 | h = c_dlopen(cobj(0) if name == "" else name.c_str(), flag) 25 | if h == cobj(): 26 | raise CError(dlerror()) 27 | return h 28 | 29 | def dlsym[Fn](lib: str, name: str) -> Fn: 30 | h = dlopen(lib) 31 | fn = c_dlsym(h, name.c_str()) 32 | if fn == cobj(): 33 | raise CError(dlerror()) 34 | return Fn(fn) 35 | 36 | def dlclose(handle: cobj): 37 | if c_dlclose(handle) != i32(0): 38 | raise CError(dlerror()) 39 | 40 | -------------------------------------------------------------------------------- /stdlib/internal/gc.seq: -------------------------------------------------------------------------------- 1 | # Primarily for internal use. Regular users should not use this module. 2 | 3 | @pure 4 | @C 5 | def seq_alloc(a: int) -> cobj: pass 6 | @pure 7 | @C 8 | def seq_alloc_atomic(a: int) -> cobj: pass 9 | from C import seq_realloc(cobj, int) -> cobj 10 | from C import seq_free(cobj) 11 | from C import seq_gc_add_roots(cobj, cobj) 12 | from C import seq_gc_remove_roots(cobj, cobj) 13 | from C import seq_gc_clear_roots() 14 | from C import seq_gc_exclude_static_roots(cobj, cobj) 15 | from C import seq_register_finalizer(cobj, cobj) 16 | 17 | def sizeof(T: type): 18 | return T.__elemsize__ 19 | 20 | def atomic(T: type): 21 | return T.__atomic__ 22 | 23 | def alloc(sz: int): 24 | return seq_alloc(sz) 25 | 26 | # Allocates a block of memory via GC, where the 27 | # caller guarantees that this block will not store 28 | # pointers to other GC-allocated data. 29 | def alloc_atomic(sz: int): 30 | return seq_alloc_atomic(sz) 31 | 32 | def realloc(p: cobj, sz: int): 33 | return seq_realloc(p, sz) 34 | 35 | def free(p: cobj): 36 | seq_free(p) 37 | 38 | def add_roots(start: cobj, end: cobj): 39 | seq_gc_add_roots(start, end) 40 | 41 | def remove_roots(start: cobj, end: cobj): 42 | seq_gc_remove_roots(start, end) 43 | 44 | def clear_roots(): 45 | seq_gc_clear_roots() 46 | 47 | def exclude_static_roots(start: cobj, end: cobj): 48 | seq_gc_exclude_static_roots(start, end) 49 | 50 | def register_finalizer(p): 51 | if hasattr(p, '__del__'): 52 | def f(x: cobj, data: cobj, T: type): 53 | Ptr[T](__ptr__(x).as_byte())[0].__del__() 54 | seq_register_finalizer(p.__raw__(), f(T=type(p), ...).__raw__()) 55 | -------------------------------------------------------------------------------- /stdlib/internal/khash.seq: -------------------------------------------------------------------------------- 1 | def __ac_isempty(flag: Ptr[u32], i: int): 2 | return int(flag[i >> 4] >> u32((i & 0xf) << 1)) & 2 3 | 4 | def __ac_isdel(flag: Ptr[u32], i: int): 5 | return int(flag[i >> 4] >> u32((i & 0xf) << 1)) & 1 6 | 7 | def __ac_iseither(flag: Ptr[u32], i: int): 8 | return int(flag[i >> 4] >> u32((i & 0xf) << 1)) & 3 9 | 10 | def __ac_set_isdel_false(flag: Ptr[u32], i: int): 11 | flag[i >> 4] &= u32(~(1 << ((i & 0xf) << 1))) 12 | 13 | def __ac_set_isempty_false(flag: Ptr[u32], i: int): 14 | flag[i >> 4] &= u32(~(2 << ((i & 0xf) << 1))) 15 | 16 | def __ac_set_isboth_false(flag: Ptr[u32], i: int): 17 | flag[i >> 4] &= u32(~(3 << ((i & 0xf) << 1))) 18 | 19 | def __ac_set_isdel_true(flag: Ptr[u32], i: int): 20 | flag[i >> 4] |= u32(1 << ((i & 0xf) << 1)) 21 | 22 | def __ac_fsize(m): 23 | return 1 if m < 16 else m >> 4 24 | -------------------------------------------------------------------------------- /stdlib/internal/sort.seq: -------------------------------------------------------------------------------- 1 | from algorithms.timsort import tim_sort_inplace 2 | from algorithms.pdqsort import pdq_sort_inplace 3 | from algorithms.insertionsort import insertion_sort_inplace 4 | from algorithms.heapsort import heap_sort_inplace 5 | from algorithms.qsort import qsort_inplace 6 | 7 | def sorted[T]( 8 | v: Generator[T], 9 | key = Optional[int](), 10 | algorithm: Optional[str] = None, 11 | reverse: bool = False 12 | ): 13 | """ 14 | Return a sorted list of the elements in v 15 | """ 16 | newlist = [a for a in v] 17 | if not isinstance(key, Optional): 18 | newlist.sort(key, algorithm, reverse) 19 | else: 20 | newlist.sort(algorithm=algorithm, reverse=reverse) 21 | return newlist 22 | 23 | def _sort_list(self, key, algorithm: str): 24 | if algorithm == 'pdq': 25 | pdq_sort_inplace(self, key) 26 | elif algorithm == 'insertion': 27 | insertion_sort_inplace(self, key) 28 | elif algorithm == 'heap': 29 | heap_sort_inplace(self, key) 30 | #case 'tim': 31 | # tim_sort_inplace(self, key) 32 | elif algorithm == 'quick': 33 | qsort_inplace(self, key) 34 | else: 35 | raise ValueError("Algorithm '" + algorithm + "' does not exist") 36 | 37 | @extend 38 | class List: 39 | def sort( 40 | self, 41 | key = Optional[int](), 42 | algorithm: Optional[str] = None, 43 | reverse: bool = False 44 | ): 45 | alg = ~algorithm if algorithm else 'pdq' 46 | if isinstance(key, Optional): 47 | _sort_list(self, lambda x: x, alg) 48 | else: 49 | _sort_list(self, key, alg) 50 | if reverse: 51 | self.reverse() 52 | -------------------------------------------------------------------------------- /stdlib/internal/types/array.seq: -------------------------------------------------------------------------------- 1 | from internal.gc import sizeof 2 | 3 | @extend 4 | class Array: 5 | def __new__(ptr: Ptr[T], sz: int) -> Array[T]: 6 | return (sz, ptr) 7 | def __new__(sz: int) -> Array[T]: 8 | return (sz, Ptr[T](sz)) 9 | def __copy__(self) -> Array[T]: 10 | p = Ptr[T](self.len) 11 | str.memcpy(p.as_byte(), self.ptr.as_byte(), self.len * sizeof(T)) 12 | return (self.len, p) 13 | def __deepcopy__(self) -> Array[T]: 14 | p = Ptr[T](self.len) 15 | i = 0 16 | while i < self.len: 17 | p[i] = self.ptr[i].__deepcopy__() 18 | i += 1 19 | return (self.len, p) 20 | def __len__(self) -> int: 21 | return self.len 22 | def __bool__(self) -> bool: 23 | return bool(self.len) 24 | def __getitem__(self, index: int) -> T: 25 | return self.ptr[index] 26 | def __setitem__(self, index: int, what: T): 27 | self.ptr[index] = what 28 | def slice(self, s: int, e: int) -> Array[T]: 29 | return (e - s, self.ptr + s) 30 | array = Array 31 | -------------------------------------------------------------------------------- /stdlib/internal/types/byte.seq: -------------------------------------------------------------------------------- 1 | @pure 2 | @C 3 | def seq_str_byte(a: byte) -> str: pass 4 | 5 | @extend 6 | class byte: 7 | @pure 8 | @llvm 9 | def __new__() -> byte: 10 | ret i8 0 11 | def __new__(b: byte) -> byte: 12 | return b 13 | @pure 14 | @llvm 15 | def __new__(i: int) -> byte: 16 | %0 = trunc i64 %i to i8 17 | ret i8 %0 18 | def __str__(self) -> str: 19 | return seq_str_byte(self) 20 | def __copy__(self) -> byte: 21 | return self 22 | def __deepcopy__(self) -> byte: 23 | return self 24 | @pure 25 | @llvm 26 | def __bool__(self) -> bool: 27 | %0 = icmp ne i8 %self, 0 28 | %1 = zext i1 %0 to i8 29 | ret i8 %1 30 | @pure 31 | @llvm 32 | def __eq__(self, other: byte) -> bool: 33 | %0 = icmp eq i8 %self, %other 34 | %1 = zext i1 %0 to i8 35 | ret i8 %1 36 | @pure 37 | @llvm 38 | def __ne__(self, other: byte) -> bool: 39 | %0 = icmp ne i8 %self, %other 40 | %1 = zext i1 %0 to i8 41 | ret i8 %1 42 | @pure 43 | @llvm 44 | def __lt__(self, other: byte) -> bool: 45 | %0 = icmp ult i8 %self, %other 46 | %1 = zext i1 %0 to i8 47 | ret i8 %1 48 | @pure 49 | @llvm 50 | def __gt__(self, other: byte) -> bool: 51 | %0 = icmp ugt i8 %self, %other 52 | %1 = zext i1 %0 to i8 53 | ret i8 %1 54 | @pure 55 | @llvm 56 | def __le__(self, other: byte) -> bool: 57 | %0 = icmp ule i8 %self, %other 58 | %1 = zext i1 %0 to i8 59 | ret i8 %1 60 | @pure 61 | @llvm 62 | def __ge__(self, other: byte) -> bool: 63 | %0 = icmp uge i8 %self, %other 64 | %1 = zext i1 %0 to i8 65 | ret i8 %1 66 | def __repr__(self): 67 | return str(__ptr__(self), 1).__repr__() 68 | @pure 69 | @llvm 70 | def __int__(self) -> int: 71 | %0 = zext i8 %self to i64 72 | ret i64 %0 73 | @pure 74 | @llvm 75 | def __float__(self) -> float: 76 | %0 = uitofp i8 %self to double 77 | ret double %0 78 | -------------------------------------------------------------------------------- /stdlib/internal/types/generator.seq: -------------------------------------------------------------------------------- 1 | @extend 2 | class Generator: 3 | @__internal__ 4 | def __promise__(self) -> Ptr[T]: 5 | pass 6 | 7 | def done(self) -> bool: 8 | self.__resume__() 9 | return self.__done__() 10 | 11 | def next(self: Generator[T]) -> T: 12 | if isinstance(T, void): 13 | pass 14 | else: 15 | return self.__promise__()[0] 16 | 17 | def __iter__(self) -> Generator[T]: 18 | return self 19 | @pure 20 | @llvm 21 | def __raw__(self) -> Ptr[byte]: 22 | ret i8* %self 23 | @pure 24 | @llvm 25 | def __done__(self) -> bool: 26 | declare i1 @llvm.coro.done(i8* nocapture readonly) 27 | %0 = call i1 @llvm.coro.done(i8* %self) 28 | %1 = zext i1 %0 to i8 29 | ret i8 %1 30 | @llvm 31 | def __resume__(self) -> void: 32 | declare void @llvm.coro.resume(i8*) 33 | call void @llvm.coro.resume(i8* %self) 34 | ret void 35 | def __str__(self) -> str: 36 | return __internal__.raw_type_str(self.__raw__(), "generator") 37 | 38 | def send(self, what: T) -> T: 39 | p = self.__promise__() 40 | p[0] = what 41 | self.__resume__() 42 | return p[0] 43 | 44 | @llvm 45 | def destroy(self) -> void: 46 | declare void @llvm.coro.destroy(i8*) 47 | call void @llvm.coro.destroy(i8* %self) 48 | ret void 49 | 50 | generator = Generator 51 | -------------------------------------------------------------------------------- /stdlib/internal/types/optional.seq: -------------------------------------------------------------------------------- 1 | @extend 2 | class Optional: 3 | def __new__() -> Optional[T]: 4 | if isinstance(T, ByVal): 5 | return __internal__.opt_tuple_new(T) 6 | else: 7 | return __internal__.opt_ref_new(T) 8 | def __new__(what: T) -> Optional[T]: 9 | if isinstance(T, ByVal): 10 | return __internal__.opt_tuple_new_arg(what, T) 11 | else: 12 | return __internal__.opt_ref_new_arg(what, T) 13 | def __bool__(self) -> bool: 14 | if isinstance(T, ByVal): 15 | return __internal__.opt_tuple_bool(self, T) 16 | else: 17 | return __internal__.opt_ref_bool(self, T) 18 | def __invert__(self) -> T: 19 | if isinstance(T, ByVal): 20 | return __internal__.opt_tuple_invert(self, T) 21 | else: 22 | return __internal__.opt_ref_invert(self, T) 23 | def __str__(self) -> str: 24 | return 'None' if not self else str(~self) 25 | def __is_optional__(self, other: Optional[T]): 26 | if (not self) or (not other): 27 | return (not self) and (not other) 28 | return self.__invert__() is other.__invert__() 29 | optional = Optional 30 | 31 | def unwrap[T](opt: Optional[T]) -> T: 32 | if not opt: 33 | raise ValueError('optional is None') 34 | return ~opt 35 | -------------------------------------------------------------------------------- /stdlib/internal/types/slice.seq: -------------------------------------------------------------------------------- 1 | @tuple 2 | class Slice: 3 | start: Optional[int] 4 | stop: Optional[int] 5 | step: Optional[int] 6 | 7 | def adjust_indices(self, length: int): 8 | stepx = ~self.step if self.step else 1 9 | startx = 0 10 | stopx = 0 11 | if stepx == 0: 12 | raise ValueError("slice step cannot be zero") 13 | if stepx > 0: 14 | startx = ~self.start if self.start else 0 15 | stopx = ~self.stop if self.stop else length 16 | else: 17 | startx = ~self.start if self.start else length - 1 18 | stopx = ~self.stop if self.stop else -(length + 1) 19 | return Slice.adjust_indices_helper(length, startx, stopx, stepx) 20 | 21 | def adjust_indices_helper(length: int, start: int, stop: int, step: int): 22 | if start < 0: 23 | start += length 24 | if start < 0: 25 | start = -1 if step < 0 else 0 26 | elif start >= length: 27 | start = length - 1 if step < 0 else length 28 | 29 | if stop < 0: 30 | stop += length 31 | if stop < 0: 32 | stop = -1 if step < 0 else 0 33 | elif stop >= length: 34 | stop = length - 1 if step < 0 else length 35 | 36 | if step < 0: 37 | if stop < start: 38 | return start, stop, step, (start - stop - 1) // (-step) + 1 39 | else: 40 | if start < stop: 41 | return start, stop, step, (stop - start - 1) // step + 1 42 | 43 | return start, stop, step, 0 44 | slice = Slice 45 | -------------------------------------------------------------------------------- /stdlib/os/__init__.seq: -------------------------------------------------------------------------------- 1 | def system(cmd: str) -> int: 2 | return _C.system(cmd.c_str()) 3 | 4 | SEEK_SET = 0 5 | SEEK_CUR = 1 6 | SEEK_END = 2 7 | 8 | @tuple 9 | class EnvMap: 10 | _map: Dict[str,str] 11 | 12 | def __new__() -> EnvMap: 13 | return (Dict[str,str](),) 14 | 15 | def _init_if_needed(self): 16 | if len(self._map) == 0: 17 | env = _C.seq_env() 18 | p = env[0] 19 | i = 0 20 | while p: 21 | s = str.from_ptr(p) 22 | if s: 23 | j = 0 24 | found = False 25 | while j < len(s): 26 | if s[j] == "=": 27 | found = True 28 | break 29 | j += 1 30 | k = s[0:j] if found else s 31 | v = s[j+1:] if found else "" 32 | self._map[k] = v 33 | i += 1 34 | p = env[i] 35 | 36 | def __getitem__(self, key: str): 37 | self._init_if_needed() 38 | return self._map[key] 39 | 40 | def __str__(self): 41 | self._init_if_needed() 42 | return str(self._map) 43 | 44 | def __contains__(self, key: str): 45 | self._init_if_needed() 46 | return key in self._map 47 | 48 | def __iter__(self): 49 | self._init_if_needed() 50 | return self._map.items() 51 | 52 | environ = EnvMap() 53 | 54 | def getenv(key: str, default: str = ""): 55 | return environ[key] if key in environ else default 56 | 57 | 58 | def mkdir(name: str, mode: int = 0x1FF) -> int: 59 | # TODO: use errno 60 | from C import mkdir(cobj, int) -> int 61 | ret = mkdir(name.ptr, mode) 62 | if ret != 0: 63 | raise OSError("mkdir failed") 64 | -------------------------------------------------------------------------------- /stdlib/os/path.seq: -------------------------------------------------------------------------------- 1 | def splitext(p: str) -> Tuple[str, str]: 2 | """ 3 | Split the extension from a pathname. 4 | Extension is everything from the last dot to the end, ignoring 5 | leading dots. Returns "(root, ext)"; ext may be empty.""" 6 | sep = '/' 7 | extsep = '.' 8 | 9 | sepIndex = p.rfind(sep) 10 | dotIndex = p.rfind(extsep) 11 | if dotIndex > sepIndex: 12 | # skip all leading dots 13 | filenameIndex = sepIndex + 1 14 | while filenameIndex < dotIndex: 15 | if p[filenameIndex:filenameIndex+1] != extsep: 16 | return p[:dotIndex], p[dotIndex:] 17 | filenameIndex += 1 18 | return p, p[:0] 19 | -------------------------------------------------------------------------------- /stdlib/python.seq: -------------------------------------------------------------------------------- 1 | _py_init() 2 | -------------------------------------------------------------------------------- /stdlib/string.seq: -------------------------------------------------------------------------------- 1 | ascii_letters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ' 2 | ascii_lowercase = 'abcdefghijklmnopqrstuvwxyz' 3 | ascii_uppercase = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 4 | 5 | digits = '0123456789' 6 | hexdigits = '0123456789abcdefABCDEF' 7 | octdigits = '01234567' 8 | 9 | punctuation = '!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~' 10 | printable = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~ \t\n\r\x0b\x0c' 11 | whitespace = ' \t\n\r\x0b\x0c' 12 | -------------------------------------------------------------------------------- /stdlib/sys.seq: -------------------------------------------------------------------------------- 1 | argv = list(__argv__, len(__argv__)) 2 | 3 | stdin = File(_C.seq_stdin()) 4 | stdout = File(_C.seq_stdout()) 5 | stderr = File(_C.seq_stderr()) 6 | 7 | def exit(status: int = 0): 8 | raise SystemExit(status) 9 | 10 | maxsize = 0x7fffffffffffffff 11 | -------------------------------------------------------------------------------- /stdlib/threading.seq: -------------------------------------------------------------------------------- 1 | @tuple 2 | class Lock: 3 | p: cobj 4 | 5 | def __new__() -> Lock: 6 | return (_C.seq_lock_new(),) 7 | 8 | def acquire(self, block: bool = True, timeout: float = -1.0): 9 | if timeout >= 0.0 and not block: 10 | raise ValueError("can't specify a timeout for a non-blocking call") 11 | return _C.seq_lock_acquire(self.p, block, timeout) 12 | 13 | def release(self): 14 | _C.seq_lock_release(self.p) 15 | 16 | def __enter__(self): 17 | self.acquire() 18 | 19 | def __exit__(self): 20 | self.release() 21 | 22 | @tuple 23 | class RLock: 24 | p: cobj 25 | 26 | def __new__() -> RLock: 27 | return (_C.seq_rlock_new(),) 28 | 29 | def acquire(self, block: bool = True, timeout: float = -1.0): 30 | if timeout >= 0.0 and not block: 31 | raise ValueError("can't specify a timeout for a non-blocking call") 32 | return _C.seq_rlock_acquire(self.p, block, timeout) 33 | 34 | def release(self): 35 | _C.seq_rlock_release(self.p) 36 | 37 | def __enter__(self): 38 | self.acquire() 39 | 40 | def __exit__(self): 41 | self.release() 42 | 43 | def active_count(): 44 | from openmp import get_num_threads 45 | return get_num_threads() 46 | 47 | def get_native_id(): 48 | from openmp import get_thread_num 49 | return get_thread_num() 50 | 51 | def get_ident(): 52 | return get_native_id() + 1 53 | -------------------------------------------------------------------------------- /stdlib/time.seq: -------------------------------------------------------------------------------- 1 | from sys import stderr 2 | 3 | def time(): 4 | return _C.seq_time() / 1e9 5 | 6 | class TimeInterval: 7 | """ 8 | Utility class for timing Seq code 9 | """ 10 | start: int 11 | msg: str 12 | 13 | def __init__(self): 14 | self.start = _C.seq_time() 15 | self.msg = '' 16 | 17 | def __enter__(self): 18 | self.start = _C.seq_time() 19 | 20 | def __exit__(self): 21 | print(self.report(self.msg), file=stderr) 22 | 23 | def report(self, msg='', memory=False): 24 | msg = f"{'Block' if not self.msg else self.msg} took {self.elapsed()}s" 25 | # if memory: 26 | # msg = f'{msg} ({_C.memory()} MB)' 27 | return msg 28 | 29 | def elapsed(self): 30 | return float(_C.seq_time() - self.start) / 1e9 31 | 32 | def tick(self, msg, memory=False): 33 | ret = self.report(msg) 34 | self.start = _C.seq_time() 35 | 36 | def timing(msg: str = ""): 37 | """ 38 | Example usage: 39 | 40 | .. code-block:: seq 41 | 42 | from time import timing 43 | with timing('foo function'): 44 | foo() # prints runtime of foo 45 | """ 46 | return TimeInterval(0, msg) 47 | -------------------------------------------------------------------------------- /test/CMakeLists.txt.in: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.8.2) 2 | 3 | project(googletest-download NONE) 4 | 5 | include(ExternalProject) 6 | ExternalProject_Add(googletest 7 | GIT_REPOSITORY https://github.com/google/googletest.git 8 | GIT_TAG release-1.10.0 9 | SOURCE_DIR "${CMAKE_CURRENT_BINARY_DIR}/googletest-src" 10 | BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/googletest-build" 11 | CONFIGURE_COMMAND "" 12 | BUILD_COMMAND "" 13 | INSTALL_COMMAND "" 14 | TEST_COMMAND "" 15 | ) 16 | -------------------------------------------------------------------------------- /test/apps/bwa/example.seq: -------------------------------------------------------------------------------- 1 | # Implementation of https://github.com/lh3/bwa/blob/master/example.c 2 | 3 | from sys import argv 4 | from bio import FASTQ 5 | from bio.bwa import BWA 6 | 7 | bwa = BWA(argv[1]) 8 | for read in FASTQ(argv[2]): 9 | for reg in bwa.align(read.read): 10 | if reg.secondary >= 0: continue 11 | aln = bwa.reg2aln(read.read, reg) 12 | print read.name, '-' if aln.rev else '+', bwa.name(aln), aln.pos, aln.mapq, aln.cigar, aln.NM 13 | -------------------------------------------------------------------------------- /test/apps/cora/util.seq: -------------------------------------------------------------------------------- 1 | K: Static[int] = 64 2 | 3 | @tuple 4 | class BitSet: 5 | v: List[int] 6 | 7 | def __new__(n: int) -> BitSet: 8 | return ([0 for _ in range((n // 64) + 1)],) 9 | def __getitem__(self, idx: int): 10 | return (self.v[idx // 64] & (1 << (idx % 64))) != 0 11 | def __setitem__(self, idx: int, b: bool): 12 | if b: 13 | self.v[idx // 64] |= (1 << (idx % 64)) 14 | else: 15 | self.v[idx // 64] &= ~(1 << (idx % 64)) 16 | -------------------------------------------------------------------------------- /test/apps/minimap2/sw.seq: -------------------------------------------------------------------------------- 1 | # Smith-Waterman alignment from minimap2 implemented using Seq's inter-sequence alignment 2 | # https://github.com/lh3/minimap2 3 | # https://github.com/lh3/ksw2 4 | # Usage: seqc sw.seq 5 | # and are text files of the same length with one sequence per line. 6 | from time import TimeInterval 7 | from sys import argv 8 | from bio import seqs, inter_align 9 | from math import sqrt 10 | from statistics import mean, stdev 11 | queries = argv[1] 12 | targets = argv[2] 13 | 14 | total, num = 0, 0 15 | score = True # must be global 16 | 17 | @inter_align 18 | def process_inter(t): 19 | global total, num 20 | query, target = t 21 | inter_score = query.align(target, a=1, b=2, ambig=0, gapo=4, gape=2, zdrop=400, bandwidth=751, ext_only=False, score_only=score).score 22 | total += inter_score 23 | num += 1 24 | 25 | def process_intra(t): 26 | global total, num 27 | query, target = t 28 | inter_score = query.align(target, a=1, b=2, ambig=0, gapo=4, gape=2, zdrop=400, bandwidth=751, ext_only=False, score_only=score).score 29 | total += inter_score 30 | num += 1 31 | 32 | def run(queries, targets, msg, f, filter=False): 33 | global num, total, score 34 | def filter_len(t): 35 | query, target = t 36 | if len(query) <= 512 and len(target) <= 512: 37 | yield query, target 38 | 39 | for s in [False, True]: 40 | times = [] 41 | for i in range(3): 42 | num, total = 0, 0 43 | t = TimeInterval() 44 | score = s 45 | if filter: 46 | zip(seqs(queries), seqs(targets)) |> filter_len |> f 47 | else: 48 | zip(seqs(queries), seqs(targets)) |> f 49 | times.append(t.elapsed()) 50 | # print '-', i, num, total, times[-1] 51 | m = mean(times) 52 | print f'{msg}: seq-{msg} {int(score)} {m} {sqrt(sum((i - m)**2 for i in times) / len(times))}' 53 | # print stdev(times) # broken 54 | 55 | from C import seq_get_interaln_simd() -> str 56 | from C import seq_set_sw_maxsimd(int) 57 | 58 | run(queries, targets, 'intra', process_intra) 59 | run(queries, targets, 'intra-512', process_intra, True) 60 | 61 | for simd in [0x20, 0x80, 0x100]: 62 | seq_set_sw_maxsimd(simd) 63 | print seq_get_interaln_simd() 64 | run(queries, targets, 'inter', process_inter) 65 | run(queries, targets, 'inter-512', process_inter, True) 66 | 67 | -------------------------------------------------------------------------------- /test/apps/minimap2/sw_simple.seq: -------------------------------------------------------------------------------- 1 | # Smith-Waterman alignment from minimap2 implemented using Seq's inter-sequence alignment 2 | # https://github.com/lh3/minimap2 3 | # https://github.com/lh3/ksw2 4 | # Usage: seqc sw.seq 5 | # and are text files of the same length with one sequence per line. 6 | from time import TimeInterval 7 | from sys import argv 8 | from bio import seqs, inter_align 9 | from math import sqrt 10 | from statistics import mean, stdev 11 | queries = argv[1] 12 | targets = argv[2] 13 | 14 | total, num = 0, 0 15 | score = True # must be global 16 | 17 | @inter_align 18 | def process_inter(t): 19 | global total, num 20 | query, target = t 21 | inter_score = query.align(target, a=1, b=2, ambig=0, gapo=4, gape=2, score_only=score).score 22 | total += inter_score 23 | num += 1 24 | 25 | def process_intra(t): 26 | global total, num 27 | query, target = t 28 | inter_score = query.align(target, a=1, b=2, ambig=0, gapo=4, gape=2, score_only=score).score 29 | total += inter_score 30 | num += 1 31 | 32 | def run(queries, targets, msg, f): 33 | global num, total, score 34 | for s in [False, True]: 35 | times = [] 36 | for i in range(3): 37 | num, total = 0, 0 38 | t = TimeInterval() 39 | score = s 40 | zip(seqs(queries), seqs(targets)) |> f 41 | times.append(t.elapsed()) 42 | # print '-', i, num, total, times[-1] 43 | m = mean(times) 44 | print f'[sw-time] seq-{msg} {int(score)} {m} {sqrt(sum((i - m)**2 for i in times) / len(times))}' 45 | # print stdev(times) # broken 46 | 47 | run(queries, targets, 'intra', process_intra) 48 | run(queries, targets, 'inter', process_inter) 49 | -------------------------------------------------------------------------------- /test/apps/snap/test.seq: -------------------------------------------------------------------------------- 1 | from sys import argv 2 | from bio import FASTQ 3 | from genomeindex import * 4 | K: Static[int] = 20 5 | 6 | def update(counts, pos, max_pos, max_count): 7 | count = counts.get(pos, 0) + 1 8 | counts[pos] = count 9 | return (pos, count) if count > max_count else (max_pos, max_count) 10 | 11 | def main(args): 12 | index = GenomeIndex[Kmer[K]](args[0]) 13 | for read in FASTQ(args[1]): 14 | counts: Dict[int, int] = {} 15 | max_pos, max_count = 0, 0 16 | 17 | for i,kmer in enumerate(read.seq.kmers(K, K)): 18 | offset = i * K 19 | hits = index[kmer] 20 | hits_rev = index[~kmer] 21 | 22 | for i in range(len(hits)): 23 | pos = int(hits[i]) - offset 24 | max_pos, max_count = update(counts, pos, max_pos, max_count) 25 | 26 | for i in range(len(hits_rev)): 27 | pos = int(hits_rev[i]) - offset 28 | max_pos, max_count = update(counts, pos, max_pos, max_count) 29 | 30 | print read, max_pos 31 | 32 | if len(argv) > 0: 33 | main(argv) 34 | -------------------------------------------------------------------------------- /test/bench/bedcov.seq: -------------------------------------------------------------------------------- 1 | # BED coverage benchmark from https://github.com/lh3/biofast 2 | from sys import argv 3 | from time import timing 4 | from bio import * 5 | from bio.intervals import IntervalTree 6 | 7 | with timing('bed coverage (total)'): 8 | interval_tree = IntervalTree() 9 | 10 | with timing('reading first BED file'): 11 | for record in BED(argv[1], copy=True, validate=False): 12 | interval_tree.add(record.chrom, record.chrom_start, record.chrom_end) 13 | 14 | with timing('indexing'): 15 | interval_tree.index() 16 | 17 | with timing('querying second BED file'): 18 | for record in BED(argv[2], copy=False, validate=False): 19 | cov, cov_st, cov_en, n = 0, 0, 0, 0 20 | st1, en1 = record.chrom_start, record.chrom_end 21 | for item in interval_tree.overlap(record.chrom, st1, en1): 22 | n += 1 23 | # calcualte overlap length/coverage 24 | st0, en0 = item.start, item.end 25 | if st0 < st1: st0 = st1 26 | if en0 > en1: en0 = en1 27 | if st0 > cov_en: # no overlap with previous found intervals 28 | # set coverage to current interval 29 | cov += cov_en - cov_st 30 | cov_st, cov_en = st0, en0 31 | elif cov_en < en0: 32 | cov_en = en0 # overlap with previous found intervals 33 | cov += cov_en - cov_st 34 | # print chrom, start, end, count, # of coverage nt 35 | print f'{record.chrom}\t{record.chrom_start}\t{record.chrom_end}\t{n}\t{cov}' 36 | -------------------------------------------------------------------------------- /test/bench/fmindex.seq: -------------------------------------------------------------------------------- 1 | ###################### 2 | # Prefetch benchmark # 3 | ###################### 4 | from sys import argv 5 | from bio import * 6 | from bio.fmindex import FMIndex 7 | from time import timing 8 | from pickle import load 9 | import gzip 10 | 11 | fmi = None 12 | with gzip.open(argv[1], 'rb') as jar: 13 | fmi = load(jar, FMIndex) 14 | 15 | step = 20 16 | n = 0 17 | 18 | def update(count): 19 | global n 20 | n += count 21 | 22 | @prefetch 23 | def find(s, fmi): 24 | intv = fmi.interval(s[-1]) 25 | s = s[:-1] 26 | while s and intv: 27 | intv = fmi[intv, s[-1]] 28 | s = s[:-1] 29 | return len(intv) 30 | 31 | for k in (10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32): 32 | n = 0 33 | with timing(f'{k=}'): 34 | FASTQ(argv[2]) |> seqs |> split(k, step=step) |> find(fmi) |> update 35 | print n 36 | -------------------------------------------------------------------------------- /test/bench/fqcnt.seq: -------------------------------------------------------------------------------- 1 | # FASTQ counter benchmark from https://github.com/lh3/biofast 2 | from sys import argv, exit, stderr 3 | from bio import * 4 | 5 | if len(argv) != 2: 6 | stderr.write("Usage: fqcnt.py \n") 7 | exit(1) 8 | 9 | n, slen, qlen = 0, 0, 0 10 | for r in FASTQ(argv[1], validate=False): 11 | n += 1 12 | slen += len(r.read) 13 | qlen += len(r.qual) 14 | 15 | print n, slen, qlen 16 | -------------------------------------------------------------------------------- /test/bench/hamming.seq: -------------------------------------------------------------------------------- 1 | ############################### 2 | # Hammming distance benchmark # 3 | ############################### 4 | from sys import argv 5 | from time import timing 6 | from bio import * 7 | 8 | def dist_fast(k1, k2): 9 | return abs(k1 - k2) 10 | 11 | def dist_slow(k1, k2): 12 | d = 0 13 | for i in range(type(k1).len()): 14 | if k1[i] != k2[i]: 15 | d += 1 16 | return d 17 | 18 | def test(use_slow_dist, K: Static[int]): 19 | n = 0 20 | with timing(f'{K}-mer ({use_slow_dist=})'): 21 | for s in FASTA(argv[1]) |> seqs: 22 | for kmer in s |> kmers(1, K): 23 | d = 0 24 | rckmer = ~kmer 25 | if use_slow_dist: 26 | d = dist_slow(rckmer, kmer) 27 | else: 28 | d = dist_fast(rckmer, kmer) 29 | n ^= d 30 | print n 31 | 32 | print 'start' 33 | test(False, 4) 34 | test(True, 4) 35 | test(False, 8) 36 | test(True, 8) 37 | test(False, 16) 38 | test(True, 16) 39 | test(False, 32) 40 | test(True, 32) 41 | test(False, 64) 42 | test(True, 64) 43 | test(False, 128) 44 | test(True, 128) 45 | -------------------------------------------------------------------------------- /test/bench/hash.seq: -------------------------------------------------------------------------------- 1 | ############################## 2 | # Test k-mer hash collisions # 3 | ############################## 4 | from sys import argv 5 | from bio import * 6 | d = {} 7 | #d.resize(1 << 32) 8 | 9 | def test(use_bad_hash: bool, K: Static[int]): 10 | def update(kmer, use_bad_hash, seen): 11 | if kmer not in seen: 12 | h = int(kmer.as_int()) if use_bad_hash else hash(kmer) 13 | d[h] = d.get(h, 0) + 1 14 | seen.add(kmer) 15 | 16 | seen: Set[Kmer[K]] = set() 17 | #seen.resize(1 << 32) 18 | FASTA(argv[1]) |> seqs |> kmers(1, K) |> update(use_bad_hash, seen) 19 | m = max((v, k) for k,v in d.items())[0] 20 | a = sum(v for v in d.values()) / len(d) 21 | print f'{K}-mer ({use_bad_hash=}):\tmax={m}, avg={a}' 22 | d.clear() 23 | 24 | print 'start' 25 | test(False, 64) 26 | test(True, 64) 27 | -------------------------------------------------------------------------------- /test/bench/kmercnt.seq: -------------------------------------------------------------------------------- 1 | # Implementation of benchmark at https://github.com/lh3/kmer-cnt 2 | # Usage: seqc kmercnt.seq 3 | from sys import argv 4 | from time import timing 5 | from bio import * 6 | 7 | def print_hist(h, N = 256): 8 | cnt = [0 for _ in range(N)] 9 | for v in h.values(): 10 | cnt[min(v, N - 1)] += 1 11 | for i in range(1, N): 12 | print f'{i}\t{cnt[i]}' 13 | 14 | with timing('k-mer counting'), FASTQ(argv[1], copy=False, validate=False) as fastq: 15 | h = {} 16 | fastq |> seqs |> kmers(step=1, k=31) |> canonical |> h.increment 17 | print_hist(h) 18 | -------------------------------------------------------------------------------- /test/bench/rc.seq: -------------------------------------------------------------------------------- 1 | ################################ 2 | # Reverse complement benchmark # 3 | ################################ 4 | from sys import argv 5 | from time import timing 6 | from bio import * 7 | from internal.gc import alloc_atomic, free 8 | 9 | def test_slow(s): 10 | n = len(s) 11 | p = alloc_atomic(n) 12 | for i in range(n): 13 | p[n - i - 1] = s[i].ptr[0].comp() 14 | r = seq(p, n) 15 | b = s > r 16 | free(p) 17 | return b 18 | 19 | def test_fast(s: seq): 20 | return s > ~s 21 | 22 | def test(sublen, use_slow_test): 23 | n = 0 24 | with timing(f'{sublen=} ({use_slow_test=})'): 25 | for s in FASTA(argv[1]) |> seqs: 26 | for sub in s |> split(sublen, 1): 27 | b = False 28 | if use_slow_test: 29 | b = test_slow(sub) 30 | else: 31 | b = test_fast(sub) 32 | n += 1 if b else 0 33 | print n 34 | 35 | for i in range(1, 32 + 1): 36 | test(i, True) 37 | test(i, False) 38 | -------------------------------------------------------------------------------- /test/bench/rc_pipeline.seq: -------------------------------------------------------------------------------- 1 | ###################### 2 | # Pipeline benchmark # 3 | ###################### 4 | from sys import argv 5 | from time import timing 6 | from bio import * 7 | 8 | n = 0 9 | def update(kmer): 10 | global n 11 | x = type(kmer)() |> base(len(kmer) // 2, k'T') 12 | if kmer > x: 13 | n += 1 14 | 15 | def test_fast(K: Static[int]): 16 | global n 17 | n = 0 18 | with timing(f'{K}-mer (fast)'): 19 | FASTA(argv[1]) |> seqs |> kmers(step=1, k=K) |> revcomp |> update 20 | print n 21 | 22 | 23 | def test_slow(K: Static[int]): 24 | global n 25 | n = 0 26 | with timing(f'{K}-mer (slow)'): 27 | for a in seqs(FASTA(argv[1])): 28 | for b in kmers(a, step=1, k=K): 29 | c = revcomp(b) 30 | update(c) 31 | print n 32 | 33 | def test_super_slow(K: Static[int]): 34 | global n 35 | n = 0 36 | with timing(f'{K}-mer (super slow)'): 37 | for a in seqs(FASTA(argv[1])): 38 | for b in split(a, K, step=1): 39 | if not b.N(): 40 | c = K(b) 41 | d = revcomp(c) 42 | update(d) 43 | print n 44 | 45 | test_fast(4) 46 | test_slow(4) 47 | test_super_slow(4) 48 | 49 | test_fast(8) 50 | test_slow(8) 51 | test_super_slow(8) 52 | 53 | test_fast(16) 54 | test_slow(16) 55 | test_super_slow(16) 56 | 57 | test_fast(32) 58 | test_slow(32) 59 | test_super_slow(32) 60 | 61 | test_fast(64) 62 | test_slow(64) 63 | test_super_slow(64) 64 | 65 | test_fast(128) 66 | test_slow(128) 67 | test_super_slow(128) 68 | -------------------------------------------------------------------------------- /test/bench/sw.seq: -------------------------------------------------------------------------------- 1 | ###################################### 2 | # Inter-sequence alignment benchmark # 3 | ###################################### 4 | from sys import argv 5 | from time import timing 6 | from bio import * 7 | 8 | prefix = argv[1] 9 | checksum = 0 10 | 11 | @inter_align 12 | def process_inter(t): 13 | global checksum 14 | query, target = t 15 | score = query.align(target, 16 | a=1, 17 | b=2, 18 | ambig=0, 19 | gapo=2, 20 | gape=1, 21 | zdrop=100, 22 | bandwidth=100, 23 | end_bonus=5).score 24 | checksum += score 25 | 26 | def process_intra(t): 27 | global checksum 28 | query, target = t 29 | score = query.align(target, 30 | a=1, 31 | b=2, 32 | ambig=0, 33 | gapo=2, 34 | gape=1, 35 | zdrop=100, 36 | bandwidth=100, 37 | end_bonus=5).score 38 | checksum += score 39 | 40 | for m in range(30, 125, 5): 41 | in1 = f'{prefix}.max_{m}.1.txt' 42 | in2 = f'{prefix}.max_{m}.2.txt' 43 | 44 | checksum = 0 45 | with timing(f'intra ({m=})'): 46 | zip(seqs(in1), seqs(in2)) |> process_intra 47 | print checksum 48 | 49 | checksum = 0 50 | with timing(f'inter ({m=})'): 51 | zip(seqs(in1), seqs(in2)) |> process_inter 52 | print checksum 53 | -------------------------------------------------------------------------------- /test/core/empty.seq: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seq-lang/seq/0c275584163c172e5e7f20562c314991ed3bcf37/test/core/empty.seq -------------------------------------------------------------------------------- /test/core/exit.seq: -------------------------------------------------------------------------------- 1 | import sys 2 | sys.exit(42) 3 | -------------------------------------------------------------------------------- /test/core/helloworld.seq: -------------------------------------------------------------------------------- 1 | print "hello world" # EXPECT: hello world 2 | -------------------------------------------------------------------------------- /test/core/parser.seq: -------------------------------------------------------------------------------- 1 | x, y = 1, 2 2 | print x, y # EXPECT: 1 2 3 | (x, y) = (3, 4) 4 | print x, y # EXPECT: 3 4 5 | x, y = (1, 2) 6 | print x, y # EXPECT: 1 2 7 | (x, y) = 3, 4 8 | print x, y # EXPECT: 3 4 9 | (x, y) = [3, 4] 10 | print x, y # EXPECT: 3 4 11 | [x, y] = [1, 2] 12 | print x, y # EXPECT: 1 2 13 | 14 | # TODO generator/range slices? 15 | # a, b, *tx, c, d = range(10) 16 | # print a, b, tx, c, d # 0 1 [2, 3, 4, 5, 6, 7] 8 9 17 | 18 | l = list(iter(range(10))) 19 | [a, b, *lx, c, d] = l 20 | print a, b, lx, c, d # EXPECT: 0 1 [2, 3, 4, 5, 6, 7] 8 9 21 | a, b, *lx = l 22 | print a, b, lx # EXPECT: 0 1 [2, 3, 4, 5, 6, 7, 8, 9] 23 | *lx, a, b = l 24 | print lx, a, b # EXPECT: [0, 1, 2, 3, 4, 5, 6, 7] 8 9 25 | 26 | *xz, a, b = (1, 2, 3, 4, 5) 27 | print xz, a, b # EXPECT: (1, 2, 3) 4 5 28 | 29 | 30 | # *x = range(5) # ERR 31 | (*ex,) = [1, 2, 3] 32 | print ex # EXPECT: [1, 2, 3] 33 | 34 | # https://stackoverflow.com/questions/6967632/unpacking-extended-unpacking-and-nested-extended-unpacking 35 | 36 | sa, sb = 'XY' 37 | print sa, sb # EXPECT: X Y 38 | (sa, sb), sc = 'XY', 'Z' 39 | print sa, sb, sc # EXPECT: X Y Z 40 | # (sa, sb), sc = 'XYZ' # ERROR: 41 | 42 | sa, *la = 'X' 43 | print sa, la, 1 # EXPECT: X 1 44 | 45 | sa, *la = 'XYZ' 46 | print sa, la # EXPECT: X YZ 47 | 48 | # a, *b, c, *d = 1,2,3,4,5 # ERROR -- two starred expressions in assignment 49 | 50 | (xa,xb), *xc, xd = [1,2],'this' 51 | print xa, xb, xc, xd # EXPECT: 1 2 () this 52 | 53 | (a, b), (sc, *sl) = [1,2], 'this' 54 | print a, b, sc, sl # EXPECT: 1 2 t his 55 | 56 | 57 | 58 | # // a, b, *x, c, d = y 59 | # // (^) = y 60 | # // [^] = y 61 | # // *a = y NO ; *a, = y YES 62 | # // (a, b), c = d, e 63 | # // *(a, *b), c = this 64 | # // a = *iterable 65 | 66 | 67 | # # Issue #116 68 | # def foo(): 69 | # a = 42 70 | # def bar(): 71 | # print a # <-- this should be a parser error; 'a' has to be global 72 | # bar() 73 | # foo() # ERROR: identifier 'a' not found 74 | -------------------------------------------------------------------------------- /test/data/MT-human.fa.fai: -------------------------------------------------------------------------------- 1 | MT_human 16569 10 60 61 2 | -------------------------------------------------------------------------------- /test/data/MT-orang.fa.fai: -------------------------------------------------------------------------------- 1 | MT_orang 16499 10 60 61 2 | -------------------------------------------------------------------------------- /test/data/invalid/invalid_fai_float.fai: -------------------------------------------------------------------------------- 1 | fastq1 66 8 30 31 79.2 2 | fastq2 28 156 14 15 188 3 | fastq2 84 12 566 988 91 4 | fastq3 29 72 146 19 134 5 | fastq4 66 8 30 31 79 6 | fastq5 28 156 14 15 188 7 | -------------------------------------------------------------------------------- /test/data/invalid/invalid_fai_missing_col.fai: -------------------------------------------------------------------------------- 1 | fastq2 28 156 14 15 188 2 | fastq1 66 8 30 31 3 | fastq2 84 12 566 988 91 4 | fastq3 29 72 146 19 134 5 | fastq4 66 8 30 31 79 6 | fastq5 28 156 14 15 188 7 | -------------------------------------------------------------------------------- /test/data/invalid/invalid_with_header.bed: -------------------------------------------------------------------------------- 1 | browser position chr7:127471196-127495720 2 | browser hide all 3 | track name="ItemRGBDemo" description="Item RGB demonstration" visibility=2 itemRgb="On" 4 | chr7 127471196a 127472363 Pos1 0 + 127471196 127472363 255,0,0 4 11,12,13,14 14,55,66,99 5 | chr7 127472363 127473530 Pos2 0 + 127472363 127473530 255,0,0 6 | chr7 127473530 127474697 Pos3 0 + 127473530 127474697 255,0,0 7 | chr7 127474697 127475864 Pos4 0 + 127474697 127475864 255,0,0 8 | chr7 127475864 127477031 Neg1 0 - 127475864 127477031 0,0,255 9 | chr7 127477031 127478198 Neg2 0 - 127477031 127478198 0,0,255 10 | chr7 127478198 127479365 Neg3 0 - 127478198 127479365 0,0,255 11 | chr7 127479365 127480532 Pos5 0 + 127479365 127480532 255,0,0 12 | chr7 127480532 127481699 Neg4 0 - 127480532 127481699 0,0,255 13 | -------------------------------------------------------------------------------- /test/data/invalid/seqs_bad_base.fasta: -------------------------------------------------------------------------------- 1 | >chrA 2 | TCCTCCCCGTTCGCTGGACCCTTGGTCTATCTAGTCAAGAATTAACTCCC 3 | ATTTAGTTGGCTGTTCGTCGATTACCCCTACTGGACCGTCGCAACGGCTC 4 | ACGTGGAGGTCTTAGACCAAGAAAGCTACTGTATGCGGGGATATCACATC 5 | AGATTGCCAGGCGAGCAGCTCTAGCGTGACACGCCTAGACTCATTCGTTG 6 | TTCCTTGTCAATCCCAGGGGTCTCCACAGGGAGTGGATCGAGCTAATCAC 7 | CGTTTCGAGTCCGTCAGGCGGAGAGTAGCAGTAAGTACAAACTTCTGCTA 8 | GTCGCTCTGCCACAACGTAGCCACCTAAGATTAACCCTGGAATTGTCCGG 9 | GCGGCATGATCCATCGAGGAGTTAGCGGGGACAGGGAGTTACCAGTCGAG 10 | ACGTCCATGGTGGTGCTGCAATCCATGGATACCATCTCCTTGCCATTCCT 11 | AGGGACATCG 12 | >chrB 13 | TATGGGGTAGCATCATTAAGTGGGGAGGTAGACCAGGAGTTCGGTTCCCG 14 | GAGTTTCGTTAGTTCAGGTAGCGTGACCTCGTCTTAGTATGCAGTCGTGA 15 | AATAATAGACATTTCTGCCTGTCAGGTTGCACTAATCACACCCAGGCTGT 16 | TAACGAGGCGGCTCGTAGTATAAACGCTTTGGACTAGACTCGATACCTAG 17 | CGGCGCGCATTGATAAATGGTGCATCTATAGTAAAAGGCGTCCCAACCTG 18 | GGGACTTAGCGTTGAATACCCGTGCAAGGATCTCTAATCGGTTCTCAATG 19 | GCTGCCTGCTCTTTCTCTAAACGAGACTCTAATATCATGTGTGGTCCTTG 20 | CTTTCGGTCGAGAAAAAGCCTTTGATCGCATCCCAAACCGACATCTAAAA 21 | GCTTCATGTATGTCGGCAGCGAAAAAACGACCAAATAGAAGTCCCCTAAC 22 | GGAGAATAGGCCGCCCACGACAGAACACCGCTTCGTCCT 23 | >chrC 24 | CCCGCTAGCCGTGCCTGATCCTCAACCAAGCTGGGTAAAGACAACCGTCT 25 | AATCATTAACTTACGTTGTTACGTCATTTTGCGCTTAAAATTGTCGCACC 26 | GGAATCCGTCGAGACTTCCCGAGACATGTCCCCTTAATAAATGTACGGTG 27 | TGACCTAACGATCGGATCACCGTCCGTGCTAAAACACACAACCGCTGCGT 28 | GACACCGACCGAACGTTACCGAAGGCTGTCCGCCTAACATCTATATTTGG 29 | CGGTAAAGAGGCGGTTCCGGCGGACTATAAAGTCACAGGCCACTGTTTCT 30 | TTGCAAGATATGGCTCTCTGTCAGGACCGCCCCCTAGGGTCAGCTCAAAT 31 | AAGCTTGTCCCGGACTCCGTACTTCCAACAGAAAGGTGACCGCTACATTC 32 | TGCTATTGACCCCTCACACAACGTTCCCCCGCATGGCGTACGTGTTACCA 33 | GGGCGGTTGCGGCCTTACGTCGCCATAAGCACGTATATAAGTCACCCACT 34 | >chrD 35 | TGCCGTGACCACCCCGCGAGAATCTCATAATGATATCTCCAATCGAGT 36 | -------------------------------------------------------------------------------- /test/data/invalid/seqs_bad_base.fasta.fai: -------------------------------------------------------------------------------- 1 | chrA 460 6 50 51 2 | chrB 489 482 50 51 3 | chrC 500 987 50 51 4 | chrD 49 1503 49 50 5 | -------------------------------------------------------------------------------- /test/data/invalid/seqs_bad_base.fastq: -------------------------------------------------------------------------------- 1 | @SL-HXF:348:HKLFWCCXX:1:2101:15676:57231:CACCAAAAGTACATGA 2 | GTGCACAGAAAAAAAGGTTAAATTGAAAAGTAAATATGATAGAAATGATTGCAAATGTTGGCAAACCACTAAATCGACTAAAACTTGAATAAAAGTAAAAATCATCCATGTCATTTATAAAGCGACTCAACTAAAGCATAAGGATATAAGA 3 | + 4 | AAFFFKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKFKKKKKKKKKKKKKFKKKKKKKFKKFKKKKFKKKFK<,AAAFKFKKFAFKKA,,,Aone 2 | ATGCATGCATGCATGCATGCATGCATGCAT 3 | GCATGCATGCATGCATGCATGCATGCATGC 4 | ATGCAT 5 | >two another chromosome 6 | ATGCATGCATGCAT 7 | GCATGCATGCATGC 8 | -------------------------------------------------------------------------------- /test/data/sample_fasta_for_fai.fasta.fai: -------------------------------------------------------------------------------- 1 | one 66 5 30 31 2 | two 28 98 14 15 3 | -------------------------------------------------------------------------------- /test/data/seqs.fasta: -------------------------------------------------------------------------------- 1 | >chrA my random comment 2 | TCCTCCCCGTTCGCTGGACCCTTGGTCTATCTAGTCAAGAATTAACTCCC 3 | ATTTAGTTGGCTGTTCGTCGATTACCCCTACTGGACCGTCGCAACGGCTC 4 | ACGTGGAGGTCTTAGACCAAGAAAGCTACTGTATGCGGGGATATCACATC 5 | AGATTGCCAGGCGAGCAGCTCTAGCGTGACACGCCTAGACTCATTCGTTG 6 | TTCCTTGTCAATCCCAGGGGTCTCCACAGGGAGTGGATCGAGCTAATCAC 7 | CGTTTCGAGTCCGTCAGGCGGAGAGTAGCAGTAAGTACAAACTTCTGCTA 8 | GTCGCTCTGCCACAACGTAGCCACCTAAGATTAACCCTGGAATTGTCCGG 9 | GCGGCATGATCCATCGAGGAGTTAGCGGGGACAGGGAGTTACCAGTCGAG 10 | ACGTCCATGGTGGTGCTGCAATCCATGGATACCATCTCCTTGCCATTCCT 11 | AGGGACATCG 12 | >chrB 13 | TATGGGGTAGCATCATTAAGTGGGGAGGTAGACCAGGAGTTCGGTTCCCG 14 | GAGTTTCGTTAGTTCAGGTAGCGTGACCTCGTCTTAGTATGCAGTCGTGA 15 | AATAATAGACATTTCTGCCTGTCAGGTTGCACTAATCACACCCAGGCTGT 16 | TAACGAGGCGGCTCGTAGTATAAACGCTTTGGACTAGACTCGATACCTAG 17 | CGGCGCGCATTGATAAATGGTGCATCTATAGTAAAAGGCGTCCCAACCTG 18 | GGGACTTAGCGTTGAATACCCGTGCAAGGATCTCTAATCGGTTCTCAATG 19 | GCTGCCTGCTCTTTCTCTAAACGAGACTCTAATATCATGTGTGGTCCTTG 20 | CTTTCGGTCGAGAAAAAGCCTTTGATCGCATCCCAAACCGACATCTAAAA 21 | GCTTCATGTATGTCGGCAGCGAAAAAACGACCAAATAGAAGTCCCCTAAC 22 | GGAGAATAGGCCGCCCACGACAGAACACCGCTTCGTCCT 23 | >chrC 24 | CCCGCTAGCCGTGCCTGATCCTCAACCAAGCTGGGTAAAGACAACCGTCT 25 | AATCATTAACTTACGTTGTTACGTCATTTTGCGCTTAAAATTGTCGCACC 26 | GGAATCCGTCGAGACTTCCCGAGACATGTCCCCTTAATAAATGTACGGTG 27 | TGACCTAACGATCGGATCACCGTCCGTGCTAAAACACACAACCGCTGCGT 28 | GACACCGACCGAACGTTACCGAAGGCTGTCCGCCTAACATCTATATTTGG 29 | CGGTAAAGAGGCGGTTCCGGCGGACTATAAAGTCACAGGCCACTGTTTCT 30 | TTGCAAGATATGGCTCTCTGTCAGGACCGCCCCCTAGGGTCAGCTCAAAT 31 | AAGCTTGTCCCGGACTCCGTACTTCCAACAGAAAGGTGACCGCTACATTC 32 | TGCTATTGACCCCTCACACAACGTTCCCCCGCATGGCGTACGTGTTACCA 33 | GGGCGGTTGCGGCCTTACGTCGCCATAAGCACGTATATAAGTCACCCACT 34 | >chrD hello 35 | TGCCGTGACCACCCCGCGAGAATCTCATAATGATATCTCCAATCGAGTA 36 | -------------------------------------------------------------------------------- /test/data/seqs.fasta.fai: -------------------------------------------------------------------------------- 1 | chrA 460 27 50 51 2 | chrB 489 503 50 51 3 | chrC 500 1008 50 51 4 | chrD 49 1530 49 50 5 | -------------------------------------------------------------------------------- /test/data/seqs.fasta.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seq-lang/seq/0c275584163c172e5e7f20562c314991ed3bcf37/test/data/seqs.fasta.gz -------------------------------------------------------------------------------- /test/data/seqs.fastq: -------------------------------------------------------------------------------- 1 | @SL-HXF:348:HKLFWCCXX:1:2101:15676:57231:CACCAAAAGTACATGA comment A B C 2 | GTGCACAGAAAAAAAGGTTAAATTGAAAAGTAAATATGATAGAAATGATTGCAAATGTTGGCAAACCACTAAATCGACTAAAACTTGAATAAAAGTAAAAATCATCCATGTCATTTATAAAGCGACTCAACTAAAGCATAAGGATATAAGA 3 | + 4 | AAFFFKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKFKKKKKKKKKKKKKFKKKKKKKFKKFKKKKFKKKFK<,AAAFKFKKFAFKKA,,,AchrA 2 | GCCTTAACAT 3 | >chrC 4 | GGGGGGGGGGGCTACGCAAAATCTTAGCATACTCCTCAATTACCCACATAGGATGAATAGGTATTCATCCTATGTGGGTAATTGAGGAGTATGCTAAGATTTTGCGTAGCGGGGGGGGGG 5 | -------------------------------------------------------------------------------- /test/data/seqs2.fasta.fai: -------------------------------------------------------------------------------- 1 | chrA 10 6 10 11 2 | chrC 120 23 120 121 3 | -------------------------------------------------------------------------------- /test/data/toy.bam: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seq-lang/seq/0c275584163c172e5e7f20562c314991ed3bcf37/test/data/toy.bam -------------------------------------------------------------------------------- /test/data/toy.bam.bai: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seq-lang/seq/0c275584163c172e5e7f20562c314991ed3bcf37/test/data/toy.bam.bai -------------------------------------------------------------------------------- /test/data/toy.bed: -------------------------------------------------------------------------------- 1 | chr1 11 22 2 | chr2 33 44 3 | chr3 55 66 4 | -------------------------------------------------------------------------------- /test/data/toy.cram: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seq-lang/seq/0c275584163c172e5e7f20562c314991ed3bcf37/test/data/toy.cram -------------------------------------------------------------------------------- /test/data/toy.cram.crai: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seq-lang/seq/0c275584163c172e5e7f20562c314991ed3bcf37/test/data/toy.cram.crai -------------------------------------------------------------------------------- /test/data/toy.sam: -------------------------------------------------------------------------------- 1 | @SQ SN:ref LN:45 2 | @SQ SN:ref2 LN:40 3 | r001 163 ref 7 30 8M4I4M1D3M = 37 39 TTAGATAAAGAGGATACTG * XX:B:S,12561,2,20,112 4 | r002 0 ref 9 30 1S2I6M1P1I1P1I4M2I * 0 0 AAAAGATAAGGGATAAA * 5 | r003 0 ref 9 30 5H6M * 0 0 AGCTAA * 6 | r004 0 ref 16 30 6M14N1I5M * 0 0 ATAGCTCTCAGC * 7 | r003 16 ref 29 30 6H5M * 0 0 TAGGC * 8 | r001 83 ref 37 30 9M = 7 -39 CAGCGCCAT * 9 | x1 0 ref2 1 30 20M * 0 0 aggttttataaaacaaataa ???????????????????? 10 | x2 0 ref2 2 30 21M * 0 0 ggttttataaaacaaataatt ????????????????????? 11 | x3 0 ref2 6 30 9M4I13M * 0 0 ttataaaacAAATaattaagtctaca ?????????????????????????? 12 | x4 0 ref2 10 30 25M * 0 0 CaaaTaattaagtctacagagcaac ????????????????????????? 13 | x5 0 ref2 12 30 24M * 0 0 aaTaattaagtctacagagcaact ???????????????????????? 14 | x6 0 ref2 14 30 23M * 0 0 Taattaagtctacagagcaacta ??????????????????????? 15 | -------------------------------------------------------------------------------- /test/data/toy.vcf: -------------------------------------------------------------------------------- 1 | ##fileformat=VCFv4.0 2 | ##fileDate=20090805 3 | ##source=myImputationProgramV3.1 4 | ##reference=1000GenomesPilot-NCBI36 5 | ##contig= 6 | ##phasing=partial 7 | ##INFO= 8 | ##INFO= 9 | ##INFO= 10 | ##INFO= 11 | ##INFO= 12 | ##INFO= 13 | ##INFO= 14 | ##INFO= 15 | ##FILTER= 16 | ##FILTER= 17 | ##FORMAT= 18 | ##FORMAT= 19 | ##FORMAT= 20 | ##FORMAT= 21 | ##ALT= 22 | ##ALT= 23 | #CHROM POS ID REF ALT QUAL FILTER INFO FORMAT NA00001 NA00002 NA00003 24 | 20 14370 rs6054257 G A 29.2 q10;s50 NS=3;DP=14,22;AF=0.5;AA=String,Multi,Val;DB;H2 GT:GQ:DP:HQ 0|0:48:1:51,51 1|0:48:8:51,51 1/1:43:5:.,. 25 | 20 17330 . T A 3 q10 NS=3;DP=11;AF=0.017 GT:GQ:DP:HQ 0|0:49:3:58,50 0|1:3:5:65,3 0/0:41:3:.,. 26 | 20 1110696 rs6040355 A G,T 67 PASS NS=2;DP=10;AF=0.333,0.667;AA=FA,DADA;DB GT:GQ:DP:HQ 1|2:21:6:23,27 2|1:2:0:18,2 2/2:35:4:.,. 27 | 20 1230237 . T . 47 PASS NS=3;DP=13;AA=T GT:GQ:DP:HQ 0|0:54:.:56,60 0|0:48:4:51,51 0/0:61:2:.,. 28 | 20 1234567 microsat1 G GA,GAC 50 PASS NS=3;DP=9;AA=G;AN=6;AC=3,1 GT:GQ:DP 0/1:.:4 0/2:17:2 1/1:40:3 29 | 20 1235237 . T . . . . GT 0/0 0|0 ./. 30 | -------------------------------------------------------------------------------- /test/data/valid_fai.fai: -------------------------------------------------------------------------------- 1 | fastq1 66 8 30 31 79 2 | fastq2 28 156 14 15 188 3 | fastq2 84 12 566 988 91 4 | fastq3 29 72 146 19 134 5 | fastq4 66 8 30 31 79 6 | fastq5 28 156 14 15 188 7 | -------------------------------------------------------------------------------- /test/data/valid_with_header.bed: -------------------------------------------------------------------------------- 1 | browser position chr7:127471196-127495720 2 | browser hide all 3 | track name="ItemRGBDemo" description="Item RGB demonstration" visibility=2 itemRgb="On" 4 | chr7 127471196 127472363 Pos1 882.13435 + 127471196 127472363 255,0,0 4 11,12,13,14 14,55,66,99 5 | chr7 127472363 127473530 Pos2 0 + 127472363 127473530 255,0,0 6 | chr7 127473530 127474697 Pos3 0 + 127473530 127474697 255,0,0 7 | chr7 127474697 127475864 Pos4 0 + 127474697 127475864 255,0,0 8 | chr7 127475864 127477031 Neg1 0 - 127475864 127477031 0,0,255 9 | chr7 127477031 127478198 Neg2 0 - 127477031 127478198 0,0,255 10 | chr7 127478198 127479365 Neg3 0 - 127478198 127479365 0,0,255 11 | chr7 127479365 127480532 Pos5 0 + 127479365 127480532 255,0,0 12 | chr7 127480532 127481699 Neg4 0 - 127480532 127481699 0,0,255 13 | -------------------------------------------------------------------------------- /test/data/valid_without_header.bed: -------------------------------------------------------------------------------- 1 | chr7 127471196 127472363 Pos1 882.13435 + 127471196 127472363 255,0,0 4 11,12,13,14 14,55,66,99 2 | chr7 127472363 127473530 Pos2 0 + 127472363 127473530 255,0,0 3 | chr7 127473530 127474697 Pos3 0 + 127473530 127474697 255,0,0 4 | chr7 127474697 127475864 Pos4 0 + 127474697 127475864 255,0,0 5 | chr7 127475864 127477031 Neg1 0 - 127475864 127477031 0,0,255 6 | chr7 127477031 127478198 Neg2 0 - 127477031 127478198 0,0,255 7 | chr7 127478198 127479365 Neg3 0 - 127478198 127479365 0,0,255 8 | chr7 127479365 127480532 Pos5 0 + 127479365 127480532 255,0,0 9 | chr7 127480532 127481699 Neg4 0 - 127480532 127481699 0,0,255 10 | -------------------------------------------------------------------------------- /test/parser/a/__init__.seq: -------------------------------------------------------------------------------- 1 | def foo(): 2 | print 'a.foo' 3 | def bar(): 4 | print 'a.bar' 5 | print 'a' 6 | 7 | zoo = 5 8 | _zoo = 3 9 | -------------------------------------------------------------------------------- /test/parser/a/b/__init__.seq: -------------------------------------------------------------------------------- 1 | c = 'a.b.c' 2 | def har(): 3 | print 'a.b.har', __name__[-12:], c 4 | 5 | from .. import foo as fx 6 | 7 | class A: 8 | class B: 9 | def b_foo(): 10 | print 'a.b.A.B.b_foo()' 11 | return 1 12 | -------------------------------------------------------------------------------- /test/parser/a/b/rec1.seq: -------------------------------------------------------------------------------- 1 | print 'import rec1' 2 | 3 | var = 'x' 4 | 5 | import rec2 6 | rec2.foo() 7 | 8 | def bar(): 9 | print 'rec1.bar' 10 | 11 | print 'done rec1' 12 | -------------------------------------------------------------------------------- /test/parser/a/b/rec1_err.seq: -------------------------------------------------------------------------------- 1 | print 'import rec1' 2 | 3 | import rec2_err 4 | rec2_err.foo() 5 | 6 | def bar(): 7 | print 'rec1.bar' 8 | -------------------------------------------------------------------------------- /test/parser/a/b/rec2.seq: -------------------------------------------------------------------------------- 1 | print 'import rec2' 2 | 3 | from .rec1 import var 4 | 5 | def foo(): 6 | print 'rec2.' + var 7 | 8 | print 'done rec2' 9 | -------------------------------------------------------------------------------- /test/parser/a/b/rec2_err.seq: -------------------------------------------------------------------------------- 1 | print 'import rec2' 2 | 3 | from .rec1_err import bar 4 | bar() 5 | 6 | def foo(): 7 | print 'rec2.foo' 8 | -------------------------------------------------------------------------------- /test/pipeline/parallel.seq: -------------------------------------------------------------------------------- 1 | from threading import Lock, RLock 2 | 3 | n = 0 4 | f = 0.0 5 | 6 | @atomic 7 | def inc(_): 8 | global n, f 9 | n += 1 10 | f += 1.0 11 | return 0 12 | 13 | @atomic 14 | def dec(_): 15 | global n, f 16 | n -= 1 17 | f -= 1.0 18 | return 0 19 | 20 | lock = Lock() 21 | def inc_lock(_): 22 | global n 23 | with lock: 24 | n += 1 25 | return 0 26 | 27 | def dec_lock(_): 28 | global n 29 | with lock: 30 | n -= 1 31 | return 0 32 | 33 | rlock = RLock() 34 | def inc_rlock(_): 35 | global n 36 | with rlock: 37 | n += 1 38 | return 0 39 | 40 | def dec_rlock(_): 41 | global n 42 | with rlock: 43 | n -= 1 44 | return 0 45 | 46 | def foo(_): 47 | yield 0 48 | 49 | @test 50 | def test_parallel_pipe(m: int): 51 | global n, f 52 | n, f = 0, 0.0 53 | range(m) |> iter ||> inc 54 | assert n == m 55 | assert f == float(m) 56 | range(m) |> iter ||> dec 57 | assert n == 0 58 | assert f == 0.0 59 | range(m) |> iter ||> inc |> dec 60 | assert n == 0 61 | assert f == 0.0 62 | 63 | n = 0 64 | range(m) |> iter ||> inc_lock 65 | assert n == m 66 | range(m) |> iter ||> dec_lock 67 | assert n == 0 68 | range(m) |> iter ||> inc_lock |> dec_lock 69 | assert n == 0 70 | 71 | n = 0 72 | range(m) |> iter ||> inc_rlock 73 | assert n == m 74 | range(m) |> iter ||> dec_rlock 75 | assert n == 0 76 | range(m) |> iter ||> inc_rlock |> dec_rlock 77 | assert n == 0 78 | 79 | @test 80 | def test_nested_parallel_pipe(m: int): 81 | global n 82 | n = 0 83 | range(m) |> iter ||> inc |> foo ||> dec 84 | assert n == 0 85 | 86 | test_parallel_pipe(0) 87 | test_parallel_pipe(1) 88 | test_parallel_pipe(10) 89 | test_parallel_pipe(10000) 90 | 91 | test_nested_parallel_pipe(0) 92 | test_nested_parallel_pipe(1) 93 | test_nested_parallel_pipe(10) 94 | test_nested_parallel_pipe(10000) 95 | -------------------------------------------------------------------------------- /test/python/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seq-lang/seq/0c275584163c172e5e7f20562c314991ed3bcf37/test/python/__init__.py -------------------------------------------------------------------------------- /test/python/mymodule.py: -------------------------------------------------------------------------------- 1 | def multiply(a,b): 2 | return a*b 3 | 4 | def print_args(a,b,c,d,e): 5 | t = (a,b,c,d,e) 6 | if t != ((4, 5), {'a': 3.14, 'b': 2.123}, True, {'ACGT'}, [['abc'], ['1.1', '2.2'], []]): 7 | raise ValueError('TEST FAILED!') 8 | return ({'a': 3.14, 'b': 2.123}, (222, 3.14)) 9 | 10 | def print_args_var(a,b,c=1,*args,**kwargs): 11 | return 'a={}, b={}, c={}, args={}, kwargs={}'.format(a, b, c, args, kwargs) 12 | 13 | def throw_exc(): 14 | raise ValueError('foo') 15 | return 0 16 | -------------------------------------------------------------------------------- /test/python/pybridge.seq: -------------------------------------------------------------------------------- 1 | @test 2 | def test_basic(): 3 | from python import mymodule 4 | assert str(mymodule.multiply(3, 4)) == '12' 5 | test_basic() 6 | 7 | @test 8 | def test_pybridge(): 9 | @python 10 | def test_pydef(n: int) -> str: 11 | return ''.join(map(str, range(n))) 12 | assert test_pydef(5) == '01234' 13 | test_pybridge() 14 | 15 | from python import mymodule 16 | @test 17 | def test_conversions(): 18 | T = tuple[dict[str,float],tuple[int,float]] 19 | t = mymodule.print_args( 20 | (4,5), 21 | {'a': 3.14, 'b': 2.123}, 22 | True, 23 | {s'ACGT'}, 24 | [['abc'], ['1.1', '2.2'], list[str]()] 25 | ) 26 | assert T.__from_py__(t) == ({'a': 3.14, 'b': 2.123}, (222, 3.14)) 27 | test_conversions() 28 | 29 | @test 30 | def test_pythrow(): 31 | from python import mymodule.throw_exc() -> void as te 32 | try: 33 | te() 34 | except PyError as e: 35 | assert e.pytype + ":" + e.message == "ValueError:foo" 36 | return 37 | assert False 38 | test_pythrow() 39 | 40 | @test 41 | def test_pyargs(): 42 | from python import mymodule 43 | assert str(mymodule.print_args_var(1, 2, 3)) == "a=1, b=2, c=3, args=(), kwargs={}" 44 | assert str(mymodule.print_args_var(1, z=5, b=2)) == "a=1, b=2, c=1, args=(), kwargs={'z': 5}" 45 | assert str(mymodule.print_args_var(1, *(1,2,3,4,5), z=5)) == "a=1, b=1, c=2, args=(3, 4, 5), kwargs={'z': 5}" 46 | test_pyargs() 47 | -------------------------------------------------------------------------------- /test/sir/analyze/dominator.cpp: -------------------------------------------------------------------------------- 1 | #include "test.h" 2 | 3 | #include "sir/analyze/dataflow/cfg.h" 4 | #include "sir/analyze/dataflow/dominator.h" 5 | 6 | using namespace seq::ir; 7 | 8 | TEST_F(SIRCoreTest, DominatorAnalysisSimple) { 9 | auto *f = module->Nr("test_f"); 10 | auto *b = module->Nr(); 11 | f->setBody(b); 12 | 13 | auto *v = module->Nr(module->getIntType()); 14 | f->push_back(v); 15 | 16 | auto *start = module->getBool(false); 17 | auto *end = module->getBool(false); 18 | 19 | b->push_back(start); 20 | b->push_back(end); 21 | 22 | auto c = analyze::dataflow::buildCFGraph(f); 23 | analyze::dataflow::DominatorInspector dom(c.get()); 24 | dom.analyze(); 25 | 26 | ASSERT_TRUE(dom.isDominated(end, start)); 27 | ASSERT_FALSE(dom.isDominated(start, end)); 28 | } 29 | 30 | TEST_F(SIRCoreTest, DominatorAnalysisTernary) { 31 | auto *f = module->Nr("test_f"); 32 | auto *b = module->Nr(); 33 | f->setBody(b); 34 | 35 | auto *v = module->Nr(module->getIntType()); 36 | f->push_back(v); 37 | 38 | auto *start = module->getBool(false); 39 | auto *middle = module->getBool(false); 40 | auto *end = 41 | module->Nr(module->getBool(true), middle, module->getBool(true)); 42 | 43 | b->push_back(start); 44 | b->push_back(end); 45 | 46 | auto c = analyze::dataflow::buildCFGraph(f); 47 | analyze::dataflow::DominatorInspector dom(c.get()); 48 | dom.analyze(); 49 | 50 | ASSERT_TRUE(dom.isDominated(end, start)); 51 | ASSERT_TRUE(dom.isDominated(middle, start)); 52 | ASSERT_FALSE(dom.isDominated(start, end)); 53 | ASSERT_FALSE(dom.isDominated(end, middle)); 54 | } 55 | -------------------------------------------------------------------------------- /test/sir/constant.cpp: -------------------------------------------------------------------------------- 1 | #include "test.h" 2 | 3 | #include 4 | 5 | #include "util/fmt/format.h" 6 | 7 | using namespace seq::ir; 8 | 9 | TEST_F(SIRCoreTest, ConstTypeQueryAndReplace) { 10 | auto *node = module->Nr(1, module->getIntType()); 11 | ASSERT_EQ(module->getIntType(), node->getType()); 12 | 13 | auto usedTypes = node->getUsedTypes(); 14 | ASSERT_EQ(1, usedTypes.size()); 15 | ASSERT_EQ(module->getIntType(), usedTypes[0]); 16 | ASSERT_EQ(1, node->replaceUsedType(module->getIntType(), module->getIntType())); 17 | } 18 | 19 | TEST_F(SIRCoreTest, ConstCloning) { 20 | auto VALUE = 1; 21 | auto *node = module->Nr(VALUE, module->getIntType()); 22 | auto *clone = cast(cv->clone(node)); 23 | 24 | ASSERT_TRUE(clone); 25 | ASSERT_EQ(VALUE, clone->getVal()); 26 | ASSERT_EQ(module->getIntType(), clone->getType()); 27 | } 28 | -------------------------------------------------------------------------------- /test/sir/test.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "sir/sir.h" 4 | #include "sir/util/cloning.h" 5 | #include "gtest/gtest.h" 6 | 7 | class SIRCoreTest : public testing::Test { 8 | protected: 9 | std::unique_ptr module; 10 | std::unique_ptr cv; 11 | 12 | void SetUp() override { 13 | seq::ir::IdMixin::resetId(); 14 | module = std::make_unique("test"); 15 | cv = std::make_unique(module.get()); 16 | } 17 | }; 18 | -------------------------------------------------------------------------------- /test/sir/types/types.cpp: -------------------------------------------------------------------------------- 1 | #include "test.h" 2 | 3 | #include 4 | 5 | using namespace seq::ir; 6 | 7 | TEST_F(SIRCoreTest, RecordTypeQuery) { 8 | auto MEMBER_NAME = "1"; 9 | auto *type = module->Nr( 10 | "foo", std::vector{module->getIntType()}); 11 | 12 | ASSERT_EQ(module->getIntType(), type->getMemberType(MEMBER_NAME)); 13 | ASSERT_EQ(0, type->getMemberIndex(MEMBER_NAME)); 14 | 15 | ASSERT_EQ(1, std::distance(type->begin(), type->end())); 16 | ASSERT_EQ(module->getIntType(), type->front().getType()); 17 | 18 | MEMBER_NAME = "baz"; 19 | type->realize({module->getIntType()}, {MEMBER_NAME}); 20 | 21 | ASSERT_TRUE(type->isAtomic()); 22 | 23 | ASSERT_EQ(1, type->getUsedTypes().size()); 24 | ASSERT_EQ(module->getIntType(), type->getUsedTypes()[0]); 25 | } 26 | 27 | TEST_F(SIRCoreTest, RefTypeQuery) { 28 | auto MEMBER_NAME = "1"; 29 | auto *contents = module->Nr( 30 | "foo", std::vector{module->getIntType()}); 31 | auto *type = module->Nr("baz", contents); 32 | 33 | ASSERT_EQ(module->getIntType(), type->getMemberType(MEMBER_NAME)); 34 | ASSERT_EQ(0, type->getMemberIndex(MEMBER_NAME)); 35 | 36 | ASSERT_EQ(1, std::distance(type->begin(), type->end())); 37 | ASSERT_EQ(module->getIntType(), type->front().getType()); 38 | 39 | MEMBER_NAME = "baz"; 40 | type->realize({module->getIntType()}, {MEMBER_NAME}); 41 | 42 | ASSERT_FALSE(type->isAtomic()); 43 | 44 | ASSERT_EQ(1, type->getUsedTypes().size()); 45 | ASSERT_EQ(contents, type->getUsedTypes()[0]); 46 | } 47 | 48 | TEST_F(SIRCoreTest, FuncTypeQuery) { 49 | auto *type = module->Nr( 50 | "foo", module->getIntType(), std::vector{module->getFloatType()}); 51 | 52 | ASSERT_EQ(1, std::distance(type->begin(), type->end())); 53 | ASSERT_EQ(module->getFloatType(), type->front()); 54 | 55 | ASSERT_EQ(2, type->getUsedTypes().size()); 56 | } 57 | -------------------------------------------------------------------------------- /test/sir/value.cpp: -------------------------------------------------------------------------------- 1 | #include "test.h" 2 | 3 | using namespace seq::ir; 4 | 5 | TEST_F(SIRCoreTest, ValueQueryMethodsDelegate) { 6 | Value *original = module->Nr(1, module->getIntType(), "foo"); 7 | auto originalRef = original->referenceString(); 8 | 9 | auto *fn = module->Nr(); 10 | fn->realize(module->unsafeGetDummyFuncType(), {}); 11 | Value *replacement = module->Nr(fn, "baz"); 12 | original->replaceAll(replacement); 13 | 14 | ASSERT_NE(originalRef, original->referenceString()); 15 | ASSERT_EQ(original->referenceString(), replacement->referenceString()); 16 | 17 | ASSERT_EQ(1, original->getUsedVariables().size()); 18 | 19 | replacement = module->Nr(replacement); 20 | original->replaceAll(replacement); 21 | ASSERT_EQ(0, original->getUsedVariables().size()); 22 | ASSERT_EQ(1, original->getUsedValues().size()); 23 | ASSERT_EQ(module->getVoidType(), original->getType()); 24 | 25 | replacement = module->Nr(module->getIntType(), 26 | TypePropertyInstr::Property::SIZEOF); 27 | original->replaceAll(replacement); 28 | ASSERT_EQ(0, original->getUsedVariables().size()); 29 | ASSERT_EQ(0, original->getUsedValues().size()); 30 | ASSERT_EQ(1, original->getUsedTypes().size()); 31 | } 32 | 33 | TEST_F(SIRCoreTest, ValueReplaceMethodsDelegate) { 34 | Value *original = module->Nr(1, module->getIntType(), "foo"); 35 | auto originalRef = original->referenceString(); 36 | auto originalId = original->getId(); 37 | auto *var = module->Nr(); 38 | Value *replacement = module->Nr(var, "baz"); 39 | original->replaceAll(replacement); 40 | 41 | ASSERT_EQ(1, original->replaceUsedVariable(var, var)); 42 | 43 | auto *val = replacement; 44 | replacement = module->Nr(replacement); 45 | original->replaceAll(replacement); 46 | ASSERT_EQ(1, original->replaceUsedValue(val, val)); 47 | 48 | replacement = module->Nr(module->getIntType(), 49 | TypePropertyInstr::Property::SIZEOF); 50 | original->replaceAll(replacement); 51 | ASSERT_EQ(1, original->replaceUsedType(module->getIntType(), module->getFloatType())); 52 | 53 | ASSERT_NE(originalId, original->getId()); 54 | ASSERT_EQ(original->getId(), replacement->getId()); 55 | } 56 | -------------------------------------------------------------------------------- /test/sir/var.cpp: -------------------------------------------------------------------------------- 1 | #include "test.h" 2 | 3 | using namespace seq::ir; 4 | 5 | TEST_F(SIRCoreTest, VarQueryMethodsDelegate) { 6 | Var *original = module->Nr(module->getIntType()); 7 | Var *replacement = module->Nr(module->getFloatType()); 8 | original->replaceAll(replacement); 9 | 10 | ASSERT_EQ(module->getFloatType(), original->getType()); 11 | ASSERT_EQ(module->getFloatType(), original->getUsedTypes().back()); 12 | } 13 | 14 | TEST_F(SIRCoreTest, VarReplaceMethodsDelegate) { 15 | Var *original = module->Nr(module->getIntType()); 16 | Var *replacement = module->Nr(module->getFloatType()); 17 | 18 | auto originalId = original->getId(); 19 | original->replaceAll(replacement); 20 | 21 | ASSERT_EQ(1, original->replaceUsedType(module->getFloatType(), module->getIntType())); 22 | ASSERT_NE(originalId, original->getId()); 23 | ASSERT_EQ(original->getId(), replacement->getId()); 24 | } 25 | -------------------------------------------------------------------------------- /test/stdlib/random_test.seq: -------------------------------------------------------------------------------- 1 | import random as R 2 | import time 3 | import sys 4 | 5 | seed = int(time.time()) 6 | # sys.stderr.write('seed: ' + str(seed) + '\n') 7 | R.seed(seed) 8 | 9 | @test 10 | def test_rnd_result(name, results, invariant): 11 | print name 12 | for a in results: 13 | assert invariant(a) 14 | 15 | test_rnd_result('randrange', [R.randrange(10) for _ in range(100)], range(10).__contains__) 16 | test_rnd_result('randrange', [R.randrange(5, 20) for _ in range(100)], range(5, 20).__contains__) 17 | test_rnd_result('randrange', [R.randrange(9, 99, 3) for _ in range(100)], range(9, 99, 3).__contains__) 18 | test_rnd_result('randint', [R.randint(5, 20) for _ in range(100)], range(5, 20 + 1).__contains__) 19 | 20 | population = list('ABCDEFGHIJKLMNOP') 21 | test_rnd_result('choice', [R.choice(population) for _ in range(100)], population.__contains__) 22 | test_rnd_result('choice', [R.choice(population) for _ in range(100)], population.__contains__) 23 | test_rnd_result('choices', R.choices(population), population.__contains__) 24 | test_rnd_result('choices', R.choices(population, k=100), population.__contains__) 25 | 26 | @test 27 | def test_shuffle(v): 28 | s = copy(v) 29 | R.shuffle(s) 30 | assert sorted(v) == sorted(s) 31 | 32 | test_shuffle(list(range(100))) 33 | 34 | @test 35 | def test_sample(n: int, k: int): 36 | s = R.sample(list(range(n)), k=k) 37 | assert len(s) == k 38 | assert len(set(s)) == len(s) 39 | for a in s: 40 | assert a in range(n) 41 | 42 | test_sample(100, 5) 43 | test_sample(100, 100) 44 | test_sample(100, 0) 45 | -------------------------------------------------------------------------------- /test/stdlib/sort_test.seq: -------------------------------------------------------------------------------- 1 | from algorithms.qsort import qsort_inplace 2 | from algorithms.heapsort import heap_sort_inplace 3 | from algorithms.pdqsort import pdq_sort_inplace 4 | from algorithms.timsort import tim_sort_inplace 5 | from time import time 6 | 7 | def key(n: int): 8 | return -n 9 | 10 | def gen_list(n: int): 11 | import random 12 | v = List[int](n) 13 | for _ in range(n): 14 | v.append(random.randint(0, 10000)) 15 | return v 16 | 17 | def copy_to(a, b): 18 | b.clear() 19 | for i in a: 20 | b.append(i) 21 | 22 | @test 23 | def ensure_sorted(v): 24 | for i in range(len(v) - 1): 25 | assert key(v[i]) <= key(v[i + 1]) 26 | 27 | v0 = gen_list(100) 28 | v1 = List[int](len(v0)) 29 | 30 | def test_sort1(name, sort): 31 | copy_to(v0, v1) 32 | t0 = time() 33 | sort(v1, key) 34 | t1 = time() 35 | print name, t1 - t0 36 | ensure_sorted(v1) 37 | 38 | test_sort1('qsort :', qsort_inplace) 39 | test_sort1('heapsort:', heap_sort_inplace) 40 | test_sort1('pdqsort :', pdq_sort_inplace) 41 | # test_sort1('timsort :', tim_sort_inplace[int,int]) 42 | 43 | @test 44 | def test_sort2(name, sort): 45 | from random import shuffle 46 | fail = False 47 | print name 48 | for N in (0, 1, 10, 100, 1000, 10000): #, 100000): # too slow; maybe add later? 49 | print N 50 | for i in range(1000): 51 | v = list(range(N)) 52 | shuffle(v) 53 | sort(v, key) 54 | if v != list(reversed(range(N))): 55 | fail = True 56 | assert not fail 57 | 58 | test_sort2('qsort :', qsort_inplace) 59 | test_sort2('heapsort:', heap_sort_inplace) 60 | test_sort2('pdqsort :', pdq_sort_inplace) 61 | # test_sort2('timsort :', tim_sort_inplace[int,int]) 62 | 63 | # test standard sort routines 64 | @test 65 | def test_standard_sort(): 66 | copy_to(v0, v1) 67 | v2 = sorted(v1) 68 | for i in range(len(v2) - 1): 69 | assert v2[i] <= v2[i + 1] 70 | 71 | v2 = sorted(v1, key=key) 72 | for i in range(len(v2) - 1): 73 | assert key(v2[i]) <= key(v2[i + 1]) 74 | 75 | v2.sort() 76 | for i in range(len(v2) - 1): 77 | assert v2[i] <= v2[i + 1] 78 | 79 | v2.sort(key=key) 80 | for i in range(len(v2) - 1): 81 | assert key(v2[i]) <= key(v2[i + 1]) 82 | 83 | test_standard_sort() 84 | -------------------------------------------------------------------------------- /test/transform/for_lowering.seq: -------------------------------------------------------------------------------- 1 | @extend 2 | class range: 3 | def __iter__(self): 4 | yield 999 5 | 6 | @test 7 | def test_for_lowering(): 8 | from random import randint 9 | x = 10 10 | v = [] 11 | for i in range(x): 12 | v.append(i) 13 | assert v == [0,1,2,3,4,5,6,7,8,9] 14 | 15 | v = [] 16 | for i in range(x - 11, x//10): 17 | v.append(i) 18 | assert v == [-1, 0] 19 | 20 | v = [] 21 | for i in range(x, -x): 22 | v.append(i) 23 | assert v == [] 24 | 25 | v = [] 26 | for i in range(x//3, -x//3, -2): 27 | v.append(i) 28 | assert v == [3, 1, -1] 29 | 30 | v = [] 31 | for i in range(-1, 7, 3): 32 | v.append(i) 33 | assert v == [-1, 2, 5] 34 | 35 | v = [] 36 | for i in range(0, 1, randint(1,1)): # no lowering for non-const step 37 | v.append(i) 38 | assert v == [999] 39 | 40 | v = [] 41 | try: 42 | for i in range(0, 1, 0): # no lowering for zero step 43 | v.append(i) 44 | v.append(-1) 45 | except: 46 | v.append(-2) 47 | assert v == [-2] 48 | 49 | v = [] 50 | for i in range(5): 51 | if i == 1: 52 | continue 53 | if i == 3: 54 | break 55 | v.append(i) 56 | assert v == [0, 2] 57 | 58 | test_for_lowering() 59 | -------------------------------------------------------------------------------- /test/transform/inlining.seq: -------------------------------------------------------------------------------- 1 | v = 1 2 | v = 2 3 | 4 | def inline_me_aggressive_simple(): 5 | return 1 6 | 7 | def inline_me_aggressive_complex(): 8 | while True: 9 | if v == 1: 10 | return 1 11 | return 2 12 | 13 | def inline_me_aggressive_args(x): 14 | return x + 1 15 | 16 | def inline_me_simple(): 17 | return 1 18 | 19 | def inline_me_complex(): 20 | while True: 21 | if v == 1: 22 | return 1 23 | return 2 24 | 25 | def inline_me_args(x): 26 | return x + 1 27 | 28 | @test 29 | def inlining_test(): 30 | assert inline_me_simple() == -1 31 | assert inline_me_complex() == 2 32 | assert inline_me_args(2) == -3 33 | assert inline_me_aggressive_simple() == -1 34 | assert inline_me_aggressive_complex() == -2 35 | assert inline_me_aggressive_args(2) == -3 36 | 37 | inlining_test() 38 | 39 | def inline_me_aggressive_nested_while_finally(n): 40 | while n != 0: 41 | try: 42 | while n != 0: 43 | if n == 42: 44 | n -= 1 45 | continue 46 | try: 47 | if n > 0: 48 | continue 49 | else: 50 | break 51 | finally: 52 | return -1 53 | return -2 54 | finally: 55 | return n + 1 56 | 57 | def inline_test_nested_while_finally(): 58 | a = 42 59 | checkpoint1 = False 60 | checkpoint2 = False 61 | checkpoint3 = False 62 | try: 63 | while a != 4: 64 | try: 65 | a = inline_me_aggressive_nested_while_finally(a) 66 | checkpoint1 = True 67 | assert a == -42 68 | finally: 69 | a = 4 70 | checkpoint2 = True 71 | assert a == 4 72 | finally: 73 | checkpoint3 = True 74 | assert a == 4 75 | a = 5 76 | assert a == 5 77 | assert checkpoint1 78 | assert checkpoint2 79 | assert checkpoint3 80 | 81 | inline_test_nested_while_finally() 82 | -------------------------------------------------------------------------------- /test/transform/io_opt.seq: -------------------------------------------------------------------------------- 1 | class DummyFile: 2 | write_count: int = 0 3 | write_gen_count: int = 0 4 | 5 | def write(self, s: str): 6 | self.write_count += 1 7 | def __file_write_gen__(self, g): 8 | self.write_gen_count += 1 9 | 10 | @test 11 | def test_file_io(): 12 | f = DummyFile() 13 | f.write('') # opt not applied 14 | f.write('hello world') # opt not applied 15 | f.write(str.cat("hello ", "world")) # opt applied 16 | a, b, c = 3.14, 'xyz', 42 17 | f.write(f'hello {a} world {b=} abc {a+c} zzz') # opt applied 18 | f.write(f'hello world') # opt applied 19 | assert f.write_count == 2 20 | assert f.write_gen_count == 3 21 | test_file_io() 22 | 23 | @test 24 | def test_print(): 25 | from sys import stdout 26 | print('hello world') # EXPECT: hello world 27 | print(str.cat("hello ", "world")) # EXPECT: hello world 28 | a, b, c = 3.14, 'xyz', 42 29 | print(f'hello {a} world {b=} abc {a+c} zzz', file=stdout, sep='x') # EXPECT: hello 3.14 world b=xyz abc 45.14 zzz 30 | print(f'hello', f'world', sep='x') # EXPECT: helloxworld 31 | test_print() 32 | -------------------------------------------------------------------------------- /test/transform/str_opt.seq: -------------------------------------------------------------------------------- 1 | cat_count = 0 2 | 3 | # c/p from str.seq 4 | def old_cat(*args): 5 | total = 0 6 | if staticlen(args) == 1 and hasattr(args[0], "__iter__") and hasattr(args[0], "__len__"): 7 | for s in args[0]: 8 | if not isinstance(s, str): 9 | compile_error("not a string") 10 | total += s.len 11 | p = cobj(total) 12 | n = 0 13 | for s in args[0]: 14 | str.memcpy(p + n, s.ptr, s.len) 15 | n += s.len 16 | return str(p, total) 17 | elif staticlen(args) == 1 and hasattr(args[0], "__iter__"): 18 | sz = 10 19 | p = cobj(sz) 20 | n = 0 21 | for s in args[0]: 22 | if not isinstance(s, str): 23 | compile_error("not a string") 24 | if n + s.len > sz: 25 | sz = 1 + 3 * (n + s.len) // 2 26 | pp = cobj(sz) 27 | str.memcpy(pp, p, n) 28 | p = pp 29 | str.memcpy(p + n, s.ptr, s.len) 30 | n += s.len 31 | return str(p, n) 32 | else: 33 | total = 0 34 | for i in args: 35 | if not isinstance(i, str): 36 | compile_error("not a string") 37 | total += i.len 38 | p = cobj(total) 39 | n = 0 40 | for i in args: 41 | str.memcpy(p + n, i.ptr, i.len) 42 | n += i.len 43 | return str(p, total) 44 | 45 | @extend 46 | class str: 47 | def cat(*args): 48 | global cat_count 49 | cat_count += 1 50 | return old_cat(*args) 51 | 52 | @test 53 | def test_str_optimization(): 54 | assert 'hello ' + 'world' == "hello world" # no opt: just adding 2 strs 55 | assert cat_count == 0 56 | # assert 'a' + 'b' + 'c' == 'abc' # superseded by string statics 57 | # assert cat_count == 1 58 | assert 'a' * 2 == 'aa' # no opt: mul instead of add 59 | assert cat_count == 0 60 | # assert 'a' + ('b' + 'c') == 'abc' 61 | # assert cat_count == 2 62 | # assert 'a' + ('b' + ('c' + 'd')) == 'abcd' 63 | # assert cat_count == 3 64 | 65 | a = 'a' 66 | b = 'b' 67 | c = 'c' 68 | assert (a*2 + b*3 + c*4) == 'aabbbcccc' 69 | assert cat_count == 1 70 | test_str_optimization() 71 | -------------------------------------------------------------------------------- /test/types.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include "parser/common.h" 16 | #include "parser/parser.h" 17 | #include "util/common.h" 18 | #include "gtest/gtest.h" 19 | 20 | TEST(TypeCoreTest, TestName) { ; } 21 | -------------------------------------------------------------------------------- /util/jupyter/README.md: -------------------------------------------------------------------------------- 1 | # Seq Kernel 2 | 3 | A seq kernel for Jupyter. 4 | 5 | ## To Install 6 | 7 | ```bash 8 | python3 -m pip install /seq/jupyter 9 | python3 -m seq_kernel.install 10 | ``` 11 | 12 | ## To Use 13 | 14 | ```bash 15 | jupyter notebook 16 | # In the notebook interface, select Seq from the 'New' menu 17 | jupyter qtconsole --kernel seq 18 | jupyter console --kernel seq 19 | ``` 20 | -------------------------------------------------------------------------------- /util/jupyter/seq_kernel/__init__.py: -------------------------------------------------------------------------------- 1 | """A seq kernel for Jupyter""" 2 | 3 | from .kernel import __version__ 4 | -------------------------------------------------------------------------------- /util/jupyter/seq_kernel/__main__.py: -------------------------------------------------------------------------------- 1 | from ipykernel.kernelapp import IPKernelApp 2 | from .kernel import SeqKernel 3 | IPKernelApp.launch_instance(kernel_class=SeqKernel) 4 | -------------------------------------------------------------------------------- /util/jupyter/seq_kernel/install.py: -------------------------------------------------------------------------------- 1 | import json 2 | import os 3 | import sys 4 | import argparse 5 | 6 | from jupyter_client.kernelspec import KernelSpecManager 7 | from IPython.utils.tempdir import TemporaryDirectory 8 | from shutil import copyfile 9 | 10 | kernel_json = { 11 | "argv":[sys.executable,"-m","seq_kernel", "-f", "{connection_file}"], 12 | "display_name":"Seq", 13 | "language":"seq", 14 | } 15 | 16 | def install_my_kernel_spec(user=True, prefix=None): 17 | with TemporaryDirectory() as td: 18 | os.chmod(td, 0o755) # Starts off as 700, not user readable 19 | with open(os.path.join(td, 'kernel.json'), 'w') as f: 20 | json.dump(kernel_json, f, sort_keys=True) 21 | 22 | print('Installing IPython kernel spec') 23 | KernelSpecManager().install_kernel_spec(td, 'seq', user=user, prefix=prefix) 24 | 25 | def install_my_kernel_javascript(): 26 | seq_js_file = os.path.join(os.environ['SEQ_PATH'][:-7], 'jupyter', 'seq_kernel', 'kernel.js') 27 | kernel_js_file = os.path.join(KernelSpecManager().get_kernel_spec('seq').resource_dir, 'kernel.js') 28 | os.system(f'cp {seq_js_file} {kernel_js_file}') 29 | 30 | def _is_root(): 31 | try: 32 | return os.geteuid() == 0 33 | except AttributeError: 34 | return False # assume not an admin on non-Unix platforms 35 | 36 | def main(argv=None): 37 | parser = argparse.ArgumentParser( 38 | description='Install KernelSpec for Seq Kernel' 39 | ) 40 | prefix_locations = parser.add_mutually_exclusive_group() 41 | 42 | prefix_locations.add_argument( 43 | '--user', 44 | help='Install KernelSpec in user homedirectory', 45 | action='store_true' 46 | ) 47 | prefix_locations.add_argument( 48 | '--sys-prefix', 49 | help='Install KernelSpec in sys.prefix. Useful in conda / virtualenv', 50 | action='store_true', 51 | dest='sys_prefix' 52 | ) 53 | prefix_locations.add_argument( 54 | '--prefix', 55 | help='Install KernelSpec in this prefix', 56 | default=None 57 | ) 58 | 59 | args = parser.parse_args(argv) 60 | 61 | user = False 62 | prefix = None 63 | if args.sys_prefix: 64 | prefix = sys.prefix 65 | elif args.prefix: 66 | prefix = args.prefix 67 | elif args.user or not _is_root(): 68 | user = True 69 | 70 | install_my_kernel_spec(user=user, prefix=prefix) 71 | install_my_kernel_javascript() 72 | 73 | if __name__ == '__main__': 74 | main() 75 | -------------------------------------------------------------------------------- /util/jupyter/seq_kernel/wrapper.py: -------------------------------------------------------------------------------- 1 | # Exec 2 | 3 | class SeqWrapper: 4 | def __init__(self): 5 | import ctypes 6 | import ctypes.util 7 | 8 | lib = ctypes.util.find_library("seqjit") 9 | self._lib = ctypes.CDLL(lib, ctypes.RTLD_GLOBAL) 10 | 11 | self._init_fn = self._lib.seq_jit_init 12 | self._init_fn.restype = ctypes.c_void_p 13 | 14 | self._exec_fn = self._lib.seq_jit_exec 15 | self._exec_fn.argtypes = [ctypes.c_void_p, ctypes.c_char_p] 16 | 17 | self._inspect_fn = self._lib.seq_jit_inspect 18 | self._inspect_fn.argtypes = [ 19 | ctypes.c_void_p, ctypes.c_char_p, ctypes.c_int, ctypes.c_int 20 | ] 21 | self._inspect_fn.restype = ctypes.c_char_p 22 | 23 | self._document_fn = self._lib.seq_jit_document 24 | self._document_fn.argtypes = [ctypes.c_void_p, ctypes.c_char_p] 25 | self._document_fn.restype = ctypes.c_char_p 26 | 27 | self._complete_fn = self._lib.seq_jit_complete 28 | self._complete_fn.argtypes = [ctypes.c_void_p, ctypes.c_char_p] 29 | self._complete_fn.restype = ctypes.c_char_p 30 | 31 | self.handle = self._init_fn() 32 | 33 | def exec(self, code): 34 | self._exec_fn(self.handle, code.encode('utf-8')) 35 | 36 | def inspect(self, cell, line, column): 37 | file = f'' 38 | return self._inspect_fn(self.handle, file.encode('utf-8'), line, column).decode('ascii') 39 | 40 | def document(self, idn): 41 | return self._document_fn(self.handle, idn.encode('utf-8')).decode('ascii') 42 | 43 | def complete(self, prefix): 44 | l = self._complete_fn(self.handle, prefix.encode('utf-8')).decode('ascii') 45 | return l.split('\b') 46 | -------------------------------------------------------------------------------- /util/jupyter/setup.py: -------------------------------------------------------------------------------- 1 | import setuptools 2 | from seq_kernel.kernel import __version__ 3 | 4 | with open('README.md', 'r') as fh: 5 | long_description = fh.read() 6 | 7 | setuptools.setup( 8 | name='seq_kernel', 9 | version=__version__, 10 | description='Seq Kernel', 11 | long_description=long_description, 12 | long_description_content_type='text/markdown', 13 | url='https://github.com/seq-lang/seq', 14 | packages=setuptools.find_packages(), 15 | entry_points={'pygments.lexers': 'seq = seq_kernel.seqlex:SeqLexer'}, 16 | classifiers=[ 17 | 'Framework :: Jupyter', 18 | 'Intended Audience :: Science/Research', 19 | 'Programming Language :: Python' 20 | 'Programming Language :: Seq', 21 | ] 22 | ) 23 | -------------------------------------------------------------------------------- /util/jupyter/wrapper.py: -------------------------------------------------------------------------------- 1 | # Exec 2 | 3 | class SeqWrapper: 4 | def __init__(self): 5 | import ctypes 6 | import ctypes.util 7 | 8 | lib = ctypes.util.find_library("seqjit") 9 | self._lib = ctypes.CDLL(lib, ctypes.RTLD_GLOBAL) 10 | 11 | self._init_fn = self._lib.seq_jit_init 12 | self._init_fn.restype = ctypes.c_void_p 13 | 14 | self._exec_fn = self._lib.seq_jit_exec 15 | self._exec_fn.argtypes = [ctypes.c_void_p, ctypes.c_char_p] 16 | 17 | self._inspect_fn = self._lib.seq_jit_inspect 18 | self._inspect_fn.argtypes = [ 19 | ctypes.c_void_p, ctypes.c_char_p, ctypes.c_int, ctypes.c_int 20 | ] 21 | self._inspect_fn.restype = ctypes.c_char_p 22 | 23 | self._document_fn = self._lib.seq_jit_document 24 | self._document_fn.argtypes = [ctypes.c_void_p, ctypes.c_char_p] 25 | self._document_fn.restype = ctypes.c_char_p 26 | 27 | self._complete_fn = self._lib.seq_jit_complete 28 | self._complete_fn.argtypes = [ctypes.c_void_p, ctypes.c_char_p] 29 | self._complete_fn.restype = ctypes.c_char_p 30 | 31 | self.handle = self._init_fn() 32 | 33 | def exec(self, code): 34 | self._exec_fn(self.handle, code.encode('utf-8')) 35 | 36 | def inspect(self, cell, line, column): 37 | file = f'' 38 | return self._inspect_fn(self.handle, file.encode('utf-8'), line, column).decode('ascii') 39 | 40 | def document(self, idn): 41 | return self._document_fn(self.handle, idn.encode('utf-8')).decode('ascii') 42 | 43 | def complete(self, prefix): 44 | l = self._complete_fn(self.handle, prefix.encode('utf-8')).decode('ascii') 45 | return l.split('\b') 46 | 47 | s = SeqWrapper() 48 | 49 | s.exec(""" 50 | print 'hello' 51 | x = 1 52 | print x 53 | def foo(bar): 54 | ''' HAI ''' 55 | print 'foo', bar 56 | y = 2 57 | print x, y, x + y 58 | """) 59 | 60 | s.exec(""" 61 | x += 1 62 | print x 63 | foo(x+100) 64 | """) 65 | 66 | print('i: ', s.inspect(2, 3, 6)) 67 | print('i: ', s.inspect(2, 4, 1)) 68 | print('d: ', s.document("foo")) 69 | print('d: ', s.document("list")) 70 | print('c: ', s.complete("m")) 71 | 72 | -------------------------------------------------------------------------------- /util/vscode/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | out -------------------------------------------------------------------------------- /util/vscode/README.md: -------------------------------------------------------------------------------- 1 | # Seq LSP 2 | 3 | ## Running the Client and Server 4 | 5 | - Run `yarn` then `yarn run watch` in this folder. This installs all necessary npm modules in both the client and server folder. Then compiles the typescript. 6 | - Open VS Code on this folder. 7 | - Switch to the Debug viewlet. 8 | - Select `Client + Server` from the drop down. 9 | - Run the launch config. 10 | -------------------------------------------------------------------------------- /util/vscode/client/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "lsp-seq-client", 3 | "description": "VSCode part of a language server", 4 | "author": "seq-lang", 5 | "license": "MIT", 6 | "version": "0.0.1", 7 | "repository": { 8 | "type": "git", 9 | "url": "https://github.com/seq-lang/seq" 10 | }, 11 | "engines": { 12 | "vscode": "^1.33.0" 13 | }, 14 | "scripts": { 15 | "update-vscode": "vscode-install", 16 | "postinstall": "vscode-install" 17 | }, 18 | "dependencies": { 19 | "vscode-languageclient": "^5.2.1" 20 | }, 21 | "devDependencies": { 22 | "vscode": "^1.1.35" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /util/vscode/client/src/extension.ts: -------------------------------------------------------------------------------- 1 | import * as path from 'path'; 2 | import { workspace, ExtensionContext } from 'vscode'; 3 | 4 | import { 5 | LanguageClient, 6 | LanguageClientOptions, 7 | ServerOptions, 8 | TransportKind 9 | } from 'vscode-languageclient'; 10 | 11 | let client: LanguageClient; 12 | 13 | export function activate(context: ExtensionContext) { 14 | let serverModule = context.asAbsolutePath( 15 | path.join('server', 'out', 'server.js') 16 | ); 17 | let debugOptions = { execArgv: ['--nolazy', '--inspect=6009'] }; 18 | 19 | let serverOptions: ServerOptions = { 20 | run: { module: serverModule, transport: TransportKind.ipc }, 21 | debug: { 22 | module: serverModule, 23 | transport: TransportKind.ipc, 24 | options: debugOptions 25 | } 26 | }; 27 | 28 | let clientOptions: LanguageClientOptions = { 29 | documentSelector: [{ scheme: 'file', language: 'seq' }], 30 | synchronize: { 31 | fileEvents: workspace.createFileSystemWatcher('**/.clientrc') 32 | } 33 | }; 34 | 35 | client = new LanguageClient( 36 | 'languageServerSeq', 37 | 'Language Server Seq', 38 | serverOptions, 39 | clientOptions 40 | ); 41 | 42 | client.start(); 43 | } 44 | 45 | export function deactivate(): Thenable | undefined { 46 | if (!client) { 47 | return undefined; 48 | } 49 | return client.stop(); 50 | } 51 | -------------------------------------------------------------------------------- /util/vscode/client/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "target": "es6", 5 | "outDir": "out", 6 | "rootDir": "src", 7 | "sourceMap": true 8 | }, 9 | "include": ["src"], 10 | "exclude": ["node_modules", ".vscode-test"] 11 | } 12 | -------------------------------------------------------------------------------- /util/vscode/language-configuration.json: -------------------------------------------------------------------------------- 1 | { 2 | "comments": { 3 | "blockComment": [ 4 | "'''", 5 | "'''" 6 | ], 7 | "lineComment": "#" 8 | }, 9 | "brackets": [ 10 | [ 11 | "(", 12 | ")" 13 | ], 14 | [ 15 | "[", 16 | "]" 17 | ], 18 | [ 19 | "{", 20 | "}" 21 | ] 22 | ], 23 | "autoClosingPairs": [ 24 | [ 25 | "(", 26 | ")" 27 | ], 28 | [ 29 | "[", 30 | "]" 31 | ], 32 | [ 33 | "{", 34 | "}" 35 | ] 36 | ], 37 | "surroundingPairs": [ 38 | [ 39 | "(", 40 | ")" 41 | ], 42 | [ 43 | "[", 44 | "]" 45 | ], 46 | [ 47 | "{", 48 | "}" 49 | ] 50 | ] 51 | } -------------------------------------------------------------------------------- /util/vscode/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "seq-lang", 3 | "description": "A language server for seq", 4 | "author": "seq-lang", 5 | "license": "MIT", 6 | "version": "0.0.1", 7 | "repository": { 8 | "type": "git", 9 | "url": "https://github.com/seq-lang/seq" 10 | }, 11 | "categories": [], 12 | "keywords": [ 13 | "multi-root ready" 14 | ], 15 | "engines": { 16 | "vscode": "^1.33.0" 17 | }, 18 | "activationEvents": [ 19 | "onLanguage:seq" 20 | ], 21 | "main": "./client/out/extension", 22 | "contributes": { 23 | "languages": [ 24 | { 25 | "id": "seq", 26 | "aliases": [ 27 | "Seq", 28 | "seq-lang" 29 | ], 30 | "extensions": [ 31 | ".seq" 32 | ], 33 | "configuration": "./language-configuration.json" 34 | } 35 | ], 36 | "grammars": [ 37 | { 38 | "language": "seq", 39 | "scopeName": "source.seq", 40 | "path": "./syntaxes/seq.tmLanguage.json" 41 | } 42 | ], 43 | "configuration": { 44 | "type": "object", 45 | "title": "Seq configuration", 46 | "properties": { 47 | "languageServerSeq.maxNumberOfProblems": { 48 | "scope": "resource", 49 | "type": "number", 50 | "default": 100, 51 | "description": "Controls the maximum number of problems produced by the server." 52 | }, 53 | "languageServerSeq.trace.server": { 54 | "scope": "window", 55 | "type": "string", 56 | "enum": [ 57 | "off", 58 | "messages", 59 | "verbose" 60 | ], 61 | "default": "off", 62 | "description": "Traces the communication between VS Code and the language server." 63 | } 64 | } 65 | } 66 | }, 67 | "scripts": { 68 | "vscode:prepublish": "cd client && yarn run update-vscode && cd .. && yarn run compile", 69 | "compile": "tsc -b", 70 | "watch": "tsc -b -w", 71 | "postinstall": "cd client && yarn && cd ../server && yarn && cd .." 72 | }, 73 | "devDependencies": { 74 | "@types/mocha": "^5.2.7", 75 | "@types/node": "^12.11.7", 76 | "tslint": "^5.16.0", 77 | "typescript": "^3.6.4" 78 | }, 79 | "dependencies": {} 80 | } 81 | -------------------------------------------------------------------------------- /util/vscode/server/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "lsp-seq-server", 3 | "description": "The seq language server.", 4 | "version": "0.0.1", 5 | "author": "seq-lang", 6 | "license": "MIT", 7 | "engines": { 8 | "node": "*" 9 | }, 10 | "repository": { 11 | "type": "git", 12 | "url": "https://github.com/seq-lang/seq" 13 | }, 14 | "dependencies": { 15 | "@types/ffi": "^0.2.2", 16 | "@types/ref": "^0.0.28", 17 | "bindings": "^1.5.0", 18 | "ffi": "lxe/node-ffi#node-12", 19 | "ref": "lxe/ref#node-12", 20 | "vscode-languageserver": "^5.2.1" 21 | }, 22 | "scripts": {} 23 | } 24 | -------------------------------------------------------------------------------- /util/vscode/server/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es6", 4 | "module": "commonjs", 5 | "moduleResolution": "node", 6 | "sourceMap": true, 7 | "strict": true, 8 | "outDir": "out", 9 | "rootDir": "src" 10 | }, 11 | "include": ["src"], 12 | "exclude": ["node_modules", ".vscode-test"] 13 | } 14 | -------------------------------------------------------------------------------- /util/vscode/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "target": "es6", 5 | "outDir": "out", 6 | "rootDir": "src", 7 | "sourceMap": true 8 | }, 9 | "include": [ 10 | "src" 11 | ], 12 | "exclude": [ 13 | "node_modules", 14 | ".vscode-test" 15 | ], 16 | "references": [ 17 | { "path": "./client" }, 18 | { "path": "./server" } 19 | ] 20 | } -------------------------------------------------------------------------------- /util/vscode/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "rules": { 3 | "indent": [true, "tabs"], 4 | "semicolon": [true, "always"] 5 | } 6 | } --------------------------------------------------------------------------------