diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c5a67e5..9658366 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -95,3 +95,37 @@ jobs: args: --workspace --no-fail-fast env: RUST_BACKTRACE: full + + expander_test: + strategy: + fail-fast: false + matrix: + toolchain: + - 1.42.0-x86_64-unknown-linux-gnu + - stable-x86_64-unknown-linux-gnu + python-version: + - '3.6' # https://packages.ubuntu.com/bionic/python3 + - '3.8' # https://packages.ubuntu.com/focal/python3 + + name: Expand_test (${{ matrix.toolchain }}, ${{ matrix.python-version }}) + runs-on: ubuntu-18.04 + + steps: + - name: Checkout + uses: actions/checkout@v2 + + - name: 'Setup `${{ matrix.toolchain }}`' + uses: actions-rs/toolchain@v1 + with: + toolchain: ${{ matrix.toolchain }} + override: true + profile: minimal + components: rustfmt + + - name: Setup Python ${{ matrix.python-version }} + uses: actions/setup-python@v2 + with: + python-version: ${{ matrix.python-version }} + + - name: expand.py tests + run: bash ./.github/workflows/test-expand.sh diff --git a/.github/workflows/test-expand.sh b/.github/workflows/test-expand.sh new file mode 100755 index 0000000..2d5b4c5 --- /dev/null +++ b/.github/workflows/test-expand.sh @@ -0,0 +1,22 @@ +#!/bin/bash + +TEST_MODULES=(convolution dsu fenwicktree lazysegtree math maxflow mincostflow modint scc segtree string twosat --all) +TMP_PATH=$(mktemp -d) +# shellcheck disable=SC2164 +SCRIPT_DIR="$(cd "$(dirname "$0")"; pwd)" +TEST_FILE="test.rs" +FILE_HEAD="fn main() {}" + +for MODULE in "${TEST_MODULES[@]}" ;do + echo Test module "$MODULE" + python3 "$SCRIPT_DIR/../../expand.py" "$MODULE" > "$TMP_PATH/$TEST_FILE" + echo Output "$(wc -c < "$TMP_PATH/$TEST_FILE")" Bytes + echo "$FILE_HEAD" >> "$TMP_PATH/$TEST_FILE" + if ! rustc -A warnings "$TMP_PATH/$TEST_FILE"; + then + echo Error compiling for "$MODULE" + exit 1 + else + echo Test passed + fi +done diff --git a/expand.py b/expand.py new file mode 100755 index 0000000..4072ced --- /dev/null +++ b/expand.py @@ -0,0 +1,118 @@ +#!/usr/bin/python3 + +import sys +import getopt +import tempfile +import subprocess + +usage = '''Usage:expand.py [options] +Output Modules: + convolution + dsu + fenwicktree + lazysegtree + math + maxflow + mincostflow + modint + scc + segtree + string + twosat + +You can select multiple modules for + e.g.)expand.py math segtree + +Options: + -a --all import all modules + -h --help print help +''' +output_header = '//https://github.com/rust-lang-ja/ac-library-rs\n' +opt_list = ['help', 'all'] +output_list_all = ('convolution', 'dsu', 'fenwicktree', 'lazysegtree', 'math', + 'maxflow', 'mincostflow', 'modint', 'scc', 'segtree', + 'string', 'twosat', + 'internal_bit', 'internal_math', 'internal_queue', + 'internal_scc', 'internal_type_traits',) +dependency_list = {'convolution': ('internal_bit', 'modint',), + 'lazysegtree': ('internal_bit', 'segtree'), + 'math': ('internal_math',), + 'maxflow': ('internal_type_traits', 'internal_queue',), + 'mincostflow': ('internal_type_traits',), + 'modint': ('internal_math',), + 'scc': ('internal_scc',), + 'segtree': ('internal_bit', 'internal_type_traits',), + 'twosat': ('internal_scc',), } +src_path = 'src/' + + +def output_file(filename): + global src_path + + res = [] + with open(src_path+filename+'.rs', 'r') as f: + res.append('pub mod {} {{'.format(filename)) + + for line in f: + res.append(line.rstrip()) + + res.append('}') + return res + + +try: + opts, args = getopt.getopt(sys.argv[1:], 'ah', opt_list) +except getopt.GetoptError as e: + print(e) + print(usage) + sys.exit(2) + +if len(opts) == 0 and len(args) == 0: + print(usage) + sys.exit(0) + +for o, v in opts: + if o == '--help' or o == '-h': + print(usage) + sys.exit(0) + elif o == '--all' or o == '-a': + args = list(output_list_all) + +output_list = set() + +while len(args) != 0: + pop = args.pop() + if pop not in output_list_all: + print('invalid args:{}'.format(pop)) + print(usage) + sys.exit(2) + output_list.add(pop) + if pop in dependency_list: + for d in dependency_list[pop]: + args.append(d) + +output_list = list(output_list) +output_list.sort() + +output_data = [] +for i in output_list: + buf = output_file(i) + output_data.extend(buf) + +for i in output_list: + # Modules that begin with 'internal' are for internal use, so they are not + # declared. + if not i.startswith('internal'): + output_data.append('use {}::*;'.format(i)) + +# rustfmt +with tempfile.TemporaryDirectory() as temp_dir: + temp_file = temp_dir + '/output.rs' + with open(temp_file, 'w') as f: + print(output_header, file=f) + for i in output_data: + print(i, file=f) + output_data = subprocess.run(["rustfmt", temp_file], check=True) + with open(temp_file, 'r') as f: + for line in f: + print(line, end="")