[RFC] Doc-check utility. (#12)
* 1. Implement doc-check utility. * 1. Move ONNF installation script to a standalone script file. * 1. Modify build script to install llvm-project next to ONNF. The build script used to install llvm-project inside ONNF, which didn't make sense. * 1. Check out code to ONNF directory. * 1. Pass path parameter correctly. * 1. Debugging buildbot. * 1. Remove debug code. * 1. Update installation instructions in README.md. 2. Enforce consistency with scripts used in testing using doc-check. * 1. Fix error with respect to syntax to build multiple CMake targets. * 1. Move doc-check to doc_check. 2. Remove directive_config in top-level driver. * 1. Build onnf and check-mlir-lit separately because only CMake 3.15+ supports building multiple targets in one cmake --build run. * 1. Use new env variables to locate LLVM-Project. * 1. Documentation nits. * 1. Prettify buildbot scripts. * 1. Fix build script error. * 1. Support exclude_dirs in DocCheck. 2. Add README for DocCheck. * 1. Mark python3 interpreter as required. 2. Use imported interpreter target. * 1. Automatically deduce doc file extension in DocCheckCtx. 2. Rename ctx.open -> ctx.open_doc since it should only be used to open doc file. 3. Always read line in parser, instead of reading lines in driver and then passing it to parser.py. * 1. Rename parser -> doc_parser due to name conflict with python built-in module. 2. Explose doc_check module directory first before importing; otherwise if the doc_check utility is invoked by other script, importing will not work correctly. * 1. Keep renaming parser -> doc_parser. 2. Explicitly define a default configuration parser that parses the configuration into a python dictionary. * 1. Add test for doc-check. 2. Exclude doc-check tests from project dock-check because base directory is different. * 1. Raise ValueError if directive configuration fails to parse. 2. Format code. * Shorten test case documentation. Show example of using same-as-file directive, check with DocCheck. * 1. Shorten test case documentation. 2. More documentation, check documentation with DocCheck. * 1. Add copyright notice. * 1. Make documentation clearer. 2. Prettify build-scripts. * 1. Provide more documentation. 2. Fix some non-compliance with pep8 recommendations. Co-authored-by: Gheorghe-Teodor Bercea <gt.bercea@gmail.com>
This commit is contained in:
parent
7607edefe9
commit
1ebcc2eb64
|
@ -5,11 +5,6 @@ jobs:
|
||||||
- image: circleci/python
|
- image: circleci/python
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- checkout
|
|
||||||
- run:
|
|
||||||
name: Pull Submodules
|
|
||||||
command: |
|
|
||||||
git submodule update --init --recursive
|
|
||||||
- run:
|
- run:
|
||||||
name: Installing GCC, CMake, Ninja, Protobuf
|
name: Installing GCC, CMake, Ninja, Protobuf
|
||||||
command: sudo apt-get update && sudo apt-get install -y gcc g++ cmake ninja-build protobuf-compiler
|
command: sudo apt-get update && sudo apt-get install -y gcc g++ cmake ninja-build protobuf-compiler
|
||||||
|
@ -23,19 +18,25 @@ jobs:
|
||||||
# mlir-opt executable exists.
|
# mlir-opt executable exists.
|
||||||
if [ ! -f llvm-project/build/bin/mlir-opt ]; then
|
if [ ! -f llvm-project/build/bin/mlir-opt ]; then
|
||||||
export MAKEFLAGS=-j4
|
export MAKEFLAGS=-j4
|
||||||
source .circleci/install-mlir.sh
|
source utils/install-mlir.sh
|
||||||
fi
|
fi
|
||||||
- save_cache:
|
- save_cache:
|
||||||
key: V2-LLVM-PROJECT-{{ arch }}
|
key: V2-LLVM-PROJECT-{{ arch }}
|
||||||
paths:
|
paths:
|
||||||
- llvm-project
|
- llvm-project
|
||||||
|
- checkout:
|
||||||
|
path: ONNF
|
||||||
|
- run:
|
||||||
|
name: Pull Submodules
|
||||||
|
command: |
|
||||||
|
cd ONNF
|
||||||
|
git submodule update --init --recursive
|
||||||
- run:
|
- run:
|
||||||
name: Install ONNF
|
name: Install ONNF
|
||||||
command: |
|
command: source ONNF/utils/install-onnf.sh
|
||||||
mkdir build && cd build
|
- run:
|
||||||
LLVM_PROJ_SRC=$(pwd)/../llvm-project/ LLVM_PROJ_BUILD=$(pwd)/../llvm-project/build cmake ..
|
name: Run DocCheck
|
||||||
make all
|
command: cd ONNF/build && cmake --build . --target check-doc
|
||||||
LIT_OPTS=-v make check-mlir-lit
|
|
||||||
- run:
|
- run:
|
||||||
name: Print the Current Time
|
name: Print the Current Time
|
||||||
command: date
|
command: date
|
||||||
|
|
|
@ -25,6 +25,6 @@ add_subdirectory(third_party/pybind11)
|
||||||
|
|
||||||
set(CMAKE_CXX_STANDARD 14)
|
set(CMAKE_CXX_STANDARD 14)
|
||||||
add_subdirectory(src)
|
add_subdirectory(src)
|
||||||
|
add_subdirectory(doc)
|
||||||
add_subdirectory(test)
|
add_subdirectory(test)
|
||||||
|
|
||||||
|
|
38
README.md
38
README.md
|
@ -5,19 +5,44 @@ Open Neural Network Frontend : an ONNX frontend for MLIR.
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
We assume an existing installation of MLIR. The LLVM-Project repo commit hash we used to test against is 9b6ad8466bb8b97082b705270603ad7f4559e931 and the MLIR repo commit hash we used is 0710266d0f56cf6ab0f437badbd7416b6cecdf5f.
|
Firstly, install MLIR (as a part of LLVM-Project):
|
||||||
|
|
||||||
|
[same-as-file]: <> (utils/install-mlir.sh)
|
||||||
|
``` bash
|
||||||
|
git clone https://github.com/llvm/llvm-project.git
|
||||||
|
mkdir llvm-project/build
|
||||||
|
cd llvm-project/build
|
||||||
|
cmake -G Ninja ../llvm \
|
||||||
|
-DLLVM_ENABLE_PROJECTS=mlir \
|
||||||
|
-DLLVM_BUILD_EXAMPLES=ON \
|
||||||
|
-DLLVM_TARGETS_TO_BUILD="host" \
|
||||||
|
-DCMAKE_BUILD_TYPE=Release \
|
||||||
|
-DLLVM_ENABLE_ASSERTIONS=ON \
|
||||||
|
-DLLVM_ENABLE_RTTI=ON
|
||||||
|
|
||||||
|
cmake --build . --target check-mlir -- ${MAKEFLAGS}
|
||||||
|
```
|
||||||
|
|
||||||
Two environment variables need to be set:
|
Two environment variables need to be set:
|
||||||
- LLVM_SRC should point to the llvm src directory (e.g., llvm-project/llvm).
|
- LLVM_PROJ_SRC should point to the llvm src directory (e.g., llvm-project/llvm).
|
||||||
- LLVM_BUILD should point to the llvm build directory (e.g., llvm-project/build).
|
- LLVM_PROJ_BUILD should point to the llvm build directory (e.g., llvm-project/build).
|
||||||
|
|
||||||
To build ONNF, use the following command:
|
To build ONNF, use the following command:
|
||||||
|
|
||||||
|
[same-as-file]: <> ({"ref": "utils/install-onnf.sh", "skip-doc": 2})
|
||||||
```
|
```
|
||||||
git clone --recursive git@github.com:clang-ykt/ONNF.git
|
git clone --recursive git@github.com:clang-ykt/ONNF.git
|
||||||
mkdir build
|
|
||||||
cd build
|
# Export environment variables pointing to LLVM-Projects.
|
||||||
|
export LLVM_PROJ_SRC=$(pwd)/llvm-project/
|
||||||
|
export LLVM_PROJ_BUILD=$(pwd)/llvm-project/build
|
||||||
|
|
||||||
|
mkdir ONNF/build && cd ONNF/build
|
||||||
cmake ..
|
cmake ..
|
||||||
cmake --build . --target all
|
cmake --build . --target onnf
|
||||||
|
|
||||||
|
# Run FileCheck tests:
|
||||||
|
cmake --build . --target check-mlir-lit
|
||||||
```
|
```
|
||||||
|
|
||||||
After the above commands succeed, an `onnf` executable should appear in the `bin` directory.
|
After the above commands succeed, an `onnf` executable should appear in the `bin` directory.
|
||||||
|
@ -63,4 +88,3 @@ module {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
add_subdirectory(doc_check)
|
|
@ -0,0 +1,9 @@
|
||||||
|
find_package(Python3 REQUIRED
|
||||||
|
COMPONENTS Interpreter)
|
||||||
|
|
||||||
|
add_custom_target(check-doc
|
||||||
|
COMMAND Python3::Interpreter
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/check.py
|
||||||
|
${CMAKE_SOURCE_DIR}
|
||||||
|
--exclude_dirs third_party doc/doc_check/test)
|
||||||
|
|
|
@ -0,0 +1,77 @@
|
||||||
|
# DocCheck
|
||||||
|
|
||||||
|
### Goal
|
||||||
|
|
||||||
|
DocCheck provides a set of utilities to enforce invariant properties of artifacts (e.g., code snippets or
|
||||||
|
output of execution) presented in the software documentation. They can be used to ensure that these
|
||||||
|
artifacts are always compatible and up-to-date with the state of software development.
|
||||||
|
|
||||||
|
### Directives
|
||||||
|
|
||||||
|
DocCheck provides a set of directives that can be used in documentations to enforce desired invariants.
|
||||||
|
A directive is a comment with a specific format/syntax to communicate the intent to check certain invariants to the
|
||||||
|
DocCheck checker. Generally, a directive has the following syntax in markdown:
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
[{directive}]: <> ({configuration})
|
||||||
|
```
|
||||||
|
|
||||||
|
Where {directive} specifies the type of invariance checking intended and {configuration} expresses the specific
|
||||||
|
parameters of this directive. In general, a directive configuration is expressed using a python dictionary literal,
|
||||||
|
but special shorthands exist for each directive individually.
|
||||||
|
|
||||||
|
##### `same-as-file`:
|
||||||
|
|
||||||
|
Use `same-as-file` directive to ensure that the code section following this directive is the same as a source file.
|
||||||
|
This is useful primarily because testing code snippet in documentation directly is often impossible. However,
|
||||||
|
unit tests can be written utilizing an exact copy of the code snippet content. We can use `same-as-file` directive
|
||||||
|
to ensure the code snippet is always the same as its copy used in some unit tests,
|
||||||
|
|
||||||
|
`same-as-file` directive supports a convenient short-hand configuration format where the directive configuration can be fully specified using the name of the reference file to check against.
|
||||||
|
For example, to ensure a code snippet is the same as a unit-tested file `reference.cpp`, use the following directive as shown in the documentation snippet:
|
||||||
|
|
||||||
|
[same-as-file]: <> (doc/doc_check/test/same-as-file/simple/README.md)
|
||||||
|
````markdown
|
||||||
|
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
||||||
|
|
||||||
|
[same-as-file]: <> (reference.cpp)
|
||||||
|
```cpp
|
||||||
|
#include<iostream>
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
cout<<"Hello World";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
````
|
||||||
|
|
||||||
|
In the canonical form of directive configuration (as a python dictionary literal), this directive supports these parameters in it:
|
||||||
|
|
||||||
|
`ref` (string): reference file to check against.
|
||||||
|
|
||||||
|
`skip-doc` (int): number of lines to skip when checking the documentation.
|
||||||
|
|
||||||
|
`skip-ref` (int): number of lines to skip when scanning the reference file.
|
||||||
|
|
||||||
|
For example, to ensure the following code snippet is the same as a unit-tested file `reference.cpp`, except for the first 2 lines of the code used in documentation, and the first 3 lines of code used in the reference file, the following directive configuration can be used:
|
||||||
|
|
||||||
|
[same-as-file]: <> (doc/doc_check/test/same-as-file/skip-doc-ref/README.md)
|
||||||
|
````markdown
|
||||||
|
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
||||||
|
|
||||||
|
[same-as-file]: <> ({"ref": "reference.cpp", "skip-doc": 2, "skip-ref": 3})
|
||||||
|
```cpp
|
||||||
|
// First line unique to documentation
|
||||||
|
// Second line unique to documentation
|
||||||
|
#include<iostream>
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
cout<<"Hello World";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
````
|
|
@ -0,0 +1,51 @@
|
||||||
|
# ===-------------------- check.py - Documentation Checker ----------------===//
|
||||||
|
#
|
||||||
|
# Copyright 2019-2020 The IBM Research Authors.
|
||||||
|
#
|
||||||
|
# =============================================================================
|
||||||
|
#
|
||||||
|
# ===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import os, sys
|
||||||
|
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
from utils import setup_logger, DocCheckerCtx
|
||||||
|
|
||||||
|
logger = setup_logger("doc-check")
|
||||||
|
|
||||||
|
# Make common utilities visible by adding them to system paths.
|
||||||
|
doc_check_base_dir = os.path.dirname(os.path.realpath(__file__))
|
||||||
|
sys.path.append(doc_check_base_dir)
|
||||||
|
|
||||||
|
from doc_parser import try_parse_and_handle_directive
|
||||||
|
|
||||||
|
parser = argparse.ArgumentParser()
|
||||||
|
parser.add_argument(
|
||||||
|
"root_dir",
|
||||||
|
help="directory in which to look for documentation to operate on")
|
||||||
|
|
||||||
|
parser.add_argument('--exclude_dirs', nargs='+',
|
||||||
|
help='a set of directories to exclude, with path specified relative to root_dir', default=[])
|
||||||
|
|
||||||
|
|
||||||
|
def main(root_dir, exclude_dirs):
|
||||||
|
for i, exclude_dir in enumerate(exclude_dirs):
|
||||||
|
exclude_dirs[i] = os.path.join(root_dir, exclude_dir)
|
||||||
|
|
||||||
|
ctx = DocCheckerCtx(root_dir)
|
||||||
|
for doc_file in Path(root_dir).rglob('*.md'):
|
||||||
|
# Skip, if doc file is in directories to be excluded.
|
||||||
|
if any([str(doc_file).startswith(exclude_dir) for exclude_dir in exclude_dirs]):
|
||||||
|
continue
|
||||||
|
|
||||||
|
logger.info("Checking {}...".format(doc_file))
|
||||||
|
with ctx.open_doc(doc_file) as markdown_file:
|
||||||
|
while not markdown_file.eof():
|
||||||
|
try_parse_and_handle_directive(ctx)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
args = parser.parse_args()
|
||||||
|
main(**vars(args))
|
|
@ -0,0 +1,81 @@
|
||||||
|
# ===----------------- directive.py - Directive Base Class ----------------===//
|
||||||
|
#
|
||||||
|
# Copyright 2019-2020 The IBM Research Authors.
|
||||||
|
#
|
||||||
|
# =============================================================================
|
||||||
|
#
|
||||||
|
# ===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
import re
|
||||||
|
import ast
|
||||||
|
from typing import List, Dict, Callable, Any, Pattern, Tuple
|
||||||
|
|
||||||
|
from doc_parser import failure, success, succeeded
|
||||||
|
from utils import DocCheckerCtx
|
||||||
|
|
||||||
|
DirectiveConfigList = List[Dict[str, Any]]
|
||||||
|
ConfigParseResult = Tuple[str, Dict[str, Any]]
|
||||||
|
|
||||||
|
|
||||||
|
class Directive(object):
|
||||||
|
""""""
|
||||||
|
def __init__(self, ext_to_regexes: Dict[str, str],
|
||||||
|
config_parsers: List[Callable[[str, DirectiveConfigList],
|
||||||
|
ConfigParseResult]],
|
||||||
|
handler: Callable[[Dict[str, Any], DocCheckerCtx], None]):
|
||||||
|
"""
|
||||||
|
:param ext_to_regexes: specify a regex expression to match the directive (for each file extension type).
|
||||||
|
:param config_parsers: specify a list of parsers to parse configuration. They will be invoked in order until one indicates parsing is successful.
|
||||||
|
:param handler: a function to perform the invariance check specified by the directive.
|
||||||
|
"""
|
||||||
|
self.ext_to_patterns: Dict[str, Pattern] = {}
|
||||||
|
for ext, pattern in ext_to_regexes.items():
|
||||||
|
self.ext_to_patterns[ext] = re.compile(pattern)
|
||||||
|
|
||||||
|
self.config_parsers: List[Callable[[str, DirectiveConfigList],
|
||||||
|
ConfigParseResult]] = config_parsers
|
||||||
|
self.handler = handler
|
||||||
|
|
||||||
|
def try_parse_directive(
|
||||||
|
self, ctx: DocCheckerCtx,
|
||||||
|
directive_config: DirectiveConfigList) -> Tuple[str, Any]:
|
||||||
|
"""
|
||||||
|
:param ctx: parser context.
|
||||||
|
:param directive_config: a list used to output parsed directive configuration.
|
||||||
|
:return: parse result.
|
||||||
|
"""
|
||||||
|
line = ctx.doc_file.next_non_empty_line()
|
||||||
|
matches = self.ext_to_patterns[ctx.doc_file_ext()].findall(line)
|
||||||
|
if len(matches) > 1:
|
||||||
|
raise ValueError("more than one directives in a line")
|
||||||
|
|
||||||
|
match = matches[0] if len(matches) else None
|
||||||
|
if match:
|
||||||
|
for parser in self.config_parsers:
|
||||||
|
if succeeded(parser(match, directive_config)):
|
||||||
|
return success()
|
||||||
|
|
||||||
|
raise ValueError("Failed to parse configuration.")
|
||||||
|
else:
|
||||||
|
return failure()
|
||||||
|
|
||||||
|
def handle(self, config, ctx):
|
||||||
|
self.handler(config, ctx)
|
||||||
|
|
||||||
|
|
||||||
|
def generic_config_parser(
|
||||||
|
match: str, directive_config: DirectiveConfigList) -> Tuple[str, Any]:
|
||||||
|
"""
|
||||||
|
Generic configuration parser.
|
||||||
|
Will return success if and only if configuration is specified as a python dictionary literal.
|
||||||
|
|
||||||
|
@param match: the content from which to parse the directive configuration.
|
||||||
|
@param directive_config: a list to output the parsed directive_config.
|
||||||
|
@return: parsing result.
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
directive_config.append(ast.literal_eval(match))
|
||||||
|
return success()
|
||||||
|
except (SyntaxError, ValueError):
|
||||||
|
# If literal_eval failed, return parsing failure.
|
||||||
|
return failure()
|
|
@ -0,0 +1,52 @@
|
||||||
|
# ===-------------------------- utils.py - Utility ------------------------===//
|
||||||
|
#
|
||||||
|
# Copyright 2019-2020 The IBM Research Authors.
|
||||||
|
#
|
||||||
|
# =============================================================================
|
||||||
|
#
|
||||||
|
# ===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
import logging
|
||||||
|
|
||||||
|
logger = logging.getLogger('doc-check')
|
||||||
|
|
||||||
|
from doc_parser import *
|
||||||
|
from utils import *
|
||||||
|
|
||||||
|
|
||||||
|
def parse(line, directive_configs):
|
||||||
|
directive_configs.append({'ref': line})
|
||||||
|
return success()
|
||||||
|
|
||||||
|
|
||||||
|
def handle(config, ctx):
|
||||||
|
logger.debug("Handling a same-as-file directive with config {}".format(config))
|
||||||
|
ref_file_path = config["ref"]
|
||||||
|
doc_file = ctx.doc_file
|
||||||
|
parse_code_section_delimiter(ctx)
|
||||||
|
with WrappedFile(open(
|
||||||
|
os.path.join(ctx.root_dir, ref_file_path))) as ref_file:
|
||||||
|
doc_file.skip_lines(config.get("skip-doc", 0))
|
||||||
|
ref_file.skip_lines(config.get("skip-ref", 0))
|
||||||
|
while not ref_file.eof():
|
||||||
|
ref_line = ref_file.readline().rstrip('\r\n')
|
||||||
|
doc_line = doc_file.readline().rstrip('\r\n')
|
||||||
|
loc = (doc_file.f.name, doc_file.line,
|
||||||
|
ref_file_path, ref_file.line)
|
||||||
|
loc_info = "\ndoc file {}, line no. {}. ref file {}, line no. {}.".format(*loc)
|
||||||
|
if doc_file.eof():
|
||||||
|
raise ValueError("Check failed because doc file is "
|
||||||
|
"shorter than reference file." + loc_info)
|
||||||
|
|
||||||
|
if ref_line != doc_line:
|
||||||
|
doc_line_info = "\nDoc line : {}".format(doc_line)
|
||||||
|
ref_line_info = "\nReference line: {}".format(ref_line)
|
||||||
|
raise ValueError(
|
||||||
|
"Check failed because doc file content is not "
|
||||||
|
"the same as that of reference file." +
|
||||||
|
doc_line_info + ref_line_info)
|
||||||
|
|
||||||
|
parse_code_section_delimiter(ctx)
|
||||||
|
|
||||||
|
|
||||||
|
ext_to_patterns = {'.md': '\\[same-as-file\\]: <> \\(([^)]*)\\)'}
|
|
@ -0,0 +1,35 @@
|
||||||
|
# ===------------ doc_parser.py - Documentation Parsing Utility ------------===//
|
||||||
|
#
|
||||||
|
# Copyright 2019-2020 The IBM Research Authors.
|
||||||
|
#
|
||||||
|
# =============================================================================
|
||||||
|
#
|
||||||
|
# ===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
from typing import List
|
||||||
|
from utils import *
|
||||||
|
|
||||||
|
from directive import Directive, generic_config_parser
|
||||||
|
|
||||||
|
|
||||||
|
def parse_code_section_delimiter(ctx):
|
||||||
|
assert ctx.doc_file_ext() == ".md"
|
||||||
|
if not ctx.doc_file.next_non_empty_line().strip().startswith("```"):
|
||||||
|
raise ValueError("Did not parse a code section delimiter")
|
||||||
|
|
||||||
|
|
||||||
|
def try_parse_and_handle_directive(ctx):
|
||||||
|
from directive_impl import same_as_file
|
||||||
|
|
||||||
|
# Register all directives.
|
||||||
|
all_directives: List[Directive] = [
|
||||||
|
Directive(same_as_file.ext_to_patterns, [generic_config_parser, same_as_file.parse], same_as_file.handle)
|
||||||
|
]
|
||||||
|
|
||||||
|
for directive in all_directives:
|
||||||
|
directive_config = []
|
||||||
|
if succeeded(directive.try_parse_directive(ctx, directive_config)):
|
||||||
|
directive.handle(directive_config.pop(), ctx)
|
||||||
|
return success(directive_config)
|
||||||
|
|
||||||
|
return failure()
|
|
@ -0,0 +1,11 @@
|
||||||
|
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
||||||
|
|
||||||
|
[same-as-file]: <> (reference.cpp)
|
||||||
|
```cpp
|
||||||
|
#include<iostream>
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
cout<<"Hello World";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
```
|
|
@ -0,0 +1,8 @@
|
||||||
|
#include<iostream>
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
cout<<"Hello World";
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
||||||
|
|
||||||
|
[same-as-file]: <> (reference.cpp)
|
||||||
|
```cpp
|
||||||
|
#include<iostream>
|
||||||
|
|
||||||
|
```
|
|
@ -0,0 +1,8 @@
|
||||||
|
#include<iostream>
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
cout<<"Hello World";
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,13 @@
|
||||||
|
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
||||||
|
|
||||||
|
[same-as-file]: <> (reference.cpp)
|
||||||
|
```cpp
|
||||||
|
#include<iostream>
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
cout<<"Hello World";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
```
|
|
@ -0,0 +1,8 @@
|
||||||
|
#include<iostream>
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
cout<<"Hello World";
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
||||||
|
|
||||||
|
[same-as-file]: <> ({"ref": "reference.cpp", "skip-doc": 2, "skip-ref": 3})
|
||||||
|
```cpp
|
||||||
|
// First line unique to documentation
|
||||||
|
// Second line unique to documentation
|
||||||
|
#include<iostream>
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
cout<<"Hello World";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
```
|
|
@ -0,0 +1,11 @@
|
||||||
|
// First line unique to reference
|
||||||
|
// Second line unique to reference
|
||||||
|
// Third line unique to reference
|
||||||
|
#include<iostream>
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
cout<<"Hello World";
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,44 @@
|
||||||
|
# ===------- test-same-as-file.py - Test for same-as-file directive -------===//
|
||||||
|
#
|
||||||
|
# Copyright 2019-2020 The IBM Research Authors.
|
||||||
|
#
|
||||||
|
# =============================================================================
|
||||||
|
#
|
||||||
|
# ===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
import unittest
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
|
# Make common utilities visible by adding them to system paths.
|
||||||
|
test_dir = os.path.dirname(os.path.realpath(__file__))
|
||||||
|
doc_check_base_dir = os.path.abspath(os.path.join(test_dir, os.pardir))
|
||||||
|
print(doc_check_base_dir)
|
||||||
|
sys.path.append(doc_check_base_dir)
|
||||||
|
|
||||||
|
import check
|
||||||
|
|
||||||
|
|
||||||
|
class TestStringMethods(unittest.TestCase):
|
||||||
|
def test_basic(self):
|
||||||
|
check.main('./same-as-file/simple/', [])
|
||||||
|
|
||||||
|
def test_different(self):
|
||||||
|
with self.assertRaises(ValueError) as context:
|
||||||
|
check.main("./same-as-file/error-doc-different-from-ref/", [])
|
||||||
|
self.assertTrue('Check failed because doc file content is not the same as that of reference file.' in str(
|
||||||
|
context.exception))
|
||||||
|
|
||||||
|
def test_doc_shorter_than_ref(self):
|
||||||
|
# check.main('./same-as-file/error-doc-shorter-than-ref/', [])
|
||||||
|
with self.assertRaises(ValueError) as context:
|
||||||
|
check.main('./same-as-file/error-doc-shorter-than-ref/', [])
|
||||||
|
self.assertTrue('Check failed because doc file is shorter than reference file.' in str(
|
||||||
|
context.exception))
|
||||||
|
|
||||||
|
def test_skip_doc_ref(self):
|
||||||
|
check.main('./same-as-file/skip-doc-ref/', [])
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
|
@ -0,0 +1,91 @@
|
||||||
|
# ===-------------------------- utils.py - Utility ------------------------===//
|
||||||
|
#
|
||||||
|
# Copyright 2019-2020 The IBM Research Authors.
|
||||||
|
#
|
||||||
|
# =============================================================================
|
||||||
|
#
|
||||||
|
# ===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
import logging
|
||||||
|
import os
|
||||||
|
|
||||||
|
|
||||||
|
# Based on https://stackoverflow.com/a/6367075.
|
||||||
|
class WrappedFile(object):
|
||||||
|
"""
|
||||||
|
Complements the standard python file object in two ways:
|
||||||
|
- Implements a line number based EOF checker.
|
||||||
|
- Allows retriving the current line position of the cursor, which is
|
||||||
|
good for error localization.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, f):
|
||||||
|
self.f = f
|
||||||
|
self.line = 0
|
||||||
|
|
||||||
|
# Compute the total number of lines.
|
||||||
|
self.num_lines = len(f.readlines())
|
||||||
|
f.seek(0)
|
||||||
|
|
||||||
|
def close(self):
|
||||||
|
return self.f.close()
|
||||||
|
|
||||||
|
def readline(self):
|
||||||
|
self.line += 1
|
||||||
|
return self.f.readline()
|
||||||
|
|
||||||
|
def next_non_empty_line(self):
|
||||||
|
while not self.eof():
|
||||||
|
line = self.readline()
|
||||||
|
if len(line.strip()):
|
||||||
|
return line
|
||||||
|
raise RuntimeError("Enf of file.")
|
||||||
|
|
||||||
|
def skip_lines(self, num_lines):
|
||||||
|
for i in range(num_lines):
|
||||||
|
self.readline()
|
||||||
|
|
||||||
|
def eof(self):
|
||||||
|
return self.line >= self.num_lines
|
||||||
|
|
||||||
|
# to allow using in 'with' statements
|
||||||
|
def __enter__(self):
|
||||||
|
return self
|
||||||
|
|
||||||
|
def __exit__(self, exc_type, exc_val, exc_tb):
|
||||||
|
self.close()
|
||||||
|
|
||||||
|
|
||||||
|
class DocCheckerCtx(object):
|
||||||
|
def __init__(self, root_dir: str):
|
||||||
|
self.root_dir = root_dir
|
||||||
|
self.doc_file = None
|
||||||
|
|
||||||
|
def open_doc(self, file_name):
|
||||||
|
self.doc_file = WrappedFile(open(file_name, 'r'))
|
||||||
|
return self.doc_file
|
||||||
|
|
||||||
|
def doc_file_ext(self):
|
||||||
|
assert self.doc_file is not None, "hasn't opened any doc file"
|
||||||
|
_, file_extension = os.path.splitext(self.doc_file.f.name)
|
||||||
|
return file_extension
|
||||||
|
|
||||||
|
|
||||||
|
def success(states=None):
|
||||||
|
return "ok", states
|
||||||
|
|
||||||
|
|
||||||
|
def failure(states=None):
|
||||||
|
return "failed", states
|
||||||
|
|
||||||
|
|
||||||
|
def succeeded(states):
|
||||||
|
return states[0] == "ok"
|
||||||
|
|
||||||
|
|
||||||
|
def setup_logger(name):
|
||||||
|
handler = logging.StreamHandler()
|
||||||
|
logger = logging.getLogger(name)
|
||||||
|
logger.setLevel(logging.DEBUG)
|
||||||
|
logger.addHandler(handler)
|
||||||
|
return logger
|
|
@ -0,0 +1,10 @@
|
||||||
|
# Export environment variables pointing to LLVM-Projects.
|
||||||
|
export LLVM_PROJ_SRC=$(pwd)/llvm-project/
|
||||||
|
export LLVM_PROJ_BUILD=$(pwd)/llvm-project/build
|
||||||
|
|
||||||
|
mkdir ONNF/build && cd ONNF/build
|
||||||
|
cmake ..
|
||||||
|
cmake --build . --target onnf
|
||||||
|
|
||||||
|
# Run FileCheck tests:
|
||||||
|
cmake --build . --target check-mlir-lit
|
Loading…
Reference in New Issue