From 4b5a41b8c892ce35f91c16e5ba1326b0c2a3596f Mon Sep 17 00:00:00 2001 From: rturrado Date: Mon, 11 Sep 2023 16:20:02 +0200 Subject: [PATCH 01/28] Trying to test toy-v1 with a v3x/ParseHelper (ANTLR) while reusing the v1x/analyzer, v1x/program, and v1x/ParseResult. - Changed v1x/analyzer API so that it can also be passed a v3x/ParseHelper. - v3x/cqasm free functions use a v1x/analyzer and return a v1x/program, but do the parsing with a v3x/ParseHelper. - v3x/ParseHelper returns a v1x/ParseResult. --- include/v1x/cqasm-analyzer.hpp | 17 ------ include/v1x/cqasm-parse-helper.hpp | 31 ++-------- include/v1x/cqasm-parse-result.hpp | 45 +++++++++++++++ include/v1x/cqasm.hpp | 4 +- include/v3x/cqasm-parse-helper.hpp | 22 +++---- include/v3x/cqasm.hpp | 24 +++++--- src/cqasm-py.cpp | 12 +++- src/v1x/cqasm-analyzer.cpp | 32 ----------- src/v1x/cqasm.cpp | 33 +++++++---- src/v3x/cqasm-parse-helper.cpp | 7 ++- src/v3x/cqasm.cpp | 92 +++++++++++++++++++++++------- test/v1x/parsing.cpp | 3 +- 12 files changed, 189 insertions(+), 133 deletions(-) create mode 100644 include/v1x/cqasm-parse-result.hpp diff --git a/include/v1x/cqasm-analyzer.hpp b/include/v1x/cqasm-analyzer.hpp index 60663e33..1ad7b389 100644 --- a/include/v1x/cqasm-analyzer.hpp +++ b/include/v1x/cqasm-analyzer.hpp @@ -316,23 +316,6 @@ class Analyzer { const std::function &file_parser ) const; - /** - * Parses and analyzes the given file. - */ - AnalysisResult analyze(const std::string &filename) const; - - /** - * Parses and analyzes the given file pointer. The optional filename - * argument will be used only for error messages. - */ - AnalysisResult analyze(FILE *file, const std::string &filename = "") const; - - /** - * Parses and analyzes the given string. The optional filename argument - * will be used only for error messages. - */ - AnalysisResult analyze_string(const std::string &data, const std::string &filename = "") const; - }; } // namespace analyzer diff --git a/include/v1x/cqasm-parse-helper.hpp b/include/v1x/cqasm-parse-helper.hpp index 20e9c5e9..773f7fb2 100644 --- a/include/v1x/cqasm-parse-helper.hpp +++ b/include/v1x/cqasm-parse-helper.hpp @@ -1,16 +1,18 @@ /** \file - * Contains helper classes and objects for the lexer and parser generated by - * flex/bison, as well as the entry points for invoking the parser directly, in - * case you don't need semantic analysis. + * Contains helper classes and objects for the lexer and parser generated by flex/bison, + * as well as the entry points for invoking the parser directly, + * in case you don't need semantic analysis. */ #pragma once -#include "../cqasm-annotations.hpp" +#include "cqasm-annotations.hpp" #include "cqasm-ast.hpp" +#include "cqasm-parse-result.hpp" #include + namespace cqasm { namespace v1x { @@ -23,27 +25,6 @@ namespace parser { // Make sure it exists here for compatibility. using SourceLocation = annotations::SourceLocation; -/** - * Parse result information. - */ -class ParseResult { -public: - - /** - * Root node of the AST, if analysis was sufficiently successful. This may - * be set even if parsing was not ENTIRELY successful, in which case it - * will contain one or more error nodes. - */ - ast::One root; - - /** - * List of accumulated errors. Analysis was successful if and only if - * `errors.empty()`. - */ - std::vector errors; - -}; - /** * Parse the given file. */ diff --git a/include/v1x/cqasm-parse-result.hpp b/include/v1x/cqasm-parse-result.hpp new file mode 100644 index 00000000..faf6092c --- /dev/null +++ b/include/v1x/cqasm-parse-result.hpp @@ -0,0 +1,45 @@ +/** \file + * Contains helper classes and objects for the lexer and parser generated by + * flex/bison, as well as the entry points for invoking the parser directly, in + * case you don't need semantic analysis. + */ + +#pragma once + +#include "cqasm-annotations.hpp" +#include "cqasm-ast.hpp" + +#include + +namespace cqasm { +namespace v1x { + +/** + * Namespace for the parser functions and classes. + */ +namespace parser { + +/** + * Parse result information. + */ +class ParseResult { +public: + + /** + * Root node of the AST, if analysis was sufficiently successful. This may + * be set even if parsing was not ENTIRELY successful, in which case it + * will contain one or more error nodes. + */ + ast::One root; + + /** + * List of accumulated errors. Analysis was successful if and only if + * `errors.empty()`. + */ + std::vector errors; + +}; + +} // namespace parser +} // namespace v1x +} // namespace cqasm diff --git a/include/v1x/cqasm.hpp b/include/v1x/cqasm.hpp index b3f90f82..4f12819e 100644 --- a/include/v1x/cqasm.hpp +++ b/include/v1x/cqasm.hpp @@ -5,8 +5,10 @@ #pragma once -#include "cqasm-parse-helper.hpp" +#include "cqasm-tree.hpp" #include "cqasm-analyzer.hpp" +#include "cqasm-semantic.hpp" + /** * Toplevel namespace with entry points for the new API. diff --git a/include/v3x/cqasm-parse-helper.hpp b/include/v3x/cqasm-parse-helper.hpp index 5bd8f0b6..99ad0076 100644 --- a/include/v3x/cqasm-parse-helper.hpp +++ b/include/v3x/cqasm-parse-helper.hpp @@ -6,7 +6,8 @@ #pragma once -#include "../cqasm-annotations.hpp" +#include "cqasm-annotations.hpp" +#include "v1x/cqasm-parse-result.hpp" #include @@ -23,26 +24,21 @@ namespace parser { // Make sure it exists here for compatibility. using SourceLocation = annotations::SourceLocation; -/** - * Parse result information. - */ -class ParseResult{}; - /** * Parse the given file. */ -ParseResult parse_file(const std::string &filename); +cqasm::v1x::parser::ParseResult parse_file(const std::string &filename); /** * Parse using the given file pointer. */ -ParseResult parse_file(FILE *file, const std::string &filename = ""); +cqasm::v1x::parser::ParseResult parse_file(FILE *file, const std::string &filename = ""); /** * Parse the given string. A filename may be given in addition for use within * error messages. */ -ParseResult parse_string(const std::string &data, const std::string &filename=""); +cqasm::v1x::parser::ParseResult parse_string(const std::string &data, const std::string &filename=""); /** * Internal helper class for parsing cQASM files. @@ -73,12 +69,12 @@ class ParseHelper { /** * The parse result. */ - ParseResult result; + cqasm::v1x::parser::ParseResult result; private: - friend ParseResult parse_file(const std::string &filename); - friend ParseResult parse_file(FILE *file, const std::string &filename); - friend ParseResult parse_string(const std::string &data, const std::string &filename); + friend cqasm::v1x::parser::ParseResult parse_file(const std::string &filename); + friend cqasm::v1x::parser::ParseResult parse_file(FILE *file, const std::string &filename); + friend cqasm::v1x::parser::ParseResult parse_string(const std::string &data, const std::string &filename); /** * Parse a string or file with flex/bison. If use_file is set, the file diff --git a/include/v3x/cqasm.hpp b/include/v3x/cqasm.hpp index 502ba9de..71586aa0 100644 --- a/include/v3x/cqasm.hpp +++ b/include/v3x/cqasm.hpp @@ -5,7 +5,9 @@ #pragma once -#include "cqasm-parse-helper.hpp" +#include "cqasm-tree.hpp" +#include "v1x/cqasm-analyzer.hpp" +#include "v1x/cqasm-semantic.hpp" /** @@ -23,9 +25,9 @@ namespace v3x { * Parses and analyzes the given file with the default analyzer, dumping error * messages to stderr and throwing an analyzer::AnalysisFailed on failure. */ -void analyze( +tree::One analyze( const std::string &filename, - const std::string &api_version = "3.0" + const std::string &api_version = "1.0" ); /** @@ -33,10 +35,10 @@ void analyze( * error messages to stderr and throwing an analyzer::AnalysisFailed on failure. * The optional filename is only used for error messages. */ -void analyze( +tree::One analyze( FILE *file, const std::string &filename = "", - const std::string &api_version = "3.0" + const std::string &api_version = "1.0" ); /** @@ -44,10 +46,18 @@ void analyze( * error messages to stderr and throwing an analyzer::AnalysisFailed on failure. * The optional filename is only used for error messages. */ -void analyze_string( +tree::One analyze_string( const std::string &data, const std::string &filename = "", - const std::string &api_version = "3.0" + const std::string &api_version = "1.0" +); + +/** + * Constructs an Analyzer object with the defaults for cQASM 1.0 already loaded + * into it. + */ +cqasm::v1x::analyzer::Analyzer default_analyzer( + const std::string &api_version = "1.0" ); } // namespace v3x diff --git a/src/cqasm-py.cpp b/src/cqasm-py.cpp index 4c5769e7..208d8c90 100644 --- a/src/cqasm-py.cpp +++ b/src/cqasm-py.cpp @@ -2,8 +2,10 @@ * Implementation for the internal Python-wrapped functions and classes. */ +#include "cqasm-version.hpp" #include "cqasm-py.hpp" #include "v1x/cqasm.hpp" +#include "v1x/cqasm-parse-helper.hpp" namespace v1x = cqasm::v1x; @@ -108,7 +110,10 @@ std::vector V1xAnalyzer::parse_string( std::vector V1xAnalyzer::analyze_file( const std::string &filename ) const { - auto result = a->analyze(filename); + auto result = a->analyze( + [=](){ return cqasm::version::parse_file(filename); }, + [=](){ return v1x::parser::parse_file(filename); } + ); std::vector retval{""}; if (result.errors.empty()) { retval[0] = ::tree::base::serialize(result.root); @@ -125,7 +130,10 @@ std::vector V1xAnalyzer::analyze_string( const std::string &data, const std::string &filename ) const { - auto result = a->analyze_string(data, filename); + auto result = a->analyze( + [=](){ return cqasm::version::parse_string(data, filename); }, + [=](){ return v1x::parser::parse_string(data, filename); } + ); std::vector retval{""}; if (result.errors.empty()) { retval[0] = ::tree::base::serialize(result.root); diff --git a/src/v1x/cqasm-analyzer.cpp b/src/v1x/cqasm-analyzer.cpp index 35a7a11f..4a5e7006 100644 --- a/src/v1x/cqasm-analyzer.cpp +++ b/src/v1x/cqasm-analyzer.cpp @@ -535,38 +535,6 @@ AnalysisResult Analyzer::analyze( return analyze(file_parser()); } -/** - * Parses and analyzes the given file. - */ -AnalysisResult Analyzer::analyze(const std::string &filename) const { - return analyze( - [=](){ return version::parse_file(filename); }, - [=](){ return parser::parse_file(filename); } - ); -} - -/** - * Parses and analyzes the given file pointer. The optional filename - * argument will be used only for error messages. - */ -AnalysisResult Analyzer::analyze(FILE *file, const std::string &filename) const { - return analyze( - [=](){ return version::parse_file(file, filename); }, - [=](){ return parser::parse_file(file, filename); } - ); -} - -/** - * Parses and analyzes the given string. The optional filename argument - * will be used only for error messages. - */ -AnalysisResult Analyzer::analyze_string(const std::string &data, const std::string &filename) const { - return analyze( - [=](){ return version::parse_string(data, filename); }, - [=](){ return parser::parse_string(data, filename); } - ); -} - /** * Analyzes the given AST using the given analyzer. */ diff --git a/src/v1x/cqasm.cpp b/src/v1x/cqasm.cpp index ab179be7..1ff752b0 100644 --- a/src/v1x/cqasm.cpp +++ b/src/v1x/cqasm.cpp @@ -6,25 +6,31 @@ * Implementation for \ref include/v1x/cqasm.hpp "v1x/cqasm.hpp". */ +#include "cqasm-version.hpp" #include "v1x/cqasm.hpp" +#include "v1x/cqasm-parse-helper.hpp" +#include "v1x/cqasm-parse-result.hpp" namespace cqasm { namespace v1x { /** - * Parses and analyzes the given file with the default analyzer, dumping error - * messages to stderr and throwing an analyzer::AnalysisFailed on failure. + * Parses and analyzes the given file with the default analyzer, + * dumping error messages to stderr and throwing an analyzer::AnalysisFailed on failure. */ tree::One analyze( const std::string &filename, const std::string &api_version ) { - return default_analyzer(api_version).analyze(filename).unwrap(); + return default_analyzer(api_version).analyze( + [=](){ return version::parse_file(filename); }, + [=](){ return parser::parse_file(filename); } + ).unwrap(); } /** - * Parses and analyzes the given file pointer with the default analyzer, dumping - * error messages to stderr and throwing an analyzer::AnalysisFailed on failure. + * Parses and analyzes the given file pointer with the default analyzer, + * dumping error messages to stderr and throwing an analyzer::AnalysisFailed on failure. * The optional filename is only used for error messages. */ tree::One analyze( @@ -32,12 +38,15 @@ tree::One analyze( const std::string &filename, const std::string &api_version ) { - return default_analyzer(api_version).analyze(file, filename).unwrap(); + return default_analyzer(api_version).analyze( + [=](){ return version::parse_file(file, filename); }, + [=](){ return parser::parse_file(file, filename); } + ).unwrap(); } /** - * Parses and analyzes the given string with the default analyzer, dumping - * error messages to stderr and throwing an analyzer::AnalysisFailed on failure. + * Parses and analyzes the given string with the default analyzer, + * dumping error messages to stderr and throwing an analyzer::AnalysisFailed on failure. * The optional filename is only used for error messages. */ tree::One analyze_string( @@ -45,12 +54,14 @@ tree::One analyze_string( const std::string &filename, const std::string &api_version ) { - return default_analyzer(api_version).analyze_string(data, filename).unwrap(); + return default_analyzer(api_version).analyze( + [=](){ return version::parse_string(data, filename); }, + [=](){ return parser::parse_string(data, filename); } + ).unwrap(); } /** - * Constructs an Analyzer object with the defaults for cQASM 1.0 already loaded - * into it. + * Constructs an Analyzer object with the defaults for cQASM 1.0 already loaded into it. */ analyzer::Analyzer default_analyzer(const std::string &api_version) { analyzer::Analyzer analyzer{api_version}; diff --git a/src/v3x/cqasm-parse-helper.cpp b/src/v3x/cqasm-parse-helper.cpp index 12633764..e1b89375 100644 --- a/src/v3x/cqasm-parse-helper.cpp +++ b/src/v3x/cqasm-parse-helper.cpp @@ -2,6 +2,7 @@ * Implementation for \ref include/v3x/cqasm-parse-helper.hpp "v3x/cqasm-parse-helper.hpp". */ +#include "v1x/cqasm-parse-result.hpp" #include "v3x/cqasm-parse-helper.hpp" #include // runtime_error @@ -14,14 +15,14 @@ namespace parser { /** * Parse the given file. */ -ParseResult parse_file(const std::string & /* filename */) { +cqasm::v1x::parser::ParseResult parse_file(const std::string & /* filename */) { throw std::runtime_error("Unimplemented"); } /** * Parse using the given file pointer. */ -ParseResult parse_file(FILE * /* file */, const std::string & /* filename */) { +cqasm::v1x::parser::ParseResult parse_file(FILE * /* file */, const std::string & /* filename */) { throw std::runtime_error("Unimplemented"); } @@ -29,7 +30,7 @@ ParseResult parse_file(FILE * /* file */, const std::string & /* filename */) { * Parse the given string. A filename may be given in addition for use within * error messages. */ -ParseResult parse_string(const std::string & /* data */, const std::string & /* filename */) { +cqasm::v1x::parser::ParseResult parse_string(const std::string & /* data */, const std::string & /* filename */) { throw std::runtime_error("Unimplemented"); } diff --git a/src/v3x/cqasm.cpp b/src/v3x/cqasm.cpp index 340d063f..7840dc5c 100644 --- a/src/v3x/cqasm.cpp +++ b/src/v3x/cqasm.cpp @@ -6,7 +6,10 @@ * Implementation for \ref include/v3x/cqasm.hpp "v3x/cqasm.hpp". */ +#include "cqasm-version.hpp" +#include "v1x/cqasm-parse-result.hpp" #include "v3x/cqasm.hpp" +#include "v3x/cqasm-parse-helper.hpp" #include // runtime_error @@ -15,40 +18,89 @@ namespace cqasm { namespace v3x { /** - * Parses and analyzes the given file with the default analyzer, dumping error - * messages to stderr and throwing an analyzer::AnalysisFailed on failure. + * Parses and analyzes the given file with the default analyzer, + * dumping error messages to stderr and throwing an analyzer::AnalysisFailed on failure. */ -void analyze( - const std::string & /* filename */, - const std::string & /* api_version */ +tree::One analyze( + const std::string &filename, + const std::string &api_version ) { - throw std::runtime_error("Unimplemented"); + return default_analyzer(api_version).analyze( + [=](){ return version::parse_file(filename); }, + [=](){ return parser::parse_file(filename); } + ).unwrap(); } /** - * Parses and analyzes the given file pointer with the default analyzer, dumping - * error messages to stderr and throwing an analyzer::AnalysisFailed on failure. + * Parses and analyzes the given file pointer with the default analyzer, + * dumping error messages to stderr and throwing an analyzer::AnalysisFailed on failure. * The optional filename is only used for error messages. */ -void analyze( - FILE * /* file */, - const std::string & /* filename */, - const std::string & /* api_version */ +tree::One analyze( + FILE *file, + const std::string &filename, + const std::string &api_version ) { - throw std::runtime_error("Unimplemented"); + return default_analyzer(api_version).analyze( + [=](){ return version::parse_file(file, filename); }, + [=](){ return parser::parse_file(file, filename); } + ).unwrap(); } /** - * Parses and analyzes the given string with the default analyzer, dumping - * error messages to stderr and throwing an analyzer::AnalysisFailed on failure. + * Parses and analyzes the given string with the default analyzer, + * dumping error messages to stderr and throwing an analyzer::AnalysisFailed on failure. * The optional filename is only used for error messages. */ -void analyze_string( - const std::string & /* data */, - const std::string & /* filename */, - const std::string & /* api_version */ +tree::One analyze_string( + const std::string &data, + const std::string &filename, + const std::string &api_version ) { - throw std::runtime_error("Unimplemented"); + return default_analyzer(api_version).analyze( + [=](){ return version::parse_string(data, filename); }, + [=](){ return parser::parse_string(data, filename); } + ).unwrap(); +} + +/** + * Constructs an Analyzer object with the defaults for cQASM 1.0 already loaded into it. + */ +cqasm::v1x::analyzer::Analyzer default_analyzer(const std::string &api_version) { + cqasm::v1x::analyzer::Analyzer analyzer{api_version}; + + // Register the default mappings (true, false, pi, x, y, z, etc.) and + // functions (operators, things like trigonometric functions, etc.). + analyzer.register_default_functions_and_mappings(); + + // Register the error models. + // Originally, depolarizing_channel accepted any number of floating point arguments, + // but the new parser doesn't support that, + // so we just brute-force the first 50 into it and call it a day. + std::ostringstream args; + for (int i = 0; i <= 50; i++) { + analyzer.register_error_model("depolarizing_channel", args.str()); + args << "r"; + } + + // Register a toy version of the cQASM 1.0 instruction set. + analyzer.register_instruction("measure_all", "", false, false); + analyzer.register_instruction("x", "Q"); + analyzer.register_instruction("y", "Q"); + analyzer.register_instruction("z", "Q"); + analyzer.register_instruction("i", "Q"); + analyzer.register_instruction("h", "Q"); + analyzer.register_instruction("prep", "Q", false); + analyzer.register_instruction("prep_x", "Q", false); + analyzer.register_instruction("prep_y", "Q", false); + analyzer.register_instruction("prep_z", "Q", false); + analyzer.register_instruction("measure", "Q", false); + analyzer.register_instruction("measure_x", "Q", false); + analyzer.register_instruction("measure_y", "Q", false); + analyzer.register_instruction("measure_z", "Q", false); + analyzer.register_instruction("cnot", "QQ"); + + return analyzer; } } // namespace v3x diff --git a/test/v1x/parsing.cpp b/test/v1x/parsing.cpp index 7bb8e4eb..771594b8 100644 --- a/test/v1x/parsing.cpp +++ b/test/v1x/parsing.cpp @@ -141,8 +141,7 @@ class ParsingTest : public ::testing::Test { analyzer.register_instruction("reset-averaging", "Q", false, false); analyzer.register_instruction("load_state", "s", false, false); - // Add a dynamic function in order to test the behavior of dynamic - // function nodes. + // Add a dynamic function in order to test the behavior of dynamic function nodes. if (api_version != "1.0") { analyzer.register_function("or", "bb", [](const cq1x::values::Values &v) -> cq1x::values::Value { auto lhs = v[0]; From 3b65d4e83e43ed8ff043f7d81a9325ec233fd5fb Mon Sep 17 00:00:00 2001 From: rturrado Date: Tue, 12 Sep 2023 16:06:55 +0200 Subject: [PATCH 02/28] Refactored v3x/ParseHelper and implemented it using a ScannerAntlr. The ScannerAntlr::parse_ code merely invokes the lexer and the parser at the moment. --- conanfile.py | 1 + include/cqasm-version.hpp | 36 ++++----- include/v1x/cqasm-parse-helper.hpp | 35 +++++---- include/v1x/cqasm.hpp | 14 ++-- include/v3x/cqasm-parse-helper.hpp | 119 +++++++++++++---------------- include/v3x/cqasm.hpp | 32 +++----- src/CMakeLists.txt | 8 +- src/cqasm-version.cpp | 43 ++++++----- src/v1x/cqasm-parse-helper.cpp | 48 ++++++------ src/v1x/cqasm-parser.y | 4 +- src/v1x/cqasm.cpp | 26 +++---- src/v3x/cqasm-parse-helper.cpp | 105 ++++++++++++++----------- src/v3x/cqasm.cpp | 32 ++------ 13 files changed, 236 insertions(+), 267 deletions(-) diff --git a/conanfile.py b/conanfile.py index d28b4bfe..9a71371f 100644 --- a/conanfile.py +++ b/conanfile.py @@ -50,6 +50,7 @@ class LibqasmConan(ConanFile): exports_sources = "CMakeLists.txt", "include/*", "python/*", "res/*", "scripts/*", "src/*", "test/*" def build_requirements(self): + self.requires("fmt/10.1.1") self.tool_requires("m4/1.4.19") if self.settings.os == "Windows": self.tool_requires("winflexbison/2.5.24") diff --git a/include/cqasm-version.hpp b/include/cqasm-version.hpp index e7fd462f..02b8bd37 100644 --- a/include/cqasm-version.hpp +++ b/include/cqasm-version.hpp @@ -6,10 +6,10 @@ #include "cqasm-error.hpp" +#include // FILE* +#include // unique_ptr +#include #include -#include -#include -#include #include /** @@ -62,18 +62,18 @@ std::ostream &operator<<(std::ostream &os, const Version &object); struct ScannerAdaptor { virtual ~ScannerAdaptor() = default; - virtual void parse(const std::string &filename, Version &version) const = 0; + virtual void parse(const std::string &file_name, Version &version) const = 0; }; class ScannerFlexBison : public ScannerAdaptor { protected: void *scanner_{ nullptr }; - void parse_(const std::string &filename, Version &version) const; + void parse_(const std::string &file_name, Version &version) const; public: ScannerFlexBison(); ~ScannerFlexBison() override; - void parse(const std::string &filename, Version &version) const override = 0; + void parse(const std::string &file_name, Version &version) const override = 0; }; @@ -82,7 +82,7 @@ class ScannerFlexBisonFile : public ScannerFlexBison { public: explicit ScannerFlexBisonFile(FILE *fp); ~ScannerFlexBisonFile() override = default; - void parse(const std::string &filename, Version &version) const override; + void parse(const std::string &file_name, Version &version) const override; }; @@ -91,29 +91,28 @@ class ScannerFlexBisonString : public ScannerFlexBison { public: explicit ScannerFlexBisonString(const char *data); ~ScannerFlexBisonString() override = default; - void parse(const std::string &filename, Version &version) const override; + void parse(const std::string &file_name, Version &version) const override; }; /** - * Parse the given file to get its version number. + * Parse the given file path to get its version number. * Throws an AnalysisError if this fails. */ -Version parse_file(const std::string &filename); +Version parse_file(const std::string &file_path); /** * Parse using the given file pointer to get its version number. * Throws an AnalysisError if this fails. - * The file is rewound back to the start when parsing completes. - * A filename may be given in addition for use within the AnalysisError thrown when version parsing fails. + * A file_name may be given in addition for use within the AnalysisError thrown when version parsing fails. */ -Version parse_file(FILE *file, const std::string &filename = ""); +Version parse_file(FILE* fp, const std::string &file_name = ""); /** * Parse the given string as a file to get its version number. - * A filename may be given in addition for use within the AnalysisError thrown when version parsing fails. + * A file_name may be given in addition for use within the AnalysisError thrown when version parsing fails. */ -Version parse_string(const std::string &data, const std::string &filename = ""); +Version parse_string(const std::string &data, const std::string &file_name = ""); /** @@ -128,13 +127,10 @@ class ParseHelper { /** * Name of the file being parsed. */ - std::string filename; + std::string file_name; public: - /** - * Parse a file with flex/bison. - */ - explicit ParseHelper(std::unique_ptr scanner_up, std::string filename = ""); + explicit ParseHelper(std::unique_ptr scanner_up, std::string file_name = ""); /** * Does the actual parsing. diff --git a/include/v1x/cqasm-parse-helper.hpp b/include/v1x/cqasm-parse-helper.hpp index 773f7fb2..8b5dacf2 100644 --- a/include/v1x/cqasm-parse-helper.hpp +++ b/include/v1x/cqasm-parse-helper.hpp @@ -26,20 +26,20 @@ namespace parser { using SourceLocation = annotations::SourceLocation; /** - * Parse the given file. + * Parse the given file path. */ -ParseResult parse_file(const std::string &filename); +ParseResult parse_file(const std::string &file_path); /** * Parse using the given file pointer. */ -ParseResult parse_file(FILE *file, const std::string &filename = ""); +ParseResult parse_file(FILE* fp, const std::string &file_name = ""); /** - * Parse the given string. A filename may be given in addition for use within - * error messages. + * Parse the given string. + * A file_name may be given in addition for use within error messages. */ -ParseResult parse_string(const std::string &data, const std::string &filename=""); +ParseResult parse_string(const std::string &data, const std::string &file_name=""); /** * Internal helper class for parsing cQASM files. @@ -65,7 +65,7 @@ class ParseHelper { /** * Name of the file being parsed. */ - std::string filename; + std::string file_name; /** * The parse result. @@ -73,23 +73,22 @@ class ParseHelper { ParseResult result; private: - friend ParseResult parse_file(const std::string &filename); - friend ParseResult parse_file(FILE *file, const std::string &filename); - friend ParseResult parse_string(const std::string &data, const std::string &filename); + friend ParseResult parse_file(const std::string &file_path); + friend ParseResult parse_file(FILE* fp, const std::string &file_name); + friend ParseResult parse_string(const std::string &data, const std::string &file_name); /** - * Parse a string or file with flex/bison. If use_file is set, the file - * specified by filename is read and data is ignored. Otherwise, filename - * is used only for error messages, and data is read instead. Don't use - * this directly, use parse(). + * Parse a string or file with flex/bison. + * If use_file is set, the file specified by file_path is read and data is ignored. + * Otherwise, file_path is used only for error messages, and data is read instead. + * Don't use this directly, use parse(). */ - ParseHelper(const std::string &filename, const std::string &data, bool use_file); + ParseHelper(const std::string &file_path, const std::string &data, bool use_file); /** - * Construct the analyzer internals for the given filename, and analyze - * the file. + * Construct the analyzer internals for the given file_name, and analyze the file. */ - ParseHelper(const std::string &filename, FILE *fptr); + ParseHelper(const std::string &file_name, FILE *fptr); /** * Initializes the scanner. Returns whether this was successful. diff --git a/include/v1x/cqasm.hpp b/include/v1x/cqasm.hpp index 4f12819e..ab819707 100644 --- a/include/v1x/cqasm.hpp +++ b/include/v1x/cqasm.hpp @@ -22,33 +22,33 @@ namespace cqasm { namespace v1x { /** - * Parses and analyzes the given file with the default analyzer, dumping error + * Parses and analyzes the given file path with the default analyzer, dumping error * messages to stderr and throwing an analyzer::AnalysisFailed on failure. */ tree::One analyze( - const std::string &filename, + const std::string &file_path, const std::string &api_version = "1.0" ); /** * Parses and analyzes the given file pointer with the default analyzer, dumping * error messages to stderr and throwing an analyzer::AnalysisFailed on failure. - * The optional filename is only used for error messages. + * The optional file_name is only used for error messages. */ tree::One analyze( - FILE *file, - const std::string &filename = "", + FILE *fp, + const std::string &file_name = "", const std::string &api_version = "1.0" ); /** * Parses and analyzes the given string with the default analyzer, dumping * error messages to stderr and throwing an analyzer::AnalysisFailed on failure. - * The optional filename is only used for error messages. + * The optional file_name is only used for error messages. */ tree::One analyze_string( const std::string &data, - const std::string &filename = "", + const std::string &file_name = "", const std::string &api_version = "1.0" ); diff --git a/include/v3x/cqasm-parse-helper.hpp b/include/v3x/cqasm-parse-helper.hpp index 99ad0076..47a81623 100644 --- a/include/v3x/cqasm-parse-helper.hpp +++ b/include/v3x/cqasm-parse-helper.hpp @@ -8,8 +8,13 @@ #include "cqasm-annotations.hpp" #include "v1x/cqasm-parse-result.hpp" +#include "v3x/cqasm_lexer.h" -#include +#include "antlr4-runtime/antlr4-runtime.h" + +#include // ifstream +#include // unique_ptr +#include namespace cqasm { @@ -24,94 +29,74 @@ namespace parser { // Make sure it exists here for compatibility. using SourceLocation = annotations::SourceLocation; -/** - * Parse the given file. - */ -cqasm::v1x::parser::ParseResult parse_file(const std::string &filename); + +struct ScannerAdaptor { + virtual ~ScannerAdaptor() = default; + + virtual void parse(const std::string &file_name, cqasm::v1x::parser::ParseResult &result) = 0; +}; + +class ScannerAntlr : public ScannerAdaptor { +protected: + void parse_(const std::string & /* file_name */, cqasm::v1x::parser::ParseResult & /* result */, + antlr4::ANTLRInputStream &is); +public: + ScannerAntlr(); + ~ScannerAntlr() override; + void parse(const std::string &file_name, cqasm::v1x::parser::ParseResult &result) = 0; +}; + +class ScannerAntlrFile : public ScannerAntlr { + std::ifstream ifs_; +public: + explicit ScannerAntlrFile(const std::string &file_path); + ~ScannerAntlrFile() override; + void parse(const std::string &file_name, cqasm::v1x::parser::ParseResult &result) override; +}; + +class ScannerAntlrString : public ScannerAntlr { + std::string data_; +public: + explicit ScannerAntlrString(const std::string &data); + ~ScannerAntlrString() override; + void parse(const std::string &file_name, cqasm::v1x::parser::ParseResult &result) override; +}; + /** - * Parse using the given file pointer. + * Parse using the given file path. + * Throws an AnalysisError if this fails. */ -cqasm::v1x::parser::ParseResult parse_file(FILE *file, const std::string &filename = ""); +cqasm::v1x::parser::ParseResult parse_file(const std::string &file_path, const std::string &file_name = ""); /** - * Parse the given string. A filename may be given in addition for use within - * error messages. + * Parse the given string. + * A file_name may be given in addition for use within error messages. */ -cqasm::v1x::parser::ParseResult parse_string(const std::string &data, const std::string &filename=""); +cqasm::v1x::parser::ParseResult parse_string(const std::string &data, const std::string &file_name=""); + /** * Internal helper class for parsing cQASM files. */ class ParseHelper { -public: - - /** - * File pointer being scanned, if no data was specified. - */ - FILE *fptr = nullptr; - /** - * Flex data buffer, if data was specified. + * Scanner doing the actual parsing. */ - void *buf = nullptr; - - /** - * Flex reentrant scanner data. - */ - void *scanner = nullptr; + std::unique_ptr scanner_up_; /** * Name of the file being parsed. */ - std::string filename; - - /** - * The parse result. - */ - cqasm::v1x::parser::ParseResult result; - -private: - friend cqasm::v1x::parser::ParseResult parse_file(const std::string &filename); - friend cqasm::v1x::parser::ParseResult parse_file(FILE *file, const std::string &filename); - friend cqasm::v1x::parser::ParseResult parse_string(const std::string &data, const std::string &filename); - - /** - * Parse a string or file with flex/bison. If use_file is set, the file - * specified by filename is read and data is ignored. Otherwise, filename - * is used only for error messages, and data is read instead. Don't use - * this directly, use parse(). - */ - ParseHelper(const std::string &filename, const std::string &data, bool use_file); - - /** - * Construct the analyzer internals for the given filename, and analyze - * the file. - */ - ParseHelper(const std::string &filename, FILE *fptr); - - /** - * Initializes the scanner. Returns whether this was successful. - */ - bool construct(); - - /** - * Does the actual parsing. - */ - void parse(); + std::string file_name; public: + explicit ParseHelper(std::unique_ptr scanner_up, std::string file_name = ""); /** - * Destroys the parse helper. - */ - virtual ~ParseHelper(); - - /** - * Pushes an error. + * Does the actual parsing. */ - void push_error(const std::string &error); - + cqasm::v1x::parser::ParseResult parse(); }; } // namespace parser diff --git a/include/v3x/cqasm.hpp b/include/v3x/cqasm.hpp index 71586aa0..9c8973e6 100644 --- a/include/v3x/cqasm.hpp +++ b/include/v3x/cqasm.hpp @@ -16,45 +16,33 @@ namespace cqasm { /** - * Namespace for the "new" cQASM 3.x API. Its contents are pulled into the main - * cQASM namespace when you include "cqasm.hpp" for compatibility. + * Namespace for the "new" cQASM 3.x API. + * Its contents are pulled into the main cQASM namespace when you include "cqasm.hpp" for compatibility. */ namespace v3x { /** - * Parses and analyzes the given file with the default analyzer, dumping error - * messages to stderr and throwing an analyzer::AnalysisFailed on failure. + * Parses and analyzes the given file path with the default analyzer, + * dumping error messages to stderr and throwing an analyzer::AnalysisFailed on failure. */ tree::One analyze( - const std::string &filename, + const std::string &file_path, const std::string &api_version = "1.0" ); /** - * Parses and analyzes the given file pointer with the default analyzer, dumping - * error messages to stderr and throwing an analyzer::AnalysisFailed on failure. - * The optional filename is only used for error messages. - */ -tree::One analyze( - FILE *file, - const std::string &filename = "", - const std::string &api_version = "1.0" -); - -/** - * Parses and analyzes the given string with the default analyzer, dumping - * error messages to stderr and throwing an analyzer::AnalysisFailed on failure. - * The optional filename is only used for error messages. + * Parses and analyzes the given string with the default analyzer, + * dumping error messages to stderr and throwing an analyzer::AnalysisFailed on failure. + * The optional file_name is only used for error messages. */ tree::One analyze_string( const std::string &data, - const std::string &filename = "", + const std::string &file_name = "", const std::string &api_version = "1.0" ); /** - * Constructs an Analyzer object with the defaults for cQASM 1.0 already loaded - * into it. + * Constructs an Analyzer object with the defaults for cQASM 1.0 already loaded into it. */ cqasm::v1x::analyzer::Analyzer default_analyzer( const std::string &api_version = "1.0" diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 53f419aa..a645e49b 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -53,6 +53,7 @@ else() endif() find_package(antlr4-runtime REQUIRED) +find_package(fmt REQUIRED) find_package(Python3 REQUIRED) #------------------------------------------------------------------------------- @@ -232,9 +233,10 @@ target_compile_features(cqasm-lib-obj PUBLIC cxx_std_20 ) -target_link_libraries(cqasm-lib-obj PUBLIC - antlr4_static - tree-lib-obj +target_link_libraries(cqasm-lib-obj + PRIVATE antlr4_static + PRIVATE fmt::fmt + PRIVATE tree-lib-obj ) # fPIC: otherwise some weirdness happens with pthreads or something when linking statically. diff --git a/src/cqasm-version.cpp b/src/cqasm-version.cpp index 3febfb41..16943557 100644 --- a/src/cqasm-version.cpp +++ b/src/cqasm-version.cpp @@ -100,14 +100,14 @@ ScannerFlexBison::~ScannerFlexBison() { } } -void ScannerFlexBison::parse_(const std::string &filename, Version &version) const { - auto result = cqasm_version_parse(static_cast(scanner_), filename, version); +void ScannerFlexBison::parse_(const std::string &file_name, Version &version) const { + auto result = cqasm_version_parse(static_cast(scanner_), file_name, version); if (result == 2) { throw error::AnalysisError( - std::string("ScannerFlexBison::parse_: out of memory while parsing '") + filename + "'."); + std::string("ScannerFlexBison::parse_: out of memory while parsing '") + file_name + "'."); } else if (result != 0) { throw error::AnalysisError( - std::string("ScannerFlexBison::parse_: failed to parse '") + filename + "'."); + std::string("ScannerFlexBison::parse_: failed to parse '") + file_name + "'."); } } @@ -119,37 +119,37 @@ ScannerFlexBisonFile::ScannerFlexBisonFile(FILE *fp } } -void ScannerFlexBisonFile::parse(const std::string &filename, Version &version) const { +void ScannerFlexBisonFile::parse(const std::string &file_name, Version &version) const { cqasm_version_set_in(fp_, static_cast(scanner_)); - parse_(filename, version); + parse_(file_name, version); } ScannerFlexBisonString::ScannerFlexBisonString(const char *data ) : data_{ data } {} -void ScannerFlexBisonString::parse(const std::string &filename, Version &version) const { +void ScannerFlexBisonString::parse(const std::string &file_name, Version &version) const { auto buffer = cqasm_version__scan_string(data_, static_cast(scanner_)); if (!buffer) { throw error::AnalysisError("ScannerFlexBisonString failed to scan input data string."); } - parse_(filename, version); + parse_(file_name, version); cqasm_version__delete_buffer(buffer, static_cast(scanner_)); } /** - * Parse the given file to get its version number. + * Parse the given file path to get its version number. * Throws an AnalysisError if this fails. */ -Version parse_file(const std::string &filename) { - FILE *fp = fopen(filename.c_str(), "r"); +Version parse_file(const std::string &file_path) { + FILE *fp = fopen(file_path.c_str(), "r"); if (!fp) { throw error::AnalysisError( - std::string("parse_file failed to open input file '") + filename + "': " + strerror(errno) + "."); + std::string("parse_file failed to open input file '") + file_path + "': " + strerror(errno) + "."); } auto scanner_up = std::make_unique(fp); - auto version = ParseHelper(std::move(scanner_up), filename).parse(); + auto version = ParseHelper(std::move(scanner_up), file_path).parse(); fclose(fp); return version; } @@ -159,9 +159,9 @@ Version parse_file(const std::string &filename) { * Throws an AnalysisError if this fails. * The file is rewound back to the start when parsing completes. */ -Version parse_file(FILE *fp, const std::string &filename) { +Version parse_file(FILE *fp, const std::string &file_name) { auto scanner_up = std::make_unique(fp); - auto version = ParseHelper(std::move(scanner_up), filename).parse(); + auto version = ParseHelper(std::move(scanner_up), file_name).parse(); rewind(fp); return version; } @@ -169,23 +169,24 @@ Version parse_file(FILE *fp, const std::string &filename) { /** * Parse the given string as a file to get its version number. */ -Version parse_string(const std::string &data, const std::string &filename) { +Version parse_string(const std::string &data, const std::string &file_name) { auto scanner_up = std::make_unique(data.c_str()); - return ParseHelper(std::move(scanner_up), filename).parse(); + return ParseHelper(std::move(scanner_up), file_name).parse(); } -ParseHelper::ParseHelper(std::unique_ptr scanner_up, std::string filename) -: scanner_up_(std::move(scanner_up)), filename(std::move(filename)) {} +ParseHelper::ParseHelper(std::unique_ptr scanner_up, std::string file_name) +: scanner_up_(std::move(scanner_up)), file_name(std::move(file_name)) {} /** * Does the actual parsing. */ Version ParseHelper::parse() { Version version; - scanner_up_->parse(filename, version); + scanner_up_->parse(file_name, version); if (version.empty()) { - throw error::AnalysisError("ParseHelper::parse: no version info nor error info was returned by version parser."); + throw error::AnalysisError( + "ParseHelper::parse: no version info nor error info was returned by version parser."); } return version; } diff --git a/src/v1x/cqasm-parse-helper.cpp b/src/v1x/cqasm-parse-helper.cpp index e9384912..ed4b6c7a 100644 --- a/src/v1x/cqasm-parse-helper.cpp +++ b/src/v1x/cqasm-parse-helper.cpp @@ -11,48 +11,48 @@ namespace v1x { namespace parser { /** - * Parse the given file. + * Parse the given file path. */ -ParseResult parse_file(const std::string &filename) { - return ParseHelper(filename, "", true).result; +ParseResult parse_file(const std::string &file_path) { + return ParseHelper(file_path, "", true).result; } /** * Parse using the given file pointer. */ -ParseResult parse_file(FILE *file, const std::string &filename) { - return ParseHelper(filename, file).result; +ParseResult parse_file(FILE *file, const std::string &file_name) { + return ParseHelper(file_name, file).result; } /** - * Parse the given string. A filename may be given in addition for use within - * error messages. + * Parse the given string. + * A file_name may be given in addition for use within error messages. */ -ParseResult parse_string(const std::string &data, const std::string &filename) { - return ParseHelper(filename, data, false).result; +ParseResult parse_string(const std::string &data, const std::string &file_name) { + return ParseHelper(file_name, data, false).result; } /** - * Parse a string or file with flex/bison. If use_file is set, the file - * specified by filename is read and data is ignored. Otherwise, filename - * is used only for error messages, and data is read instead. Don't use - * this directly, use parse(). + * Parse a string or file with flex/bison. + * If use_file is set, the file specified by file_path is read and data is ignored. + * Otherwise, file_path is used only for error messages, and data is read instead. + * Don't use this directly, use parse(). */ ParseHelper::ParseHelper( - const std::string &filename, + const std::string &file_path, const std::string &data, bool use_file -) : filename(filename) { +) : file_name(file_path) { // Create the scanner. if (!construct()) return; // Open the file or pass the data buffer to flex. if (use_file) { - fptr = fopen(filename.c_str(), "r"); + fptr = fopen(file_path.c_str(), "r"); if (!fptr) { std::ostringstream sb; - sb << "Failed to open input file " << filename << ": " + sb << "Failed to open input file " << file_path << ": " << strerror(errno); push_error(sb.str()); return; @@ -68,13 +68,12 @@ ParseHelper::ParseHelper( } /** - * Construct the analyzer internals for the given filename, and analyze - * the file. + * Construct the analyzer internals for the given file_name, and analyze the file. */ ParseHelper::ParseHelper( - const std::string &filename, + const std::string &file_name, FILE *fptr -) : filename(filename) { +) : file_name(file_name) { // Create the scanner. if (!construct()) return; @@ -88,7 +87,8 @@ ParseHelper::ParseHelper( } /** - * Initializes the scanner. Returns whether this was successful. + * Initializes the scanner. + * Returns whether this was successful. */ bool ParseHelper::construct() { int retcode = cqasm_v1x_lex_init((yyscan_t*)&scanner); @@ -109,12 +109,12 @@ void ParseHelper::parse() { int retcode = cqasm_v1x_parse((yyscan_t) scanner, *this); if (retcode == 2) { std::ostringstream sb; - sb << "Out of memory while parsing " << filename; + sb << "Out of memory while parsing " << file_name; push_error(sb.str()); return; } else if (retcode) { std::ostringstream sb; - sb << "Failed to parse " << filename; + sb << "Failed to parse " << file_name; push_error(sb.str()); return; } diff --git a/src/v1x/cqasm-parser.y b/src/v1x/cqasm-parser.y index b5c84ec8..8c4f674f 100644 --- a/src/v1x/cqasm-parser.y +++ b/src/v1x/cqasm-parser.y @@ -45,7 +45,7 @@ void free_string(char *s) { */ #define ADD_SOURCE_LOCATION(v) \ v->set_annotation(cqasm::annotations::SourceLocation( \ - helper.filename, \ + helper.file_name, \ yyloc.first_line, \ yyloc.first_column, \ yyloc.last_line, \ @@ -678,7 +678,7 @@ Root : Program void yyerror(YYLTYPE* yyllocp, yyscan_t unused, cqasm::v1x::parser::ParseHelper &helper, const char* msg) { (void)unused; std::ostringstream sb; - sb << helper.filename + sb << helper.file_name << ":" << yyllocp->first_line << ":" << yyllocp->first_column << ": " << msg; diff --git a/src/v1x/cqasm.cpp b/src/v1x/cqasm.cpp index 1ff752b0..31829eae 100644 --- a/src/v1x/cqasm.cpp +++ b/src/v1x/cqasm.cpp @@ -15,48 +15,48 @@ namespace cqasm { namespace v1x { /** - * Parses and analyzes the given file with the default analyzer, + * Parses and analyzes the given file path with the default analyzer, * dumping error messages to stderr and throwing an analyzer::AnalysisFailed on failure. */ tree::One analyze( - const std::string &filename, + const std::string &file_path, const std::string &api_version ) { return default_analyzer(api_version).analyze( - [=](){ return version::parse_file(filename); }, - [=](){ return parser::parse_file(filename); } + [=](){ return version::parse_file(file_path); }, + [=](){ return parser::parse_file(file_path); } ).unwrap(); } /** * Parses and analyzes the given file pointer with the default analyzer, * dumping error messages to stderr and throwing an analyzer::AnalysisFailed on failure. - * The optional filename is only used for error messages. + * The optional file_name is only used for error messages. */ tree::One analyze( - FILE *file, - const std::string &filename, + FILE *fp, + const std::string &file_name, const std::string &api_version ) { return default_analyzer(api_version).analyze( - [=](){ return version::parse_file(file, filename); }, - [=](){ return parser::parse_file(file, filename); } + [=](){ return version::parse_file(fp, file_name); }, + [=](){ return parser::parse_file(fp, file_name); } ).unwrap(); } /** * Parses and analyzes the given string with the default analyzer, * dumping error messages to stderr and throwing an analyzer::AnalysisFailed on failure. - * The optional filename is only used for error messages. + * The optional file_name is only used for error messages. */ tree::One analyze_string( const std::string &data, - const std::string &filename, + const std::string &file_name, const std::string &api_version ) { return default_analyzer(api_version).analyze( - [=](){ return version::parse_string(data, filename); }, - [=](){ return parser::parse_string(data, filename); } + [=](){ return version::parse_string(data, file_name); }, + [=](){ return parser::parse_string(data, file_name); } ).unwrap(); } diff --git a/src/v3x/cqasm-parse-helper.cpp b/src/v3x/cqasm-parse-helper.cpp index e1b89375..1766f158 100644 --- a/src/v3x/cqasm-parse-helper.cpp +++ b/src/v3x/cqasm-parse-helper.cpp @@ -3,79 +3,92 @@ */ #include "v1x/cqasm-parse-result.hpp" +#include "v3x/cqasm_lexer.h" +#include "v3x/cqasm_parser.h" #include "v3x/cqasm-parse-helper.hpp" +#include "antlr4-runtime/antlr4-runtime.h" + +#include +#include +#include // ifstream #include // runtime_error +namespace fs = std::filesystem; + namespace cqasm { namespace v3x { namespace parser { -/** - * Parse the given file. - */ -cqasm::v1x::parser::ParseResult parse_file(const std::string & /* filename */) { - throw std::runtime_error("Unimplemented"); +ScannerAntlr::ScannerAntlr() {} + +ScannerAntlr::~ScannerAntlr() {} + +void ScannerAntlr::parse_(const std::string & /* file_name */, cqasm::v1x::parser::ParseResult & /* result */, + antlr4::ANTLRInputStream &is) { + cqasm_lexer lexer{ &is }; + antlr4::CommonTokenStream tokens{ &lexer }; + cqasm_parser parser{ &tokens }; + // Transform parser.expr() into a ParseResult } -/** - * Parse using the given file pointer. - */ -cqasm::v1x::parser::ParseResult parse_file(FILE * /* file */, const std::string & /* filename */) { - throw std::runtime_error("Unimplemented"); +ScannerAntlrFile::ScannerAntlrFile(const std::string &file_path) +: ifs_{ file_path } { + if (!ifs_.is_open()) { + throw error::AnalysisError("ScannerAntlrFile couldn't access file."); + } } -/** - * Parse the given string. A filename may be given in addition for use within - * error messages. - */ -cqasm::v1x::parser::ParseResult parse_string(const std::string & /* data */, const std::string & /* filename */) { - throw std::runtime_error("Unimplemented"); +void ScannerAntlrFile::parse(const std::string &file_name, cqasm::v1x::parser::ParseResult &result) { + antlr4::ANTLRInputStream is{ ifs_ }; + parse_(file_name, result, is); } -/** - * Parse a string or file with flex/bison. If use_file is set, the file - * specified by filename is read and data is ignored. Otherwise, filename - * is used only for error messages, and data is read instead. Don't use - * this directly, use parse(). - */ -ParseHelper::ParseHelper( - const std::string &filename, - const std::string &, - bool -) : filename(filename) {} +ScannerAntlrString::ScannerAntlrString(const std::string &data) +: data_{ data } {} -/** - * Construct the analyzer internals for the given filename, and analyze - * the file. - */ -ParseHelper::ParseHelper( - const std::string &filename, - FILE * -) : filename(filename) {} +void ScannerAntlrString::parse(const std::string &file_name, cqasm::v1x::parser::ParseResult &result) { + antlr4::ANTLRInputStream is{ data_ }; + parse_(file_name, result, is); +} /** - * Initializes the scanner. Returns whether this was successful. + * Parse using the given file path. + * Throws an AnalysisError if the file does not exist. + * A file_name may be given in addition for use within error messages. */ -bool ParseHelper::construct() { - return true; +cqasm::v1x::parser::ParseResult parse_file(const std::string &file_path, const std::string &file_name) { + auto scanner_up = std::make_unique(file_path); + return ParseHelper(std::move(scanner_up), file_name).parse(); } /** - * Does the actual parsing. + * Parse the given string. + * A file_name may be given in addition for use within error messages. */ -void ParseHelper::parse() {} +cqasm::v1x::parser::ParseResult parse_string(const std::string &data, const std::string &file_name) { + auto scanner_up = std::make_unique(data); + return ParseHelper(std::move(scanner_up), file_name).parse(); +} -/** - * Destroys the analyzer. - */ -ParseHelper::~ParseHelper() {} + +ParseHelper::ParseHelper(std::unique_ptr scanner_up, std::string file_name) +: scanner_up_(std::move(scanner_up)), file_name(std::move(file_name)) {} /** - * Pushes an error. + * Does the actual parsing. */ -void ParseHelper::push_error(const std::string &) {} +cqasm::v1x::parser::ParseResult ParseHelper::parse() { + cqasm::v1x::parser::ParseResult result; + scanner_up_->parse(file_name, result); + if (result.errors.empty() && !result.root.is_well_formed()) { + std::cerr << *result.root; + throw error::AnalysisError( + "ParseHelper::parse: no parse errors returned, but AST is incomplete. AST was dumped."); + } + return result; +} } // namespace parser } // namespace v3x diff --git a/src/v3x/cqasm.cpp b/src/v3x/cqasm.cpp index 7840dc5c..13519f28 100644 --- a/src/v3x/cqasm.cpp +++ b/src/v3x/cqasm.cpp @@ -18,48 +18,32 @@ namespace cqasm { namespace v3x { /** - * Parses and analyzes the given file with the default analyzer, + * Parses and analyzes the given file path with the default analyzer, * dumping error messages to stderr and throwing an analyzer::AnalysisFailed on failure. */ tree::One analyze( - const std::string &filename, + const std::string &file_path, const std::string &api_version ) { return default_analyzer(api_version).analyze( - [=](){ return version::parse_file(filename); }, - [=](){ return parser::parse_file(filename); } - ).unwrap(); -} - -/** - * Parses and analyzes the given file pointer with the default analyzer, - * dumping error messages to stderr and throwing an analyzer::AnalysisFailed on failure. - * The optional filename is only used for error messages. - */ -tree::One analyze( - FILE *file, - const std::string &filename, - const std::string &api_version -) { - return default_analyzer(api_version).analyze( - [=](){ return version::parse_file(file, filename); }, - [=](){ return parser::parse_file(file, filename); } + [=](){ return version::parse_file(file_path); }, + [=](){ return parser::parse_file(file_path); } ).unwrap(); } /** * Parses and analyzes the given string with the default analyzer, * dumping error messages to stderr and throwing an analyzer::AnalysisFailed on failure. - * The optional filename is only used for error messages. + * The optional file_name is only used for error messages. */ tree::One analyze_string( const std::string &data, - const std::string &filename, + const std::string &file_name, const std::string &api_version ) { return default_analyzer(api_version).analyze( - [=](){ return version::parse_string(data, filename); }, - [=](){ return parser::parse_string(data, filename); } + [=](){ return version::parse_string(data, file_name); }, + [=](){ return parser::parse_string(data, file_name); } ).unwrap(); } From 502b607f2039c15f112fa8cf14b095d68f64c84d Mon Sep 17 00:00:00 2001 From: rturrado Date: Wed, 13 Sep 2023 18:30:47 +0200 Subject: [PATCH 03/28] Started implementing the toy v1 ANTLR parser. - BuildTreeGenAstVisitor.{h,cpp}: visitor of the AST returned by ANTLR which builds a tree-gen AST (not finished yet!). - cqasm-parse-helper.cpp: added code at ScannerAntlr::parse_ to convert the AST returned by ANTLR into a tree-gen AST. - generate_antlr_parser.py: added a parameter to generate a base visitor class. - Cqasm{Lexer,Parser}.g4: renamed cqasm_lexer.g4 and cqasm_parser.g4 to CqasmLexer.g4 and CqasmParser.ge as these texts are used as class names, and all ANTLR class names are written in camel case. - CqasmParser.g4: renamed expressions from snake case to camel case (for the same reason as above). - test_cases.txt: I will use this as a guide for the integration tests. --- include/cqasm-version.hpp | 1 + include/v1x/cqasm-ast.hpp | 2 +- include/v1x/cqasm-parse-result.hpp | 10 ++-- include/v1x/cqasm-primitives.hpp | 2 +- include/v1x/cqasm-resolver.hpp | 2 +- include/v3x/BuildTreeGenAstVisitor.h | 26 +++++++++ include/v3x/cqasm-parse-helper.hpp | 14 +---- res/v3x/toy-v1/test_cases.txt | 68 +++++++++++++++++++++++ scripts/generate_antlr_parser.py | 7 ++- src/CMakeLists.txt | 12 ++-- src/v3x/CMakeLists.txt | 1 + src/v3x/{cqasm_lexer.g4 => CqasmLexer.g4} | 2 +- src/v3x/CqasmParser.g4 | 39 +++++++++++++ src/v3x/cqasm-parse-helper.cpp | 25 +++++++-- src/v3x/cqasm_parser.g4 | 41 -------------- 15 files changed, 176 insertions(+), 76 deletions(-) create mode 100644 include/v3x/BuildTreeGenAstVisitor.h create mode 100644 res/v3x/toy-v1/test_cases.txt rename src/v3x/{cqasm_lexer.g4 => CqasmLexer.g4} (97%) create mode 100644 src/v3x/CqasmParser.g4 delete mode 100644 src/v3x/cqasm_parser.g4 diff --git a/include/cqasm-version.hpp b/include/cqasm-version.hpp index 02b8bd37..2888fe22 100644 --- a/include/cqasm-version.hpp +++ b/include/cqasm-version.hpp @@ -6,6 +6,7 @@ #include "cqasm-error.hpp" +#include // int64_t #include // FILE* #include // unique_ptr #include diff --git a/include/v1x/cqasm-ast.hpp b/include/v1x/cqasm-ast.hpp index 0c42ca5e..7583ba2d 100644 --- a/include/v1x/cqasm-ast.hpp +++ b/include/v1x/cqasm-ast.hpp @@ -5,5 +5,5 @@ #pragma once -#include "../cqasm-string-builder.hpp" +#include "cqasm-string-builder.hpp" #include "v1x/cqasm-ast-gen.hpp" diff --git a/include/v1x/cqasm-parse-result.hpp b/include/v1x/cqasm-parse-result.hpp index faf6092c..7cceb003 100644 --- a/include/v1x/cqasm-parse-result.hpp +++ b/include/v1x/cqasm-parse-result.hpp @@ -26,15 +26,15 @@ class ParseResult { public: /** - * Root node of the AST, if analysis was sufficiently successful. This may - * be set even if parsing was not ENTIRELY successful, in which case it - * will contain one or more error nodes. + * Root node of the AST, if analysis was sufficiently successful. + * This may be set even if parsing was not ENTIRELY successful, + * in which case it will contain one or more error nodes. */ ast::One root; /** - * List of accumulated errors. Analysis was successful if and only if - * `errors.empty()`. + * List of accumulated errors. + * Analysis was successful if and only if errors.empty(). */ std::vector errors; diff --git a/include/v1x/cqasm-primitives.hpp b/include/v1x/cqasm-primitives.hpp index 0edfa579..d17dab4a 100644 --- a/include/v1x/cqasm-primitives.hpp +++ b/include/v1x/cqasm-primitives.hpp @@ -4,7 +4,7 @@ #pragma once -#include "../cqasm-version.hpp" +#include "cqasm-version.hpp" #include "tree-cbor.hpp" #include diff --git a/include/v1x/cqasm-resolver.hpp b/include/v1x/cqasm-resolver.hpp index 0dcd0e2e..0a500c4a 100644 --- a/include/v1x/cqasm-resolver.hpp +++ b/include/v1x/cqasm-resolver.hpp @@ -7,7 +7,7 @@ #pragma once -#include "../cqasm-error.hpp" +#include "cqasm-error.hpp" #include "cqasm-error-model.hpp" #include "cqasm-instruction.hpp" #include "cqasm-semantic.hpp" diff --git a/include/v3x/BuildTreeGenAstVisitor.h b/include/v3x/BuildTreeGenAstVisitor.h new file mode 100644 index 00000000..4c8f672f --- /dev/null +++ b/include/v3x/BuildTreeGenAstVisitor.h @@ -0,0 +1,26 @@ +#pragma once + +#include "antlr4-runtime.h" +#include "v3x/CqasmParser.h" +#include "v3x/CqasmParserVisitor.h" + +#include + + +namespace cqasm::v3x::parser { + +class BuildTreeGenAstVisitor : public CqasmParserVisitor { +public: + std::any visitProgram(CqasmParser::ProgramContext *context) override; + std::any visitVersion(CqasmParser::VersionContext *context) override; + std::any visitStatement(CqasmParser::StatementContext *context) override; + std::any visitMapStatement(CqasmParser::MapStatementContext *context) override; + std::any visitVarStatement(CqasmParser::VarStatementContext *context) override; + std::any visitInstruction(CqasmParser::InstructionContext *context) override; + std::any visitExpressionList(CqasmParser::ExpressionListContext *context) override; + std::any visitExpression(CqasmParser::ExpressionContext *context) override; + std::any visitArrayElements(CqasmParser::ArrayElementsContext *context) override; + std::any visitArrayIndex(CqasmParser::ArrayIndexContext *context) override; +}; + +} // namespace cqasm::v3x::parser diff --git a/include/v3x/cqasm-parse-helper.hpp b/include/v3x/cqasm-parse-helper.hpp index 47a81623..1e31ba26 100644 --- a/include/v3x/cqasm-parse-helper.hpp +++ b/include/v3x/cqasm-parse-helper.hpp @@ -8,7 +8,7 @@ #include "cqasm-annotations.hpp" #include "v1x/cqasm-parse-result.hpp" -#include "v3x/cqasm_lexer.h" +#include "v3x/CqasmLexer.h" #include "antlr4-runtime/antlr4-runtime.h" @@ -17,13 +17,7 @@ #include -namespace cqasm { -namespace v3x { - -/** - * Namespace for the parser functions and classes. - */ -namespace parser { +namespace cqasm::v3x::parser { // SourceLocation used to live in this namespace, before the v3x namespace was a thing. // Make sure it exists here for compatibility. @@ -99,6 +93,4 @@ class ParseHelper { cqasm::v1x::parser::ParseResult parse(); }; -} // namespace parser -} // namespace v3x -} // namespace cqasm +} // namespace cqasm::v3x::parser diff --git a/res/v3x/toy-v1/test_cases.txt b/res/v3x/toy-v1/test_cases.txt new file mode 100644 index 00000000..7cfcde22 --- /dev/null +++ b/res/v3x/toy-v1/test_cases.txt @@ -0,0 +1,68 @@ +fail empty program +fail something before version blah; version 3 + +fail version without number version +fail bad version version blah +fail version not supported version 1.2 +OK OK version, no newline version 3 +OK OK version, semicolon version 3; +OK OK version, newline version 3\n +fail OK version, bad token version 3;123abc + +fail OK version, empty qubits version 3;qubits +fail OK version, wrong qubits version 3;qubits 123abc +OK OK version, OK qubits version 3;qubits 3 + +fail empty map version 3;map +fail empty map id version 3;map v +fail empty map id = version 3;map v = +OK OK map integer version 3;map v = 1 +OK OK map float version 3;map v = 3.14 +fail bad map id version 3;map w = v Syntactically correct, not semantically +OK OK map id version 3;map v = 1;map w = v +fail bad map array, no qubits version 3;map v = q[0] Syntactically correct, not semantically +fail bad map array, out of bounds qubit version 3;qubits 3;map v = q[3] Syntactically correct, not semantically +OK OK map array version 3;qubits 3;map v = q[0] + +fail empty var version 3;var +fail empty var id version 3;var v +fail empty var id : version 3;var v = +fail bad var id version 3;var w : v Syntactically correct, not semantically +OK OK var id version 3;map v : 1;var w : v + +fail empty instruction version 3;x +fail bad id version 3;v 1 Syntactically correct, not semantically +fail bad expression version 3;x 1 Syntactically correct, not semantically +fail bad instruction, no qubits version 3;x q[0] Syntactically correct, not semantically +fail bad instruction, out of bounds qubit version 3;qubits 3;x q[3] Syntactically correct, not semantically +OK OK one qubit instruction version 3;qubits 3;x q[0] +OK OK two qubit instruction version 3;qubits 3;h q[0];h q[1];cnot q[0], q[3] + +fail empty instruction expression version 3;qubits 3;x +fail bad instruction expression version 3;qubits 3;x 123abc +fail bad instruction expression integer version 3;qubits 3;x 1 Syntactically correct, not semantically +fail bad instruction expression float version 3;qubits 3;x 3.14 Syntactically correct, not semantically +fail bad instruction expression id version 3;qubits 3;x v Syntactically correct, not semantically + + +fail bad expression list, no second part version 3;qubits 3;h q[0];h q[1];cnot q[0], +fail bad expression list, bad first part version 3;qubits 3;h q[0];h q[1];cnot 123abc, q[0] +fail bad expression list, bad second part version 3;qubits 3;h q[0];h q[1];cnot q[0], 123abc + +Questions: +- What instructions are supported for the toy version? x, y, z, h? measure? + +Test implementation: +- Have a look at how it is done for v1x +- For semantic issues we probably need to do the checks at the AST level, kind of integration test +- However, I don't see why we cannot work with strings instead of files + +- We could just copy/paste, initially, test/v1x/parsing.cpp, simplifying it, removing instructions and functions +- Even comparing files. But, as I said above, I'd rather compare data structures (e.g. the AST) than files + +- The important stuff for this task would be to implement v3x/cqasm-parse-helper.cpp, + first refactor it like src/cqasm-version.cpp, + then make it call ANTLR +- All the AST stuff I would just copy/paste it from v1 + +- For this task, I will need help from Hans, maybe more than from Pablo diff --git a/scripts/generate_antlr_parser.py b/scripts/generate_antlr_parser.py index 81ab5560..f94e34cf 100644 --- a/scripts/generate_antlr_parser.py +++ b/scripts/generate_antlr_parser.py @@ -54,12 +54,15 @@ def generate_antlr_parser(input_folder, output_folder, antlr_jar_file_path): "java", "-jar", antlr_jar_file_path, + "-no-listener", + "-visitor", "-Xexact-output-dir", "-o", "{}".format(output_folder), "-Dlanguage=Cpp", - "{}/cqasm_lexer.g4".format(input_folder), - "{}/cqasm_parser.g4".format(input_folder) + "-Werror", + "{}/CqasmLexer.g4".format(input_folder), + "{}/CqasmParser.g4".format(input_folder) ]) if completed_process.returncode != 0: print("Error generating ANTLR lexer and parser files: {}", completed_process.returncode) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index a645e49b..8e17651b 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -183,10 +183,10 @@ function(antlr_target SCRIPT INPUT_DIR OUTPUT_DIR ANTLR_OUTPUTS) endfunction() set(ANTLR_OUTPUTS - "${CMAKE_CURRENT_BINARY_DIR}/v3x/cqasm_lexer.cpp" - "${CMAKE_CURRENT_BINARY_DIR}/v3x/cqasm_parser.cpp" - "${CMAKE_CURRENT_BINARY_DIR}/v3x/cqasm_parserBaseListener.cpp" - "${CMAKE_CURRENT_BINARY_DIR}/v3x/cqasm_parserListener.cpp" + "${CMAKE_CURRENT_BINARY_DIR}/v3x/CqasmLexer.cpp" + "${CMAKE_CURRENT_BINARY_DIR}/v3x/CqasmParser.cpp" + "${CMAKE_CURRENT_BINARY_DIR}/v3x/CqasmParserBaseVisitor.cpp" + "${CMAKE_CURRENT_BINARY_DIR}/v3x/CqasmParserVisitor.cpp" ) antlr_target( "${CMAKE_CURRENT_SOURCE_DIR}/../scripts/generate_antlr_parser.py" @@ -218,12 +218,10 @@ target_compile_definitions(cqasm-lib-obj target_include_directories(cqasm-lib-obj PRIVATE ${TREE_LIB_PRIVATE_INCLUDE} PUBLIC ${TREE_LIB_PUBLIC_INCLUDE} - PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/src" - PRIVATE "${CMAKE_CURRENT_BINARY_DIR}/src" - PRIVATE "${CMAKE_CURRENT_BINARY_DIR}/" # Do not remove the ending '/' since # it avoids the whole 'include' directory to be copied to the installation folder. # Instead, just its contents are copied. + PRIVATE "${CMAKE_CURRENT_BINARY_DIR}/" PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/../include/" PUBLIC "${CMAKE_CURRENT_BINARY_DIR}/../include/" PUBLIC "${antlr4-runtime_INCLUDE_DIR}" diff --git a/src/v3x/CMakeLists.txt b/src/v3x/CMakeLists.txt index 0cc4c7aa..49491c1c 100644 --- a/src/v3x/CMakeLists.txt +++ b/src/v3x/CMakeLists.txt @@ -2,5 +2,6 @@ set(CQASM_V3X_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/cqasm.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/cqasm-parse-helper.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/BuildTreeGenAstVisitor.cpp" PARENT_SCOPE ) diff --git a/src/v3x/cqasm_lexer.g4 b/src/v3x/CqasmLexer.g4 similarity index 97% rename from src/v3x/cqasm_lexer.g4 rename to src/v3x/CqasmLexer.g4 index c3cbee1f..af25c8b2 100644 --- a/src/v3x/cqasm_lexer.g4 +++ b/src/v3x/CqasmLexer.g4 @@ -1,4 +1,4 @@ -lexer grammar cqasm_lexer; +lexer grammar CqasmLexer; // Rules NEW_LINE: '\r'?'\n' -> skip; diff --git a/src/v3x/CqasmParser.g4 b/src/v3x/CqasmParser.g4 new file mode 100644 index 00000000..d30e919a --- /dev/null +++ b/src/v3x/CqasmParser.g4 @@ -0,0 +1,39 @@ +parser grammar CqasmParser; + +options { + tokenVocab = CqasmLexer; +} + +// Actual grammar start. +program: version QUBITS expression statement*; + +version: VERSION INTEGER_LITERAL (DOT INTEGER_LITERAL)?; + +statement: mapStatement | varStatement | instruction; + +mapStatement: MAP IDENTIFIER EQUAL expression; + +varStatement: VAR IDENTIFIER COLON IDENTIFIER; + +instruction: IDENTIFIER expressionList; + +expressionList: expression (COMMA expression)?; + +expression: + INTEGER_LITERAL + | FLOAT_LITERAL + | IDENTIFIER + | arrayElements; + +arrayElements: IDENTIFIER OPEN_BRACKET arrayIndex CLOSE_BRACKET; +arrayIndex: expression; + +/* +* Things we are leaving out at the moment: +* - Function calls. +* - Matrix literals, string literals. +* - Multiple variable declarations in the same line. +* - Operators: unary, binary, ternary. +* - Semicolons don't start a new statement. +* - Array elements cannot be neither a list of indices nor a range of indices. +*/ diff --git a/src/v3x/cqasm-parse-helper.cpp b/src/v3x/cqasm-parse-helper.cpp index 1766f158..ecbc12e7 100644 --- a/src/v3x/cqasm-parse-helper.cpp +++ b/src/v3x/cqasm-parse-helper.cpp @@ -2,9 +2,11 @@ * Implementation for \ref include/v3x/cqasm-parse-helper.hpp "v3x/cqasm-parse-helper.hpp". */ +#include "v1x/cqasm-ast.hpp" #include "v1x/cqasm-parse-result.hpp" -#include "v3x/cqasm_lexer.h" -#include "v3x/cqasm_parser.h" +#include "v3x/BuildTreeGenAstVisitor.h" +#include "v3x/CqasmLexer.h" +#include "v3x/CqasmParser.h" #include "v3x/cqasm-parse-helper.hpp" #include "antlr4-runtime/antlr4-runtime.h" @@ -25,12 +27,23 @@ ScannerAntlr::ScannerAntlr() {} ScannerAntlr::~ScannerAntlr() {} -void ScannerAntlr::parse_(const std::string & /* file_name */, cqasm::v1x::parser::ParseResult & /* result */, +void ScannerAntlr::parse_(const std::string & /* file_name */, cqasm::v1x::parser::ParseResult &result, antlr4::ANTLRInputStream &is) { - cqasm_lexer lexer{ &is }; + CqasmLexer lexer{ &is }; antlr4::CommonTokenStream tokens{ &lexer }; - cqasm_parser parser{ &tokens }; - // Transform parser.expr() into a ParseResult + CqasmParser parser{ &tokens }; + // v1x/cqasm-parse-helper.cpp, through cqasm-parser.y, passes a v1x/ParseHelper to the Flex/Bison code + // That v1x/ParseHelper includes both the parse result and the file name used for logging purposes + // The Flex/Bison code: + // 1) builds AST nodes along the parsing, and, in the end, + // 2) sets helper.result.root to the Program AST node. + // + // We have to do something similar here with ANTLR + // This parse_ function should fill the parse result as a side effect of the ANTLR parsing + // And, in case of logging any errors, use the file name + auto ast = parser.program(); + auto tree_gen_ast = BuildTreeGenAstVisitor{}.visitProgram(ast); + result.root = std::any_cast>(tree_gen_ast); } ScannerAntlrFile::ScannerAntlrFile(const std::string &file_path) diff --git a/src/v3x/cqasm_parser.g4 b/src/v3x/cqasm_parser.g4 deleted file mode 100644 index d641c41b..00000000 --- a/src/v3x/cqasm_parser.g4 +++ /dev/null @@ -1,41 +0,0 @@ -parser grammar cqasm_parser; - -options { - tokenVocab = cqasm_lexer; -} - -// Actual grammar start. -program: version statement*; - -version: VERSION INTEGER_LITERAL (DOT INTEGER_LITERAL)?; - -statement: qubits_statement | map_statement | var_statement | instruction; - -qubits_statement: QUBITS INTEGER_LITERAL; - -map_statement: MAP IDENTIFIER EQUAL expression; - -var_statement: VAR IDENTIFIER COLON IDENTIFIER; - -instruction: IDENTIFIER expression_list; - -expression_list: expression (COMMA expression)?; - -expression: - INTEGER_LITERAL - | FLOAT_LITERAL - | IDENTIFIER - | array_elements; - -array_elements: IDENTIFIER OPEN_BRACKET array_index CLOSE_BRACKET; -array_index: expression; - -/* -* Things we are leaving out at the moment: -* - Function calls. -* - Matrix literals, string literals. -* - Multiple variable declarations in the same line. -* - Operators: unary, binary, ternary. -* - Semicolons don't start a new statement. -* - Array elements cannot be neither a list of indices nor a range of indices. -*/ From c4f56128ed7fa7635b9cb2dd31edf91a06745630 Mon Sep 17 00:00:00 2001 From: rturrado Date: Thu, 14 Sep 2023 11:36:46 +0200 Subject: [PATCH 04/28] Amend of previous commit. --- src/v3x/BuildTreeGenAstVisitor.cpp | 85 ++++++++++++++++++++++++++++++ 1 file changed, 85 insertions(+) create mode 100644 src/v3x/BuildTreeGenAstVisitor.cpp diff --git a/src/v3x/BuildTreeGenAstVisitor.cpp b/src/v3x/BuildTreeGenAstVisitor.cpp new file mode 100644 index 00000000..e0fa8767 --- /dev/null +++ b/src/v3x/BuildTreeGenAstVisitor.cpp @@ -0,0 +1,85 @@ +#include "cqasm-error.hpp" +#include "v1x/cqasm-ast.hpp" +#include "v3x/BuildTreeGenAstVisitor.h" + +#include // from_chars +#include // runtime_error +#include // errc + + +namespace cqasm::v3x::parser { + +using namespace cqasm::v1x::ast; +using namespace cqasm::error; + +template +T get_terminal_node_value(antlr4::tree::TerminalNode *node) { + auto text = node->getText(); + T ret{}; + auto [ptr, ec] = std::from_chars(text.c_str(), text.c_str() + text.size(), ret); + if (ec == std::errc::invalid_argument) { + throw AnalysisError{ "terminal node is not of the expected type." }; + } else if (ec == std::errc::result_out_of_range) { + throw AnalysisError{ "terminal node is out of range" }; + } + return ret; +} + +std::any BuildTreeGenAstVisitor::visitProgram(CqasmParser::ProgramContext *context) { + auto ret = One{}; + + ret->version = std::any_cast>(visitVersion(context->version())); + + ret->num_qubits = std::any_cast>(visitExpression(context->expression())); + + for (size_t i{ 0 }; i < context->statement().size(); ++i) { + auto statement_ast = visitStatement(context->statement(i)); + ret->statements->items.add(std::any_cast>(statement_ast)); + } + + return ret; +} + +std::any BuildTreeGenAstVisitor::visitVersion(CqasmParser::VersionContext *context) { + auto ret = One{}; + + for (size_t i{ 0 }; i < context->INTEGER_LITERAL().size(); ++i) { + ret->items.push_back(get_terminal_node_value(context->INTEGER_LITERAL(i))); + } + + return ret; +} + +std::any BuildTreeGenAstVisitor::visitStatement(CqasmParser::StatementContext * /* context */) { + throw std::runtime_error{ "Unimplemented" }; +} + +std::any BuildTreeGenAstVisitor::visitMapStatement(CqasmParser::MapStatementContext * /* context */) { + throw std::runtime_error{ "Unimplemented" }; +} + +std::any BuildTreeGenAstVisitor::visitVarStatement(CqasmParser::VarStatementContext * /* context */) { + throw std::runtime_error{ "Unimplemented" }; +} + +std::any BuildTreeGenAstVisitor::visitInstruction(CqasmParser::InstructionContext * /* context */) { + throw std::runtime_error{ "Unimplemented" }; +} + +std::any BuildTreeGenAstVisitor::visitExpressionList(CqasmParser::ExpressionListContext * /* context */) { + throw std::runtime_error{ "Unimplemented" }; +} + +std::any BuildTreeGenAstVisitor::visitExpression(CqasmParser::ExpressionContext * /* context */) { + throw std::runtime_error{ "Unimplemented" }; +} + +std::any BuildTreeGenAstVisitor::visitArrayElements(CqasmParser::ArrayElementsContext * /* context */) { + throw std::runtime_error{ "Unimplemented" }; +} + +std::any BuildTreeGenAstVisitor::visitArrayIndex(CqasmParser::ArrayIndexContext * /* context */) { + throw std::runtime_error{ "Unimplemented" }; +} + +} // namespace cqasm::v3x::parser From 270a6a0484570c719118ed3396bb9e9ca7db3574 Mon Sep 17 00:00:00 2001 From: rturrado Date: Thu, 14 Sep 2023 17:43:16 +0200 Subject: [PATCH 05/28] Finished writing the builder visitor (ANTLR AST to tree-gen AST). Slightly changed the grammar to make look more like the v1x grammar. --- include/v3x/BuildTreeGenAstVisitor.h | 7 +-- src/v3x/BuildTreeGenAstVisitor.cpp | 88 ++++++++++++++++++++-------- src/v3x/CqasmParser.g4 | 11 ++-- 3 files changed, 71 insertions(+), 35 deletions(-) diff --git a/include/v3x/BuildTreeGenAstVisitor.h b/include/v3x/BuildTreeGenAstVisitor.h index 4c8f672f..ea57f532 100644 --- a/include/v3x/BuildTreeGenAstVisitor.h +++ b/include/v3x/BuildTreeGenAstVisitor.h @@ -14,13 +14,12 @@ class BuildTreeGenAstVisitor : public CqasmParserVisitor { std::any visitProgram(CqasmParser::ProgramContext *context) override; std::any visitVersion(CqasmParser::VersionContext *context) override; std::any visitStatement(CqasmParser::StatementContext *context) override; - std::any visitMapStatement(CqasmParser::MapStatementContext *context) override; - std::any visitVarStatement(CqasmParser::VarStatementContext *context) override; + std::any visitMapping(CqasmParser::MappingContext *context) override; + std::any visitVariable(CqasmParser::VariableContext *context) override; std::any visitInstruction(CqasmParser::InstructionContext *context) override; std::any visitExpressionList(CqasmParser::ExpressionListContext *context) override; std::any visitExpression(CqasmParser::ExpressionContext *context) override; - std::any visitArrayElements(CqasmParser::ArrayElementsContext *context) override; - std::any visitArrayIndex(CqasmParser::ArrayIndexContext *context) override; + std::any visitIndex(CqasmParser::IndexContext *context) override; }; } // namespace cqasm::v3x::parser diff --git a/src/v3x/BuildTreeGenAstVisitor.cpp b/src/v3x/BuildTreeGenAstVisitor.cpp index e0fa8767..2016385a 100644 --- a/src/v3x/BuildTreeGenAstVisitor.cpp +++ b/src/v3x/BuildTreeGenAstVisitor.cpp @@ -1,7 +1,9 @@ #include "cqasm-error.hpp" +#include "cqasm-tree.hpp" #include "v1x/cqasm-ast.hpp" #include "v3x/BuildTreeGenAstVisitor.h" +#include // assert #include // from_chars #include // runtime_error #include // errc @@ -27,59 +29,95 @@ T get_terminal_node_value(antlr4::tree::TerminalNode *node) { std::any BuildTreeGenAstVisitor::visitProgram(CqasmParser::ProgramContext *context) { auto ret = One{}; - ret->version = std::any_cast>(visitVersion(context->version())); - ret->num_qubits = std::any_cast>(visitExpression(context->expression())); - + ret->statements = cqasm::tree::make(); for (size_t i{ 0 }; i < context->statement().size(); ++i) { auto statement_ast = visitStatement(context->statement(i)); ret->statements->items.add(std::any_cast>(statement_ast)); } - return ret; } std::any BuildTreeGenAstVisitor::visitVersion(CqasmParser::VersionContext *context) { auto ret = One{}; - for (size_t i{ 0 }; i < context->INTEGER_LITERAL().size(); ++i) { - ret->items.push_back(get_terminal_node_value(context->INTEGER_LITERAL(i))); + auto number = get_terminal_node_value(context->INTEGER_LITERAL(i)); + ret->items.push_back(number); } - return ret; } -std::any BuildTreeGenAstVisitor::visitStatement(CqasmParser::StatementContext * /* context */) { - throw std::runtime_error{ "Unimplemented" }; -} - -std::any BuildTreeGenAstVisitor::visitMapStatement(CqasmParser::MapStatementContext * /* context */) { - throw std::runtime_error{ "Unimplemented" }; +std::any BuildTreeGenAstVisitor::visitStatement(CqasmParser::StatementContext *context) { + if (auto ast = context->mapping()) { + return cqasm::tree::make(std::any_cast(visitMapping(ast))); + } else if (auto ast = context->variable()) { + return cqasm::tree::make(std::any_cast(visitVariable(ast))); + } else if (auto ast = context->instruction()) { + return cqasm::tree::make(std::any_cast(visitInstruction(ast))); + } else { + throw AnalysisError{ "unknown statement type" }; + } } -std::any BuildTreeGenAstVisitor::visitVarStatement(CqasmParser::VarStatementContext * /* context */) { - throw std::runtime_error{ "Unimplemented" }; +std::any BuildTreeGenAstVisitor::visitMapping(CqasmParser::MappingContext *context) { + auto ret = Mapping{}; + ret.alias = cqasm::tree::make(context->IDENTIFIER()->getText()); + ret.expr = std::any_cast>(visitExpression(context->expression())); + return ret; } -std::any BuildTreeGenAstVisitor::visitInstruction(CqasmParser::InstructionContext * /* context */) { - throw std::runtime_error{ "Unimplemented" }; +std::any BuildTreeGenAstVisitor::visitVariable(CqasmParser::VariableContext *context) { + auto ret = Variables{}; + assert(context->IDENTIFIER().size() == 2); + ret.names.add(cqasm::tree::make(context->IDENTIFIER(0)->getText())); + ret.typ = cqasm::tree::make(context->IDENTIFIER(1)->getText()); + return ret; } -std::any BuildTreeGenAstVisitor::visitExpressionList(CqasmParser::ExpressionListContext * /* context */) { - throw std::runtime_error{ "Unimplemented" }; +std::any BuildTreeGenAstVisitor::visitInstruction(CqasmParser::InstructionContext *context) { + auto ret = Instruction{}; + ret.name = cqasm::tree::make(context->IDENTIFIER()->getText()); + auto expression_list_ast = visitExpressionList(context->expressionList()); + ret.operands = cqasm::tree::make(std::any_cast(expression_list_ast)); + return ret; } -std::any BuildTreeGenAstVisitor::visitExpression(CqasmParser::ExpressionContext * /* context */) { - throw std::runtime_error{ "Unimplemented" }; +std::any BuildTreeGenAstVisitor::visitExpressionList(CqasmParser::ExpressionListContext *context) { + auto ret = ExpressionList{}; + for (size_t i{ 0 }; i < context->expression().size(); ++i) { + auto expression_ast = visitExpression(context->expression(i)); + ret.items.add(std::any_cast>(expression_ast)); + } + return ret; } -std::any BuildTreeGenAstVisitor::visitArrayElements(CqasmParser::ArrayElementsContext * /* context */) { - throw std::runtime_error{ "Unimplemented" }; +std::any BuildTreeGenAstVisitor::visitExpression(CqasmParser::ExpressionContext *context) { + if (auto integer_literal_ast = context->INTEGER_LITERAL()) { + auto integer_literal = get_terminal_node_value(integer_literal_ast); + return cqasm::tree::make(integer_literal); + } else if (auto float_literal_ast = context->FLOAT_LITERAL()) { + auto float_literal = get_terminal_node_value(float_literal_ast); + return cqasm::tree::make(float_literal); + } else if (auto id_ast = context->IDENTIFIER()) { + auto id = id_ast->getText(); + return cqasm::tree::make(std::move(id)); + } else if (auto index_ast = context->index()) { + return cqasm::tree::make(std::any_cast(visitIndex(index_ast))); + } else { + throw AnalysisError{ "unknown expression type" }; + } } -std::any BuildTreeGenAstVisitor::visitArrayIndex(CqasmParser::ArrayIndexContext * /* context */) { - throw std::runtime_error{ "Unimplemented" }; +std::any BuildTreeGenAstVisitor::visitIndex(CqasmParser::IndexContext *context) { + auto ret = Index{}; + auto id = context->IDENTIFIER()->getText(); + ret.expr = cqasm::tree::make(std::move(id)); + ret.indices = cqasm::tree::make(); + auto expression_ast = visitExpression(context->expression()); + auto index_item = cqasm::tree::make(std::any_cast>(expression_ast)); + ret.indices->items.add(std::move(index_item)); + return ret; } } // namespace cqasm::v3x::parser diff --git a/src/v3x/CqasmParser.g4 b/src/v3x/CqasmParser.g4 index d30e919a..0078a70b 100644 --- a/src/v3x/CqasmParser.g4 +++ b/src/v3x/CqasmParser.g4 @@ -9,11 +9,11 @@ program: version QUBITS expression statement*; version: VERSION INTEGER_LITERAL (DOT INTEGER_LITERAL)?; -statement: mapStatement | varStatement | instruction; +statement: mapping | variable | instruction; -mapStatement: MAP IDENTIFIER EQUAL expression; +mapping: MAP IDENTIFIER EQUAL expression; -varStatement: VAR IDENTIFIER COLON IDENTIFIER; +variable: VAR IDENTIFIER COLON IDENTIFIER; instruction: IDENTIFIER expressionList; @@ -23,10 +23,9 @@ expression: INTEGER_LITERAL | FLOAT_LITERAL | IDENTIFIER - | arrayElements; + | index; -arrayElements: IDENTIFIER OPEN_BRACKET arrayIndex CLOSE_BRACKET; -arrayIndex: expression; +index: IDENTIFIER OPEN_BRACKET expression CLOSE_BRACKET; /* * Things we are leaving out at the moment: From 9b9614690630ad1140a7ee63c6f1b07f3a96a560 Mon Sep 17 00:00:00 2001 From: rturrado Date: Fri, 15 Sep 2023 12:43:28 +0200 Subject: [PATCH 06/28] Changed ScannerAntlr to have a build visitor as a dependency injection. --- include/v3x/BuildCustomAstVisitor.h | 24 +++++++++++++++++ include/v3x/BuildTreeGenAstVisitor.h | 4 +-- include/v3x/cqasm-parse-helper.hpp | 12 +++++---- src/v3x/cqasm-parse-helper.cpp | 39 ++++++++++++---------------- 4 files changed, 50 insertions(+), 29 deletions(-) create mode 100644 include/v3x/BuildCustomAstVisitor.h diff --git a/include/v3x/BuildCustomAstVisitor.h b/include/v3x/BuildCustomAstVisitor.h new file mode 100644 index 00000000..d31de02d --- /dev/null +++ b/include/v3x/BuildCustomAstVisitor.h @@ -0,0 +1,24 @@ +#pragma once + +#include "v3x/CqasmParser.h" +#include "v3x/CqasmParserVisitor.h" + +#include + + +namespace cqasm::v3x::parser { + +class BuildCustomAstVisitor : public CqasmParserVisitor { +public: + std::any visitProgram(CqasmParser::ProgramContext *context) = 0; + std::any visitVersion(CqasmParser::VersionContext *context) = 0; + std::any visitStatement(CqasmParser::StatementContext *context) = 0; + std::any visitMapping(CqasmParser::MappingContext *context) = 0; + std::any visitVariable(CqasmParser::VariableContext *context) = 0; + std::any visitInstruction(CqasmParser::InstructionContext *context) = 0; + std::any visitExpressionList(CqasmParser::ExpressionListContext *context) = 0; + std::any visitExpression(CqasmParser::ExpressionContext *context) = 0; + std::any visitIndex(CqasmParser::IndexContext *context) = 0; +}; + +} // namespace cqasm::v3x::parser diff --git a/include/v3x/BuildTreeGenAstVisitor.h b/include/v3x/BuildTreeGenAstVisitor.h index ea57f532..f9d9c833 100644 --- a/include/v3x/BuildTreeGenAstVisitor.h +++ b/include/v3x/BuildTreeGenAstVisitor.h @@ -1,6 +1,6 @@ #pragma once -#include "antlr4-runtime.h" +#include "v3x/BuildCustomAstVisitor.h" #include "v3x/CqasmParser.h" #include "v3x/CqasmParserVisitor.h" @@ -9,7 +9,7 @@ namespace cqasm::v3x::parser { -class BuildTreeGenAstVisitor : public CqasmParserVisitor { +class BuildTreeGenAstVisitor : public BuildCustomAstVisitor { public: std::any visitProgram(CqasmParser::ProgramContext *context) override; std::any visitVersion(CqasmParser::VersionContext *context) override; diff --git a/include/v3x/cqasm-parse-helper.hpp b/include/v3x/cqasm-parse-helper.hpp index 1e31ba26..7ecf4832 100644 --- a/include/v3x/cqasm-parse-helper.hpp +++ b/include/v3x/cqasm-parse-helper.hpp @@ -9,6 +9,8 @@ #include "cqasm-annotations.hpp" #include "v1x/cqasm-parse-result.hpp" #include "v3x/CqasmLexer.h" +#include "v3x/BuildCustomAstVisitor.h" +#include "v3x/BuildTreeGenAstVisitor.h" #include "antlr4-runtime/antlr4-runtime.h" @@ -31,11 +33,11 @@ struct ScannerAdaptor { }; class ScannerAntlr : public ScannerAdaptor { + std::unique_ptr build_visitor_up_; protected: - void parse_(const std::string & /* file_name */, cqasm::v1x::parser::ParseResult & /* result */, - antlr4::ANTLRInputStream &is); + void parse_(antlr4::ANTLRInputStream &is, const std::string &file_name, cqasm::v1x::parser::ParseResult &result); public: - ScannerAntlr(); + explicit ScannerAntlr(std::unique_ptr build_visitor_up); ~ScannerAntlr() override; void parse(const std::string &file_name, cqasm::v1x::parser::ParseResult &result) = 0; }; @@ -43,7 +45,7 @@ class ScannerAntlr : public ScannerAdaptor { class ScannerAntlrFile : public ScannerAntlr { std::ifstream ifs_; public: - explicit ScannerAntlrFile(const std::string &file_path); + ScannerAntlrFile(std::unique_ptr build_visitor_up, const std::string &file_path); ~ScannerAntlrFile() override; void parse(const std::string &file_name, cqasm::v1x::parser::ParseResult &result) override; }; @@ -51,7 +53,7 @@ class ScannerAntlrFile : public ScannerAntlr { class ScannerAntlrString : public ScannerAntlr { std::string data_; public: - explicit ScannerAntlrString(const std::string &data); + ScannerAntlrString(std::unique_ptr build_visitor_up, const std::string &data); ~ScannerAntlrString() override; void parse(const std::string &file_name, cqasm::v1x::parser::ParseResult &result) override; }; diff --git a/src/v3x/cqasm-parse-helper.cpp b/src/v3x/cqasm-parse-helper.cpp index ecbc12e7..ee19cff0 100644 --- a/src/v3x/cqasm-parse-helper.cpp +++ b/src/v3x/cqasm-parse-helper.cpp @@ -23,31 +23,24 @@ namespace cqasm { namespace v3x { namespace parser { -ScannerAntlr::ScannerAntlr() {} +ScannerAntlr::ScannerAntlr(std::unique_ptr build_visitor_up) +: build_visitor_up_{ std::move(build_visitor_up) } {} ScannerAntlr::~ScannerAntlr() {} -void ScannerAntlr::parse_(const std::string & /* file_name */, cqasm::v1x::parser::ParseResult &result, - antlr4::ANTLRInputStream &is) { +void ScannerAntlr::parse_(antlr4::ANTLRInputStream &is, const std::string & /* file_name */, + cqasm::v1x::parser::ParseResult &result) { + CqasmLexer lexer{ &is }; antlr4::CommonTokenStream tokens{ &lexer }; CqasmParser parser{ &tokens }; - // v1x/cqasm-parse-helper.cpp, through cqasm-parser.y, passes a v1x/ParseHelper to the Flex/Bison code - // That v1x/ParseHelper includes both the parse result and the file name used for logging purposes - // The Flex/Bison code: - // 1) builds AST nodes along the parsing, and, in the end, - // 2) sets helper.result.root to the Program AST node. - // - // We have to do something similar here with ANTLR - // This parse_ function should fill the parse result as a side effect of the ANTLR parsing - // And, in case of logging any errors, use the file name auto ast = parser.program(); - auto tree_gen_ast = BuildTreeGenAstVisitor{}.visitProgram(ast); - result.root = std::any_cast>(tree_gen_ast); + auto custom_ast = build_visitor_up_->visitProgram(ast); + result.root = std::any_cast>(custom_ast); } -ScannerAntlrFile::ScannerAntlrFile(const std::string &file_path) -: ifs_{ file_path } { +ScannerAntlrFile::ScannerAntlrFile(std::unique_ptr build_visitor_up, const std::string &file_path) +: ScannerAntlr{ std::move(build_visitor_up) }, ifs_{ file_path } { if (!ifs_.is_open()) { throw error::AnalysisError("ScannerAntlrFile couldn't access file."); } @@ -55,15 +48,15 @@ ScannerAntlrFile::ScannerAntlrFile(const std::string &file_path) void ScannerAntlrFile::parse(const std::string &file_name, cqasm::v1x::parser::ParseResult &result) { antlr4::ANTLRInputStream is{ ifs_ }; - parse_(file_name, result, is); + parse_(is, file_name, result); } -ScannerAntlrString::ScannerAntlrString(const std::string &data) -: data_{ data } {} +ScannerAntlrString::ScannerAntlrString(std::unique_ptr build_visitor_up, const std::string &data) +: ScannerAntlr{ std::move(build_visitor_up) }, data_{ data } {} void ScannerAntlrString::parse(const std::string &file_name, cqasm::v1x::parser::ParseResult &result) { antlr4::ANTLRInputStream is{ data_ }; - parse_(file_name, result, is); + parse_(is, file_name, result); } /** @@ -72,7 +65,8 @@ void ScannerAntlrString::parse(const std::string &file_name, cqasm::v1x::parser: * A file_name may be given in addition for use within error messages. */ cqasm::v1x::parser::ParseResult parse_file(const std::string &file_path, const std::string &file_name) { - auto scanner_up = std::make_unique(file_path); + auto builder_visitor_up = std::make_unique(); + auto scanner_up = std::make_unique(std::move(builder_visitor_up), file_path); return ParseHelper(std::move(scanner_up), file_name).parse(); } @@ -81,7 +75,8 @@ cqasm::v1x::parser::ParseResult parse_file(const std::string &file_path, const s * A file_name may be given in addition for use within error messages. */ cqasm::v1x::parser::ParseResult parse_string(const std::string &data, const std::string &file_name) { - auto scanner_up = std::make_unique(data); + auto builder_visitor_up = std::make_unique(); + auto scanner_up = std::make_unique(std::move(builder_visitor_up), data); return ParseHelper(std::move(scanner_up), file_name).parse(); } From acb42c5fefa5b5510f7c983e2849b55434741799 Mon Sep 17 00:00:00 2001 From: rturrado Date: Sat, 16 Sep 2023 03:08:48 +0200 Subject: [PATCH 07/28] Changed test/v1x/parsing.cpp to accommodate toy v1x tests. - If the input file has 3.0 version, we parse it through the ANTLR parser. Also took the opportunity to refactor test/v1x/parsing.cpp. - Removed dirent.h dependency. Used std::filesystem instead. Updated src/CMakeLists.txt to a tree-gen/v3 version that supports printing of nodes via fmt. - TODO: merge those tree-gen changes into master. Added an empty test/v3x/cqasm-parse-helper.cpp. --- include/cqasm-version.hpp | 13 +- include/v3x/cqasm-parse-helper.hpp | 3 +- res/v3x/{toy-v1 => }/test_cases.txt | 4 +- src/CMakeLists.txt | 11 +- src/cqasm-version.cpp | 7 + src/v3x/cqasm-parse-helper.cpp | 14 +- test/CMakeLists.txt | 1 + test/cqasm-version.cpp | 49 +++-- test/main.cpp | 2 +- test/v1x/parsing.cpp | 269 ++++++++++++++-------------- test/v1x/parsing.hpp | 2 +- test/v3x/CMakeLists.txt | 3 + test/v3x/cqasm-parse-helper.cpp | 12 ++ 13 files changed, 204 insertions(+), 186 deletions(-) rename res/v3x/{toy-v1 => }/test_cases.txt (95%) create mode 100644 test/v3x/CMakeLists.txt create mode 100644 test/v3x/cqasm-parse-helper.cpp diff --git a/include/cqasm-version.hpp b/include/cqasm-version.hpp index 2888fe22..0d6c86fc 100644 --- a/include/cqasm-version.hpp +++ b/include/cqasm-version.hpp @@ -8,6 +8,7 @@ #include // int64_t #include // FILE* +#include #include // unique_ptr #include #include @@ -61,7 +62,7 @@ std::ostream &operator<<(std::ostream &os, const Version &object); struct ScannerAdaptor { - virtual ~ScannerAdaptor() = default; + virtual ~ScannerAdaptor(); virtual void parse(const std::string &file_name, Version &version) const = 0; }; @@ -82,7 +83,7 @@ class ScannerFlexBisonFile : public ScannerFlexBison { FILE *fp_{ nullptr }; public: explicit ScannerFlexBisonFile(FILE *fp); - ~ScannerFlexBisonFile() override = default; + ~ScannerFlexBisonFile() override; void parse(const std::string &file_name, Version &version) const override; }; @@ -91,7 +92,7 @@ class ScannerFlexBisonString : public ScannerFlexBison { const char *data_{ nullptr }; public: explicit ScannerFlexBisonString(const char *data); - ~ScannerFlexBisonString() override = default; + ~ScannerFlexBisonString() override; void parse(const std::string &file_name, Version &version) const override; }; @@ -139,5 +140,9 @@ class ParseHelper { Version parse(); }; - } // namespace cqasm::version + +/** + * std::ostream support via fmt (uses operator<<). + */ +template <> struct fmt::formatter : ostream_formatter {}; diff --git a/include/v3x/cqasm-parse-helper.hpp b/include/v3x/cqasm-parse-helper.hpp index 7ecf4832..8bcfed28 100644 --- a/include/v3x/cqasm-parse-helper.hpp +++ b/include/v3x/cqasm-parse-helper.hpp @@ -8,7 +8,6 @@ #include "cqasm-annotations.hpp" #include "v1x/cqasm-parse-result.hpp" -#include "v3x/CqasmLexer.h" #include "v3x/BuildCustomAstVisitor.h" #include "v3x/BuildTreeGenAstVisitor.h" @@ -27,7 +26,7 @@ using SourceLocation = annotations::SourceLocation; struct ScannerAdaptor { - virtual ~ScannerAdaptor() = default; + virtual ~ScannerAdaptor(); virtual void parse(const std::string &file_name, cqasm::v1x::parser::ParseResult &result) = 0; }; diff --git a/res/v3x/toy-v1/test_cases.txt b/res/v3x/test_cases.txt similarity index 95% rename from res/v3x/toy-v1/test_cases.txt rename to res/v3x/test_cases.txt index 7cfcde22..a6bbf332 100644 --- a/res/v3x/toy-v1/test_cases.txt +++ b/res/v3x/test_cases.txt @@ -3,7 +3,7 @@ fail something before version blah; version 3 fail version without number version fail bad version version blah -fail version not supported version 1.2 +fail version not supported version 1.2 Syntactically correct, not semantically OK OK version, no newline version 3 OK OK version, semicolon version 3; OK OK version, newline version 3\n @@ -25,7 +25,7 @@ fail bad map array, out of bounds qubit version 3;qubits 3;map v = q[3] OK OK map array version 3;qubits 3;map v = q[0] fail empty var version 3;var -fail empty var id version 3;var v +fail empty var id version 3;var v fail empty var id : version 3;var v = fail bad var id version 3;var w : v Syntactically correct, not semantically OK OK var id version 3;map v : 1;var w : v diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 8e17651b..f6d29fc1 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -33,7 +33,7 @@ include(FetchContent) # This exposes the generate_tree() function. FetchContent_Declare(tree-gen GIT_REPOSITORY https://github.com/QuTech-Delft/tree-gen.git - GIT_TAG "d708ea629bad014011d3f1efc352077414dd86f7" + GIT_TAG "8a1f25dee6d5529398676ec83a18f89786049ae8" ) FetchContent_MakeAvailable(tree-gen) @@ -53,7 +53,6 @@ else() endif() find_package(antlr4-runtime REQUIRED) -find_package(fmt REQUIRED) find_package(Python3 REQUIRED) #------------------------------------------------------------------------------- @@ -211,20 +210,16 @@ target_compile_definitions(cqasm-lib-obj PRIVATE ${TREE_LIB_PRIVATE_DEFS} ) -# The src directory and binary directory (for generated header files) are private. -# The include directory is public. -# That is, the files in include must not try to include generated files and files from the src directory, -# but the other direction is fine. target_include_directories(cqasm-lib-obj PRIVATE ${TREE_LIB_PRIVATE_INCLUDE} PUBLIC ${TREE_LIB_PUBLIC_INCLUDE} # Do not remove the ending '/' since # it avoids the whole 'include' directory to be copied to the installation folder. # Instead, just its contents are copied. - PRIVATE "${CMAKE_CURRENT_BINARY_DIR}/" + PUBLIC "${CMAKE_CURRENT_BINARY_DIR}/" PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/../include/" PUBLIC "${CMAKE_CURRENT_BINARY_DIR}/../include/" - PUBLIC "${antlr4-runtime_INCLUDE_DIR}" + PRIVATE "${antlr4-runtime_INCLUDE_DIR}" ) target_compile_features(cqasm-lib-obj PUBLIC diff --git a/src/cqasm-version.cpp b/src/cqasm-version.cpp index 16943557..d1e3933a 100644 --- a/src/cqasm-version.cpp +++ b/src/cqasm-version.cpp @@ -87,6 +87,9 @@ std::ostream &operator<<(std::ostream &os, const Version &object) { } +ScannerAdaptor::~ScannerAdaptor() {} + + ScannerFlexBison::ScannerFlexBison() { int result = cqasm_version_lex_init(static_cast(&scanner_)); if (result != 0) { @@ -119,6 +122,8 @@ ScannerFlexBisonFile::ScannerFlexBisonFile(FILE *fp } } +ScannerFlexBisonFile::~ScannerFlexBisonFile() {} + void ScannerFlexBisonFile::parse(const std::string &file_name, Version &version) const { cqasm_version_set_in(fp_, static_cast(scanner_)); parse_(file_name, version); @@ -128,6 +133,8 @@ void ScannerFlexBisonFile::parse(const std::string &file_name, Version &version) ScannerFlexBisonString::ScannerFlexBisonString(const char *data ) : data_{ data } {} +ScannerFlexBisonString::~ScannerFlexBisonString() {} + void ScannerFlexBisonString::parse(const std::string &file_name, Version &version) const { auto buffer = cqasm_version__scan_string(data_, static_cast(scanner_)); if (!buffer) { diff --git a/src/v3x/cqasm-parse-helper.cpp b/src/v3x/cqasm-parse-helper.cpp index ee19cff0..e3d26953 100644 --- a/src/v3x/cqasm-parse-helper.cpp +++ b/src/v3x/cqasm-parse-helper.cpp @@ -19,9 +19,9 @@ namespace fs = std::filesystem; -namespace cqasm { -namespace v3x { -namespace parser { +namespace cqasm::v3x::parser { + +ScannerAdaptor::~ScannerAdaptor() {} ScannerAntlr::ScannerAntlr(std::unique_ptr build_visitor_up) : build_visitor_up_{ std::move(build_visitor_up) } {} @@ -46,6 +46,8 @@ ScannerAntlrFile::ScannerAntlrFile(std::unique_ptr build_ } } +ScannerAntlrFile::~ScannerAntlrFile() {} + void ScannerAntlrFile::parse(const std::string &file_name, cqasm::v1x::parser::ParseResult &result) { antlr4::ANTLRInputStream is{ ifs_ }; parse_(is, file_name, result); @@ -54,6 +56,8 @@ void ScannerAntlrFile::parse(const std::string &file_name, cqasm::v1x::parser::P ScannerAntlrString::ScannerAntlrString(std::unique_ptr build_visitor_up, const std::string &data) : ScannerAntlr{ std::move(build_visitor_up) }, data_{ data } {} +ScannerAntlrString::~ScannerAntlrString() {} + void ScannerAntlrString::parse(const std::string &file_name, cqasm::v1x::parser::ParseResult &result) { antlr4::ANTLRInputStream is{ data_ }; parse_(is, file_name, result); @@ -98,6 +102,4 @@ cqasm::v1x::parser::ParseResult ParseHelper::parse() { return result; } -} // namespace parser -} // namespace v3x -} // namespace cqasm +} // namespace cqasm::v3x::parser diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 6778a555..907d53ca 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -8,6 +8,7 @@ if(LIBQASM_COMPAT) add_subdirectory(v10) endif() add_subdirectory(v1x) +add_subdirectory(v3x) # Sources target_sources(${PROJECT_NAME}_test PRIVATE diff --git a/test/cqasm-version.cpp b/test/cqasm-version.cpp index 83cfe5a3..f97e3efd 100644 --- a/test/cqasm-version.cpp +++ b/test/cqasm-version.cpp @@ -4,6 +4,7 @@ #include #include #include +#include using namespace ::testing; using namespace cqasm::error; @@ -171,71 +172,71 @@ TEST(parse_file, fp_empty_and_no_filename_argument) { TEST(parse_string, string_empty) { - const char *filename{ "res/cqasm_version/empty.cq" }; + const std::string filename{ "res/cqasm_version/empty.cq" }; EXPECT_THROW(parse_string("", filename), AnalysisError); } TEST(parse_string, string_version_no_number) { - const char *filename{ "res/cqasm_version/version_no_number.cq" }; + const std::string filename{ "res/cqasm_version/version_no_number.cq" }; EXPECT_THROW(parse_string("version", filename), AnalysisError); } TEST(parse_string, string_version_abc) { - const char *filename{ "res/cqasm_version/version_abc.cq" }; + const std::string filename{ "res/cqasm_version/version_abc.cq" }; EXPECT_THROW(parse_string("version abc", filename), AnalysisError); } TEST(parse_string, string_version_1_abc) { - const char *filename{ "res/cqasm_version/version_1_abc.cq" }; + const std::string filename{ "res/cqasm_version/version_1_abc.cq" }; EXPECT_THROW(parse_string("version 1.abc", filename), AnalysisError); } TEST(parse_string, string_version_1_1_abc) { - const char *filename{ "res/cqasm_version/version_1_1_abc.cq" }; + const std::string filename{ "res/cqasm_version/version_1_1_abc.cq" }; EXPECT_THROW(parse_string("version 1.1.abc", filename), AnalysisError); } TEST(parse_string, string_version_1_0) { - const char *filename{ "res/cqasm_version/version_1_0.cq" }; + const std::string filename{ "res/cqasm_version/version_1_0.cq" }; EXPECT_EQ(parse_string("version 1.0", filename), Version{ "1.0" }); } TEST(parse_string, string_version_1_1) { - const char *filename{ "res/cqasm_version/version_1_1.cq" }; + const std::string filename{ "res/cqasm_version/version_1_1.cq" }; EXPECT_EQ(parse_string("version 1.1", filename), Version{ "1.1" }); } TEST(parse_string, string_version_1_1_1) { - const char *filename{ "res/cqasm_version/version_1_1_1.cq" }; + const std::string filename{ "res/cqasm_version/version_1_1_1.cq" }; EXPECT_EQ(parse_string("version 1.1.1", filename), Version{ "1.1.1" }); } TEST(parse_string, string_version_1_2) { - const char *filename{ "res/cqasm_version/version_1_2.cq" }; + const std::string filename{ "res/cqasm_version/version_1_2.cq" }; EXPECT_EQ(parse_string("version 1.2", filename), Version{ "1.2" }); } TEST(parse_string, string_version_1_3) { - const char *filename{ "res/cqasm_version/version_1_3.cq" }; + const std::string filename{ "res/cqasm_version/version_1_3.cq" }; EXPECT_EQ(parse_string("version 1.3", filename), Version{ "1.3" }); } TEST(parse_string, string_version_2_0) { - const char *filename{ "res/cqasm_version/version_2_0.cq" }; + const std::string filename{ "res/cqasm_version/version_2_0.cq" }; EXPECT_EQ(parse_string("version 2.0", filename), Version{ "2.0" }); } TEST(parse_string, string_version_3_0) { - const char *filename{ "res/cqasm_version/version_3_0.cq" }; + const std::string filename{ "res/cqasm_version/version_3_0.cq" }; EXPECT_EQ(parse_string("version 3.0", filename), Version{ "3.0" }); } TEST(parse_string, string_version_4_0) { - const char *filename{ "res/cqasm_version/version_4_0.cq" }; + const std::string filename{ "res/cqasm_version/version_4_0.cq" }; EXPECT_EQ(parse_string("version 4.0", filename), Version{ "4.0" }); } TEST(parse_string, string_instruction_called_version) { - const char *filename{ "res/cqasm_version/instruction_called_version.cq" }; + const std::string filename{ "res/cqasm_version/instruction_called_version.cq" }; EXPECT_THROW(parse_string("version q[1:6], 3.14159\nmeasure_all", filename), AnalysisError); } TEST(parse_string, string_no_version_and_instruction) { - const char *filename{ "res/cqasm_version/no_version_and_instruction.cq" }; + const std::string filename{ "res/cqasm_version/no_version_and_instruction.cq" }; EXPECT_THROW(parse_string("qubits 3\n\nx q[0]", filename), AnalysisError); } TEST(parse_string, string_version_1_0_and_instruction) { - const char *filename{ "res/cqasm_version/version_1_0_and_instruction.cq" }; + const std::string filename{ "res/cqasm_version/version_1_0_and_instruction.cq" }; EXPECT_EQ(parse_string("version 1.0\n\nqubits 3\n\nx q[0]", filename), Version{ "1.0" }); } TEST(parse_string, string_instruction_and_version_1_0) { - const char *filename{ "res/cqasm_version/instruction_and_version_1_0.cq" }; + const std::string filename{ "res/cqasm_version/instruction_and_version_1_0.cq" }; EXPECT_THROW(parse_string("qubits 3\n\nx q[0]\n\nversion 1.0", filename), AnalysisError); } TEST(parse_string, string_version_1_0_and_no_filename_argument) { @@ -282,11 +283,8 @@ TEST(ParseHelper_parse, scanner_returns_empty_version) { const std::string filename = "file_no_version.cq"; Version ret; EXPECT_CALL(scanner, parse(filename, _)).WillOnce(SetArgReferee<1>(ret)); - try { - ParseHelper(std::move(scanner_up), filename).parse(); - } catch (const AnalysisError &err) { - EXPECT_THAT(err.get_message(), HasSubstr("no version info nor error info was returned by version parser.")); - } + EXPECT_THAT([&]() { ParseHelper(std::move(scanner_up), filename).parse(); }, + ThrowsMessage(HasSubstr("no version info nor error info was returned by version parser."))); } TEST(ParseHelper_parse, scanner_returns_correct_version) { auto scanner_up = std::make_unique(); @@ -298,9 +296,6 @@ TEST(ParseHelper_parse, scanner_returns_correct_version) { } TEST(ParseHelper_parse, scanner_throws_and_no_filename_argument) { auto scanner_up = std::make_unique(""); - try { - ParseHelper(std::move(scanner_up)).parse(); - } catch (const AnalysisError &err) { - EXPECT_THAT(err.get_message(), HasSubstr("")); - } + EXPECT_THAT([&]() { ParseHelper(std::move(scanner_up)).parse(); }, + ThrowsMessage(HasSubstr(""))); } diff --git a/test/main.cpp b/test/main.cpp index 403a5dbc..7d2605d2 100644 --- a/test/main.cpp +++ b/test/main.cpp @@ -6,7 +6,7 @@ int main_impl(int argc, char** argv, std::ostream&) { ::testing::InitGoogleMock(&argc, argv); - register_v1x_parsing_tests(); + register_v1x_tests(); return RUN_ALL_TESTS(); } diff --git a/test/v1x/parsing.cpp b/test/v1x/parsing.cpp index 771594b8..de7ad53d 100644 --- a/test/v1x/parsing.cpp +++ b/test/v1x/parsing.cpp @@ -1,37 +1,46 @@ -#include "dirent-compat.h" #include "parsing.hpp" #include "v1x/cqasm.hpp" +#include "v1x/cqasm-parse-helper.hpp" +#include "v3x/cqasm.hpp" +#include "v3x/cqasm-parse-helper.hpp" +#include +#include +#include #include -#include // googletest header file +#include #include #include #include + namespace cq1x = cqasm::v1x; +namespace cq3x = cqasm::v3x; +namespace fs = std::filesystem; + /** * Reads the given file into the given string buffer and returns true if it * exists, otherwise do nothing with the buffer and return false. */ -bool read_file(const std::string &filename, std::string &output) { - std::ifstream stream(filename); - if (!stream.is_open()) { +bool read_file(const fs::path &file_path, std::string &output) { + std::ifstream ifs(file_path); + if (!ifs.is_open()) { return false; } output.clear(); - stream.seekg(0, std::ios::end); - output.reserve(stream.tellg()); - stream.seekg(0, std::ios::beg); - output.assign(std::istreambuf_iterator(stream), std::istreambuf_iterator()); + ifs.seekg(0, std::ios::end); + output.reserve(ifs.tellg()); + ifs.seekg(0, std::ios::beg); + output.assign(std::istreambuf_iterator(ifs), std::istreambuf_iterator()); return true; } /** * Overwrites or creates the given file with the given string. */ -void write_file(const std::string &filename, const std::string &input) { - std::ofstream stream(filename, std::ios::binary | std::ios::out); // always write LF, i.e., avoid CR+LF in Windows +void write_file(const fs::path &file_path, const std::string &input) { + std::ofstream stream(file_path, std::ios::binary | std::ios::out); // always write LF, i.e., avoid CR+LF in Windows stream << input; } @@ -41,54 +50,51 @@ void write_file(const std::string &filename, const std::string &input) { */ class ParsingTest : public ::testing::Test { private: - std::string path; + fs::path path_{}; public: - explicit ParsingTest(const std::string &path) : path(path) {} + explicit ParsingTest(fs::path path) : path_{ std::move(path) } {} void TestBody() override { - // Parse the test input file. - std::string input; - ASSERT_TRUE(read_file(path + "/input.cq", input)); - cq1x::parser::ParseResult parse_result; + std::string input{}; + ASSERT_TRUE(read_file(path_ / "input.cq", input)); + cq1x::parser::ParseResult parse_result{}; auto version = cqasm::version::parse_string(input, "input.cq"); - if (version > cqasm::version::Version("1.2")) { - std::ostringstream ss; - ss << "detected version " << version; - parse_result.errors.push_back(ss.str()); - } else { + + if (version <= cqasm::version::Version("1.2")) { parse_result = cq1x::parser::parse_string(input, "input.cq"); + } else if (version == cqasm::version::Version("3.0")) { + parse_result = cq3x::parser::parse_string(input, "input.cq"); + } else { + parse_result.errors.push_back(fmt::format("detected version ", version)); } - // Check the parse result. - std::ostringstream ss; + // Check the parse result + std::string ast_actual_file_contents{}; if (parse_result.errors.empty()) { - ss << "SUCCESS" << std::endl; - ss << *parse_result.root << std::endl; + ast_actual_file_contents = fmt::format("SUCCESS\n{}\n", *parse_result.root); } else { - ss << "ERROR" << std::endl; - for (const auto &error : parse_result.errors) { - ss << error << std::endl; - } + ast_actual_file_contents = fmt::format("ERROR\n{}", fmt::join(parse_result.errors, "\n")); } - std::string ast_result = ss.str(); - write_file(path + "/ast.actual.txt", ast_result); - std::string ast_golden; - EXPECT_TRUE(read_file(path + "/ast.golden.txt", ast_golden)); - EXPECT_TRUE(ast_result == ast_golden); - // Stop if parsing failed. + auto ast_actual_file_path = path_ / "ast.actual.txt"; + write_file(ast_actual_file_path, ast_actual_file_contents); + std::string ast_golden_file_contents{}; + auto ast_golden_file_path = path_ / "ast.golden.txt"; + EXPECT_TRUE(read_file(ast_golden_file_path, ast_golden_file_contents)); + EXPECT_TRUE(ast_actual_file_contents == ast_golden_file_contents); + + // Stop if parsing failed if (!parse_result.errors.empty()) { return; } - // Try different API levels. + // Try different API levels for (const auto &api_version : std::vector({"1.0", "1.1", "1.2"})) { - - // If there were no errors, try semantic analysis. We analyze using the - // functions, error models, and instruction set available in the - // compatibility layer, though this is copy-pasted in here. + // If there were no errors, try semantic analysis. + // We analyze using the functions, error models, and instruction set available in the compatibility layer, + // though this is copy-pasted in here auto analyzer = cq1x::analyzer::Analyzer{api_version}; analyzer.register_default_functions_and_mappings(); std::ostringstream args; @@ -143,136 +149,129 @@ class ParsingTest : public ::testing::Test { // Add a dynamic function in order to test the behavior of dynamic function nodes. if (api_version != "1.0") { - analyzer.register_function("or", "bb", [](const cq1x::values::Values &v) -> cq1x::values::Value { - auto lhs = v[0]; - auto rhs = v[1]; - if (auto lhs_const = lhs->as_const_bool()) { - if (lhs_const->value) { - return cqasm::tree::make(true); - } else { - return rhs; + analyzer.register_function("or", "bb", + [](const cq1x::values::Values &v) -> cq1x::values::Value { + auto lhs = v[0]; + auto rhs = v[1]; + if (auto lhs_const = lhs->as_const_bool()) { + if (lhs_const->value) { + return cqasm::tree::make(true); + } else { + return rhs; + } } - } - if (auto rhs_const = lhs->as_const_bool()) { - if (rhs_const->value) { - return cqasm::tree::make(true); - } else { - return lhs; + if (auto rhs_const = lhs->as_const_bool()) { + if (rhs_const->value) { + return cqasm::tree::make(true); + } else { + return lhs; + } } + return cqasm::tree::make( + "operator||", v, cqasm::tree::make()); } - return cqasm::tree::make("operator||", v, cqasm::tree::make()); - }); - analyzer.register_function("operator<", "ii", [](const cq1x::values::Values &v) -> cq1x::values::Value { - const auto& lhs = v[0]; - const auto& rhs = v[1]; - if (auto lhs_const = lhs->as_const_int()) { - if (auto rhs_const = rhs->as_const_int()) { - return cqasm::tree::make( - lhs_const->value < rhs_const->value - ); + ); + analyzer.register_function("operator<", "ii", + [](const cq1x::values::Values &v) -> cq1x::values::Value { + const auto& lhs = v[0]; + const auto& rhs = v[1]; + if (auto lhs_const = lhs->as_const_int()) { + if (auto rhs_const = rhs->as_const_int()) { + return cqasm::tree::make( + lhs_const->value < rhs_const->value + ); + } } + return cqasm::tree::make( + "operator<", v, cqasm::tree::make()); } - return cqasm::tree::make("operator<", v, cqasm::tree::make()); - }); - analyzer.register_function("operator+", "ii", [](const cq1x::values::Values &v) -> cq1x::values::Value { - const auto& lhs = v[0]; - const auto& rhs = v[1]; - if (auto lhs_const = lhs->as_const_int()) { - if (auto rhs_const = rhs->as_const_int()) { - return cqasm::tree::make( - lhs_const->value + rhs_const->value - ); + ); + analyzer.register_function("operator+", "ii", + [](const cq1x::values::Values &v) -> cq1x::values::Value { + const auto& lhs = v[0]; + const auto& rhs = v[1]; + if (auto lhs_const = lhs->as_const_int()) { + if (auto rhs_const = rhs->as_const_int()) { + return cqasm::tree::make( + lhs_const->value + rhs_const->value + ); + } } + return cqasm::tree::make( + "operator+", v, cqasm::tree::make()); } - return cqasm::tree::make("operator+", v, cqasm::tree::make()); - }); + ); } - // Run the actual semantic analysis. + // Run the actual semantic analysis auto analysis_result = analyzer.analyze(*parse_result.root->as_program()); - // Check the analysis results. - ss.str(""); + // Check the analysis results + std::string semantic_actual_file_contents{}; if (analysis_result.errors.empty()) { - ss << "SUCCESS" << std::endl; - ss << *analysis_result.root << std::endl; + semantic_actual_file_contents = fmt::format("SUCCESS\n{}\n", *analysis_result.root); } else { - ss << "ERROR" << std::endl; - for (const auto &error : analysis_result.errors) { - ss << error << std::endl; - } + semantic_actual_file_contents = fmt::format("ERROR\n{}\n", fmt::join(analysis_result.errors, "\n")); } - std::string semantic_result = ss.str(); - write_file(path + "/semantic." + api_version + ".actual.txt", semantic_result); - std::string semantic_golden; - EXPECT_TRUE(read_file(path + "/semantic." + api_version + ".golden.txt", semantic_golden)); - EXPECT_TRUE(semantic_result == semantic_golden); + auto semantic_actual_file_path = path_ / fmt::format("semantic.{}.actual.txt", api_version); + write_file(path_ / std::move(semantic_actual_file_path), semantic_actual_file_contents); + std::string semantic_golden_file_contents{}; + auto semantic_golden_file_path = path_ / fmt::format("semantic.{}.golden.txt", api_version); + EXPECT_TRUE(read_file(semantic_golden_file_path, semantic_golden_file_contents)); + EXPECT_TRUE(semantic_actual_file_contents == semantic_golden_file_contents); if (analysis_result.errors.empty()) { ::tree::base::serialize(analysis_result.root); } - } - } - }; -void register_v1x_parsing_tests() { - - // Discover the tests. They should live in a directory tree with the - // following structure: +void register_v1x_tests(const fs::path& subdir) { + // Discover the tests. + // They should live in a directory tree with the following structure: // // - // |- res/v1x/parsing + // |- res/v1x/ // |- test suite directory // | |- test case directory // | | |- input.cq the input file // | | |- ast.golden the golden AST or parse error dump // | | |- [ast.actual.txt] output file with the actual data - // | | |- [semantic.golden.txt] the golden semantic tree or - // | | | analysis error dump, if parsing - // | | | should succeed - // | | '- [semantic.actual.txt] output file with the actual data, - // | | if parsing actually succeeded + // | | |- [semantic.golden.txt] the golden semantic tree or analysis error dump, + // | | | if parsing should succeed + // | | '- [semantic.actual.txt] output file with the actual data, if parsing actually succeeded // | |- ... other test case directories // | : // |- ... other test suite directories // : - DIR *parsing_dir = opendir("res/v1x/parsing"); - if (!parsing_dir) { - throw std::runtime_error("failed to open dir for parsing tests"); + auto subdir_path = fs::path{ "res" } / "v1x" / subdir; + if (!fs::exists(subdir_path)) { + throw std::runtime_error(fmt::format("failed to open v1x tests subdir '{}'", subdir_path.generic_string())); + } else if (!fs::is_directory(subdir_path)) { + throw std::runtime_error(fmt::format("'{}' is not a directory", subdir_path.generic_string())); } - while (dirent *parsing_dir_ent = readdir(parsing_dir)) { - if (parsing_dir_ent->d_name[0] == '.') { - continue; - } - auto suite_name = std::string(parsing_dir_ent->d_name); - auto suite_path = "res/v1x/parsing/" + suite_name; - DIR *suite_dir = opendir(suite_path.c_str()); - if (!suite_dir) { - continue; - } - while (dirent *suite_dir_ent = readdir(suite_dir)) { - if (suite_dir_ent->d_name[0] == '.') { - continue; - } - auto test_name = std::string(suite_dir_ent->d_name); - auto test_path = suite_path + "/"; - test_path += test_name; - { - std::ifstream stream(test_path + "/input.cq"); - if (!stream.is_open()) { - continue; + for (const fs::directory_entry& suite: fs::directory_iterator(subdir_path)) { + if (fs::is_directory(suite)) { + auto suite_name = suite.path().filename(); + for (const fs::directory_entry& test: fs::directory_iterator(suite.path())) { + auto test_name = test.path().filename(); + if (fs::is_directory(test)) { + auto input_cq_path = test.path() / "input.cq"; + if (fs::exists(input_cq_path)) { + ::testing::RegisterTest( + suite_name.c_str(), test_name.c_str(), + nullptr, nullptr, + __FILE__, __LINE__, + [=]() -> ParsingTest* { return new ParsingTest(test); }); + } } } - ::testing::RegisterTest( - suite_name.c_str(), test_name.c_str(), - nullptr, nullptr, - __FILE__, __LINE__, - [=]() -> ParsingTest* { return new ParsingTest(test_path); }); } - closedir(suite_dir); } - closedir(parsing_dir); +} + +void register_v1x_tests() { + register_v1x_tests("parsing"); + //register_v1x_tests("toy-v1x-parsing"); } diff --git a/test/v1x/parsing.hpp b/test/v1x/parsing.hpp index c0be7d62..149dbc97 100644 --- a/test/v1x/parsing.hpp +++ b/test/v1x/parsing.hpp @@ -1,3 +1,3 @@ #pragma once -void register_v1x_parsing_tests(); +void register_v1x_tests(); diff --git a/test/v3x/CMakeLists.txt b/test/v3x/CMakeLists.txt new file mode 100644 index 00000000..3be474e1 --- /dev/null +++ b/test/v3x/CMakeLists.txt @@ -0,0 +1,3 @@ +target_sources(${PROJECT_NAME}_test PRIVATE + "${CMAKE_CURRENT_SOURCE_DIR}/cqasm-parse-helper.cpp" +) diff --git a/test/v3x/cqasm-parse-helper.cpp b/test/v3x/cqasm-parse-helper.cpp new file mode 100644 index 00000000..9eb9745d --- /dev/null +++ b/test/v3x/cqasm-parse-helper.cpp @@ -0,0 +1,12 @@ +#include "cqasm-error.hpp" +#include "v1x/cqasm-ast.hpp" +#include "v1x/cqasm-parse-result.hpp" +#include "v3x/cqasm-parse-helper.hpp" + +#include +#include +#include + +using namespace ::testing; +using namespace cqasm::error; +using namespace cqasm::v3x::parser; From b46805c5c49bb58f3533b6f8081079883b01a675 Mon Sep 17 00:00:00 2001 From: rturrado Date: Sat, 16 Sep 2023 03:29:02 +0200 Subject: [PATCH 08/28] Fixed ParsingTest::TestBody. Added current branch to GitHub Actions. --- .github/workflows/test.yml | 1 + test/v1x/parsing.cpp | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index c53c345e..138b4c43 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -4,6 +4,7 @@ on: push: branches: - develop + - toy-v1-use_case_circuit_for_parser_verification pull_request: jobs: diff --git a/test/v1x/parsing.cpp b/test/v1x/parsing.cpp index de7ad53d..d296af1f 100644 --- a/test/v1x/parsing.cpp +++ b/test/v1x/parsing.cpp @@ -75,7 +75,7 @@ class ParsingTest : public ::testing::Test { if (parse_result.errors.empty()) { ast_actual_file_contents = fmt::format("SUCCESS\n{}\n", *parse_result.root); } else { - ast_actual_file_contents = fmt::format("ERROR\n{}", fmt::join(parse_result.errors, "\n")); + ast_actual_file_contents = fmt::format("ERROR\n{}\n", fmt::join(parse_result.errors, "\n")); } auto ast_actual_file_path = path_ / "ast.actual.txt"; @@ -263,7 +263,7 @@ void register_v1x_tests(const fs::path& subdir) { suite_name.c_str(), test_name.c_str(), nullptr, nullptr, __FILE__, __LINE__, - [=]() -> ParsingTest* { return new ParsingTest(test); }); + [=]() -> ParsingTest* { return new ParsingTest(test.path()); }); } } } From 232e6922f680693c0154aafbfad3bbf74b0f5322 Mon Sep 17 00:00:00 2001 From: rturrado Date: Sat, 16 Sep 2023 03:50:23 +0200 Subject: [PATCH 09/28] Trying to fix MacOS and Windows tests. --- include/v3x/cqasm-parse-helper.hpp | 2 +- test/v1x/parsing.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/include/v3x/cqasm-parse-helper.hpp b/include/v3x/cqasm-parse-helper.hpp index 8bcfed28..07841117 100644 --- a/include/v3x/cqasm-parse-helper.hpp +++ b/include/v3x/cqasm-parse-helper.hpp @@ -38,7 +38,7 @@ class ScannerAntlr : public ScannerAdaptor { public: explicit ScannerAntlr(std::unique_ptr build_visitor_up); ~ScannerAntlr() override; - void parse(const std::string &file_name, cqasm::v1x::parser::ParseResult &result) = 0; + void parse(const std::string &file_name, cqasm::v1x::parser::ParseResult &result) override = 0; }; class ScannerAntlrFile : public ScannerAntlr { diff --git a/test/v1x/parsing.cpp b/test/v1x/parsing.cpp index d296af1f..306facad 100644 --- a/test/v1x/parsing.cpp +++ b/test/v1x/parsing.cpp @@ -253,9 +253,9 @@ void register_v1x_tests(const fs::path& subdir) { } for (const fs::directory_entry& suite: fs::directory_iterator(subdir_path)) { if (fs::is_directory(suite)) { - auto suite_name = suite.path().filename(); + auto suite_name = suite.path().filename().string(); for (const fs::directory_entry& test: fs::directory_iterator(suite.path())) { - auto test_name = test.path().filename(); + auto test_name = test.path().filename().string(); if (fs::is_directory(test)) { auto input_cq_path = test.path() / "input.cq"; if (fs::exists(input_cq_path)) { From 83febafd32ef53bb1b5335ebf2120dce7907521c Mon Sep 17 00:00:00 2001 From: rturrado Date: Sat, 16 Sep 2023 04:15:21 +0200 Subject: [PATCH 10/28] Trying to fix MacOS compilation. std::from_chars is not available until clang 15. --- src/v3x/BuildTreeGenAstVisitor.cpp | 36 +++++++++++++++++++++--------- 1 file changed, 25 insertions(+), 11 deletions(-) diff --git a/src/v3x/BuildTreeGenAstVisitor.cpp b/src/v3x/BuildTreeGenAstVisitor.cpp index 2016385a..db6d66e9 100644 --- a/src/v3x/BuildTreeGenAstVisitor.cpp +++ b/src/v3x/BuildTreeGenAstVisitor.cpp @@ -6,6 +6,7 @@ #include // assert #include // from_chars #include // runtime_error +#include // stod, stoll #include // errc @@ -14,15 +15,28 @@ namespace cqasm::v3x::parser { using namespace cqasm::v1x::ast; using namespace cqasm::error; -template -T get_terminal_node_value(antlr4::tree::TerminalNode *node) { +std::int64_t get_integer_literal_value(antlr4::tree::TerminalNode *node) { auto text = node->getText(); - T ret{}; - auto [ptr, ec] = std::from_chars(text.c_str(), text.c_str() + text.size(), ret); - if (ec == std::errc::invalid_argument) { - throw AnalysisError{ "terminal node is not of the expected type." }; - } else if (ec == std::errc::result_out_of_range) { - throw AnalysisError{ "terminal node is out of range" }; + std::int64_t ret{}; + try { + ret = std::stoll(text); + } catch (std::invalid_argument&) { + throw AnalysisError{ "terminal node is not of the expected INTEGER_LITERAL type." }; + } catch (std::out_of_range&) { + throw AnalysisError{ "terminal node is out of the INTEGER_LITERAL range" }; + } + return ret; +} + +double get_float_literal_value(antlr4::tree::TerminalNode *node) { + auto text = node->getText(); + double ret{}; + try { + ret = std::stod(text); + } catch (std::invalid_argument&) { + throw AnalysisError{ "terminal node is not of the expected FLOAT_LITERAL type." }; + } catch (std::out_of_range&) { + throw AnalysisError{ "terminal node is out of the FLOAT_LITERAL range" }; } return ret; } @@ -42,7 +56,7 @@ std::any BuildTreeGenAstVisitor::visitProgram(CqasmParser::ProgramContext *conte std::any BuildTreeGenAstVisitor::visitVersion(CqasmParser::VersionContext *context) { auto ret = One{}; for (size_t i{ 0 }; i < context->INTEGER_LITERAL().size(); ++i) { - auto number = get_terminal_node_value(context->INTEGER_LITERAL(i)); + auto number = get_integer_literal_value(context->INTEGER_LITERAL(i)); ret->items.push_back(number); } return ret; @@ -94,10 +108,10 @@ std::any BuildTreeGenAstVisitor::visitExpressionList(CqasmParser::ExpressionList std::any BuildTreeGenAstVisitor::visitExpression(CqasmParser::ExpressionContext *context) { if (auto integer_literal_ast = context->INTEGER_LITERAL()) { - auto integer_literal = get_terminal_node_value(integer_literal_ast); + auto integer_literal = get_integer_literal_value(integer_literal_ast); return cqasm::tree::make(integer_literal); } else if (auto float_literal_ast = context->FLOAT_LITERAL()) { - auto float_literal = get_terminal_node_value(float_literal_ast); + auto float_literal = get_float_literal_value(float_literal_ast); return cqasm::tree::make(float_literal); } else if (auto id_ast = context->IDENTIFIER()) { auto id = id_ast->getText(); From 4a932fe91caf4ea851c506207bb6c5ff099da90e Mon Sep 17 00:00:00 2001 From: rturrado Date: Sat, 16 Sep 2023 22:29:14 +0200 Subject: [PATCH 11/28] Added Toy v1 res/cq files. --- .../expression/qubits_3__x/ast.golden.txt | 0 .../expression/qubits_3__x/input.cq | 3 + .../expression/qubits_3__x_1/ast.golden.txt | 0 .../expression/qubits_3__x_1/input.cq | 3 + .../qubits_3__x_123abc/ast.golden.txt | 0 .../expression/qubits_3__x_123abc/input.cq | 3 + .../qubits_3__x_3_14/ast.golden.txt | 0 .../expression/qubits_3__x_3_14/input.cq | 3 + .../expression/qubits_3__x_v/ast.golden.txt | 0 .../expression/qubits_3__x_v/input.cq | 3 + .../bad_first_part/ast.golden.txt | 0 .../expression_list/bad_first_part/input.cq | 5 ++ .../bad_second_part/ast.golden.txt | 0 .../expression_list/bad_second_part/input.cq | 5 ++ .../no_second_part/ast.golden.txt | 0 .../expression_list/no_second_part/input.cq | 4 ++ .../ast.golden.txt | 0 .../qubits_3__h_q0__h_q1__cnot_q0_q1/input.cq | 5 ++ .../instruction/qubits_3__x_q0/ast.golden.txt | 0 .../instruction/qubits_3__x_q0/input.cq | 3 + .../instruction/qubits_3__x_q3/ast.golden.txt | 0 .../instruction/qubits_3__x_q3/input.cq | 3 + .../instruction/v_1/ast.golden.txt | 0 .../toy-v1x-parsing/instruction/v_1/input.cq | 2 + .../instruction/x/ast.golden.txt | 0 .../toy-v1x-parsing/instruction/x/input.cq | 2 + .../instruction/x_1/ast.golden.txt | 0 .../toy-v1x-parsing/instruction/x_1/input.cq | 2 + .../instruction/x_q0/ast.golden.txt | 0 .../toy-v1x-parsing/instruction/x_q0/input.cq | 2 + .../toy-v1x-parsing/mapping/ast.golden.txt | 0 res/v1x/toy-v1x-parsing/mapping/input.cq | 3 + .../mapping/map/ast.golden.txt | 0 res/v1x/toy-v1x-parsing/mapping/map/input.cq | 2 + .../mapping/map_v/ast.golden.txt | 0 .../toy-v1x-parsing/mapping/map_v/input.cq | 2 + .../mapping/map_v_1/ast.golden.txt | 0 .../toy-v1x-parsing/mapping/map_v_1/input.cq | 2 + .../mapping/map_v_1__map_w_v/ast.golden.txt | 0 .../mapping/map_v_1__map_w_v/input.cq | 3 + .../mapping/map_v_3_14/ast.golden.txt | 0 .../mapping/map_v_3_14/input.cq | 2 + .../mapping/map_v_equals/ast.golden.txt | 0 .../mapping/map_v_equals/input.cq | 2 + .../mapping/map_v_q0/ast.golden.txt | 0 .../toy-v1x-parsing/mapping/map_v_q0/input.cq | 2 + .../mapping/map_w_v/ast.golden.txt | 0 .../toy-v1x-parsing/mapping/map_w_v/input.cq | 2 + .../mapping/qubits_3__map_v_q0/ast.golden.txt | 0 .../mapping/qubits_3__map_v_q0/input.cq | 3 + .../mapping/qubits_3__map_v_q3/ast.golden.txt | 0 .../mapping/qubits_3__map_v_q3/input.cq | 0 .../bad_token_after_version/ast.golden.txt | 0 .../program/bad_token_after_version/input.cq | 2 + .../program/empty/ast.golden.txt | 0 .../toy-v1x-parsing/program/empty/input.cq | 0 .../something_before_version/ast.golden.txt | 0 .../program/something_before_version/input.cq | 2 + .../qubits/qubits_3/ast.golden.txt | 0 .../toy-v1x-parsing/qubits/qubits_3/input.cq | 2 + .../qubits/qubits_abc/ast.golden.txt | 0 .../qubits/qubits_abc/input.cq | 2 + .../qubits/qubits_no_number/ast.golden.txt | 0 .../qubits/qubits_no_number/input.cq | 2 + res/v1x/toy-v1x-parsing/test_cases.txt | 62 +++++++++++++++++ .../variable/map_v_1__var_w_v/ast.golden.txt | 0 .../variable/map_v_1__var_w_v/input.cq | 3 + .../variable/var_v/ast.golden.txt | 0 .../toy-v1x-parsing/variable/var_v/input.cq | 2 + .../variable/var_v_colon/ast.golden.txt | 0 .../variable/var_v_colon/input.cq | 2 + .../variable/var_w_v/ast.golden.txt | 0 .../toy-v1x-parsing/variable/var_w_v/input.cq | 2 + res/v3x/test_cases.txt | 68 ------------------- 74 files changed, 152 insertions(+), 68 deletions(-) create mode 100644 res/v1x/toy-v1x-parsing/expression/qubits_3__x/ast.golden.txt create mode 100644 res/v1x/toy-v1x-parsing/expression/qubits_3__x/input.cq create mode 100644 res/v1x/toy-v1x-parsing/expression/qubits_3__x_1/ast.golden.txt create mode 100644 res/v1x/toy-v1x-parsing/expression/qubits_3__x_1/input.cq create mode 100644 res/v1x/toy-v1x-parsing/expression/qubits_3__x_123abc/ast.golden.txt create mode 100644 res/v1x/toy-v1x-parsing/expression/qubits_3__x_123abc/input.cq create mode 100644 res/v1x/toy-v1x-parsing/expression/qubits_3__x_3_14/ast.golden.txt create mode 100644 res/v1x/toy-v1x-parsing/expression/qubits_3__x_3_14/input.cq create mode 100644 res/v1x/toy-v1x-parsing/expression/qubits_3__x_v/ast.golden.txt create mode 100644 res/v1x/toy-v1x-parsing/expression/qubits_3__x_v/input.cq create mode 100644 res/v1x/toy-v1x-parsing/expression_list/bad_first_part/ast.golden.txt create mode 100644 res/v1x/toy-v1x-parsing/expression_list/bad_first_part/input.cq create mode 100644 res/v1x/toy-v1x-parsing/expression_list/bad_second_part/ast.golden.txt create mode 100644 res/v1x/toy-v1x-parsing/expression_list/bad_second_part/input.cq create mode 100644 res/v1x/toy-v1x-parsing/expression_list/no_second_part/ast.golden.txt create mode 100644 res/v1x/toy-v1x-parsing/expression_list/no_second_part/input.cq create mode 100644 res/v1x/toy-v1x-parsing/instruction/qubits_3__h_q0__h_q1__cnot_q0_q1/ast.golden.txt create mode 100644 res/v1x/toy-v1x-parsing/instruction/qubits_3__h_q0__h_q1__cnot_q0_q1/input.cq create mode 100644 res/v1x/toy-v1x-parsing/instruction/qubits_3__x_q0/ast.golden.txt create mode 100644 res/v1x/toy-v1x-parsing/instruction/qubits_3__x_q0/input.cq create mode 100644 res/v1x/toy-v1x-parsing/instruction/qubits_3__x_q3/ast.golden.txt create mode 100644 res/v1x/toy-v1x-parsing/instruction/qubits_3__x_q3/input.cq create mode 100644 res/v1x/toy-v1x-parsing/instruction/v_1/ast.golden.txt create mode 100644 res/v1x/toy-v1x-parsing/instruction/v_1/input.cq create mode 100644 res/v1x/toy-v1x-parsing/instruction/x/ast.golden.txt create mode 100644 res/v1x/toy-v1x-parsing/instruction/x/input.cq create mode 100644 res/v1x/toy-v1x-parsing/instruction/x_1/ast.golden.txt create mode 100644 res/v1x/toy-v1x-parsing/instruction/x_1/input.cq create mode 100644 res/v1x/toy-v1x-parsing/instruction/x_q0/ast.golden.txt create mode 100644 res/v1x/toy-v1x-parsing/instruction/x_q0/input.cq create mode 100644 res/v1x/toy-v1x-parsing/mapping/ast.golden.txt create mode 100644 res/v1x/toy-v1x-parsing/mapping/input.cq create mode 100644 res/v1x/toy-v1x-parsing/mapping/map/ast.golden.txt create mode 100644 res/v1x/toy-v1x-parsing/mapping/map/input.cq create mode 100644 res/v1x/toy-v1x-parsing/mapping/map_v/ast.golden.txt create mode 100644 res/v1x/toy-v1x-parsing/mapping/map_v/input.cq create mode 100644 res/v1x/toy-v1x-parsing/mapping/map_v_1/ast.golden.txt create mode 100644 res/v1x/toy-v1x-parsing/mapping/map_v_1/input.cq create mode 100644 res/v1x/toy-v1x-parsing/mapping/map_v_1__map_w_v/ast.golden.txt create mode 100644 res/v1x/toy-v1x-parsing/mapping/map_v_1__map_w_v/input.cq create mode 100644 res/v1x/toy-v1x-parsing/mapping/map_v_3_14/ast.golden.txt create mode 100644 res/v1x/toy-v1x-parsing/mapping/map_v_3_14/input.cq create mode 100644 res/v1x/toy-v1x-parsing/mapping/map_v_equals/ast.golden.txt create mode 100644 res/v1x/toy-v1x-parsing/mapping/map_v_equals/input.cq create mode 100644 res/v1x/toy-v1x-parsing/mapping/map_v_q0/ast.golden.txt create mode 100644 res/v1x/toy-v1x-parsing/mapping/map_v_q0/input.cq create mode 100644 res/v1x/toy-v1x-parsing/mapping/map_w_v/ast.golden.txt create mode 100644 res/v1x/toy-v1x-parsing/mapping/map_w_v/input.cq create mode 100644 res/v1x/toy-v1x-parsing/mapping/qubits_3__map_v_q0/ast.golden.txt create mode 100644 res/v1x/toy-v1x-parsing/mapping/qubits_3__map_v_q0/input.cq create mode 100644 res/v1x/toy-v1x-parsing/mapping/qubits_3__map_v_q3/ast.golden.txt create mode 100644 res/v1x/toy-v1x-parsing/mapping/qubits_3__map_v_q3/input.cq create mode 100644 res/v1x/toy-v1x-parsing/program/bad_token_after_version/ast.golden.txt create mode 100644 res/v1x/toy-v1x-parsing/program/bad_token_after_version/input.cq create mode 100644 res/v1x/toy-v1x-parsing/program/empty/ast.golden.txt create mode 100644 res/v1x/toy-v1x-parsing/program/empty/input.cq create mode 100644 res/v1x/toy-v1x-parsing/program/something_before_version/ast.golden.txt create mode 100644 res/v1x/toy-v1x-parsing/program/something_before_version/input.cq create mode 100644 res/v1x/toy-v1x-parsing/qubits/qubits_3/ast.golden.txt create mode 100644 res/v1x/toy-v1x-parsing/qubits/qubits_3/input.cq create mode 100644 res/v1x/toy-v1x-parsing/qubits/qubits_abc/ast.golden.txt create mode 100644 res/v1x/toy-v1x-parsing/qubits/qubits_abc/input.cq create mode 100644 res/v1x/toy-v1x-parsing/qubits/qubits_no_number/ast.golden.txt create mode 100644 res/v1x/toy-v1x-parsing/qubits/qubits_no_number/input.cq create mode 100644 res/v1x/toy-v1x-parsing/test_cases.txt create mode 100644 res/v1x/toy-v1x-parsing/variable/map_v_1__var_w_v/ast.golden.txt create mode 100644 res/v1x/toy-v1x-parsing/variable/map_v_1__var_w_v/input.cq create mode 100644 res/v1x/toy-v1x-parsing/variable/var_v/ast.golden.txt create mode 100644 res/v1x/toy-v1x-parsing/variable/var_v/input.cq create mode 100644 res/v1x/toy-v1x-parsing/variable/var_v_colon/ast.golden.txt create mode 100644 res/v1x/toy-v1x-parsing/variable/var_v_colon/input.cq create mode 100644 res/v1x/toy-v1x-parsing/variable/var_w_v/ast.golden.txt create mode 100644 res/v1x/toy-v1x-parsing/variable/var_w_v/input.cq delete mode 100644 res/v3x/test_cases.txt diff --git a/res/v1x/toy-v1x-parsing/expression/qubits_3__x/ast.golden.txt b/res/v1x/toy-v1x-parsing/expression/qubits_3__x/ast.golden.txt new file mode 100644 index 00000000..e69de29b diff --git a/res/v1x/toy-v1x-parsing/expression/qubits_3__x/input.cq b/res/v1x/toy-v1x-parsing/expression/qubits_3__x/input.cq new file mode 100644 index 00000000..d28e85d7 --- /dev/null +++ b/res/v1x/toy-v1x-parsing/expression/qubits_3__x/input.cq @@ -0,0 +1,3 @@ +version 3 +qubits 3 +x diff --git a/res/v1x/toy-v1x-parsing/expression/qubits_3__x_1/ast.golden.txt b/res/v1x/toy-v1x-parsing/expression/qubits_3__x_1/ast.golden.txt new file mode 100644 index 00000000..e69de29b diff --git a/res/v1x/toy-v1x-parsing/expression/qubits_3__x_1/input.cq b/res/v1x/toy-v1x-parsing/expression/qubits_3__x_1/input.cq new file mode 100644 index 00000000..988ca9b5 --- /dev/null +++ b/res/v1x/toy-v1x-parsing/expression/qubits_3__x_1/input.cq @@ -0,0 +1,3 @@ +version 3 +qubits 3 +x 1 diff --git a/res/v1x/toy-v1x-parsing/expression/qubits_3__x_123abc/ast.golden.txt b/res/v1x/toy-v1x-parsing/expression/qubits_3__x_123abc/ast.golden.txt new file mode 100644 index 00000000..e69de29b diff --git a/res/v1x/toy-v1x-parsing/expression/qubits_3__x_123abc/input.cq b/res/v1x/toy-v1x-parsing/expression/qubits_3__x_123abc/input.cq new file mode 100644 index 00000000..e5cc1e28 --- /dev/null +++ b/res/v1x/toy-v1x-parsing/expression/qubits_3__x_123abc/input.cq @@ -0,0 +1,3 @@ +version 3 +qubits 3 +x 123abc \ No newline at end of file diff --git a/res/v1x/toy-v1x-parsing/expression/qubits_3__x_3_14/ast.golden.txt b/res/v1x/toy-v1x-parsing/expression/qubits_3__x_3_14/ast.golden.txt new file mode 100644 index 00000000..e69de29b diff --git a/res/v1x/toy-v1x-parsing/expression/qubits_3__x_3_14/input.cq b/res/v1x/toy-v1x-parsing/expression/qubits_3__x_3_14/input.cq new file mode 100644 index 00000000..5cbaad32 --- /dev/null +++ b/res/v1x/toy-v1x-parsing/expression/qubits_3__x_3_14/input.cq @@ -0,0 +1,3 @@ +version 3 +qubits 3 +x 3.14 diff --git a/res/v1x/toy-v1x-parsing/expression/qubits_3__x_v/ast.golden.txt b/res/v1x/toy-v1x-parsing/expression/qubits_3__x_v/ast.golden.txt new file mode 100644 index 00000000..e69de29b diff --git a/res/v1x/toy-v1x-parsing/expression/qubits_3__x_v/input.cq b/res/v1x/toy-v1x-parsing/expression/qubits_3__x_v/input.cq new file mode 100644 index 00000000..6d792cfd --- /dev/null +++ b/res/v1x/toy-v1x-parsing/expression/qubits_3__x_v/input.cq @@ -0,0 +1,3 @@ +version 3 +qubits 3 +x v diff --git a/res/v1x/toy-v1x-parsing/expression_list/bad_first_part/ast.golden.txt b/res/v1x/toy-v1x-parsing/expression_list/bad_first_part/ast.golden.txt new file mode 100644 index 00000000..e69de29b diff --git a/res/v1x/toy-v1x-parsing/expression_list/bad_first_part/input.cq b/res/v1x/toy-v1x-parsing/expression_list/bad_first_part/input.cq new file mode 100644 index 00000000..852d0880 --- /dev/null +++ b/res/v1x/toy-v1x-parsing/expression_list/bad_first_part/input.cq @@ -0,0 +1,5 @@ +version 3 +qubits 3 +h q[0] +h q[1] +cnot 123abc, q[0] diff --git a/res/v1x/toy-v1x-parsing/expression_list/bad_second_part/ast.golden.txt b/res/v1x/toy-v1x-parsing/expression_list/bad_second_part/ast.golden.txt new file mode 100644 index 00000000..e69de29b diff --git a/res/v1x/toy-v1x-parsing/expression_list/bad_second_part/input.cq b/res/v1x/toy-v1x-parsing/expression_list/bad_second_part/input.cq new file mode 100644 index 00000000..5ebbe954 --- /dev/null +++ b/res/v1x/toy-v1x-parsing/expression_list/bad_second_part/input.cq @@ -0,0 +1,5 @@ +version 3 +qubits 3 +h q[0] +h q[1] +cnot q[0], 123abc diff --git a/res/v1x/toy-v1x-parsing/expression_list/no_second_part/ast.golden.txt b/res/v1x/toy-v1x-parsing/expression_list/no_second_part/ast.golden.txt new file mode 100644 index 00000000..e69de29b diff --git a/res/v1x/toy-v1x-parsing/expression_list/no_second_part/input.cq b/res/v1x/toy-v1x-parsing/expression_list/no_second_part/input.cq new file mode 100644 index 00000000..88d54d76 --- /dev/null +++ b/res/v1x/toy-v1x-parsing/expression_list/no_second_part/input.cq @@ -0,0 +1,4 @@ +version 3 +qubits 3 +h q[0];h q[1] +cnot q[0], diff --git a/res/v1x/toy-v1x-parsing/instruction/qubits_3__h_q0__h_q1__cnot_q0_q1/ast.golden.txt b/res/v1x/toy-v1x-parsing/instruction/qubits_3__h_q0__h_q1__cnot_q0_q1/ast.golden.txt new file mode 100644 index 00000000..e69de29b diff --git a/res/v1x/toy-v1x-parsing/instruction/qubits_3__h_q0__h_q1__cnot_q0_q1/input.cq b/res/v1x/toy-v1x-parsing/instruction/qubits_3__h_q0__h_q1__cnot_q0_q1/input.cq new file mode 100644 index 00000000..b9646513 --- /dev/null +++ b/res/v1x/toy-v1x-parsing/instruction/qubits_3__h_q0__h_q1__cnot_q0_q1/input.cq @@ -0,0 +1,5 @@ +version 3 +qubits 3 +h q[0] +h q[1] +cnot q[0], q[1] diff --git a/res/v1x/toy-v1x-parsing/instruction/qubits_3__x_q0/ast.golden.txt b/res/v1x/toy-v1x-parsing/instruction/qubits_3__x_q0/ast.golden.txt new file mode 100644 index 00000000..e69de29b diff --git a/res/v1x/toy-v1x-parsing/instruction/qubits_3__x_q0/input.cq b/res/v1x/toy-v1x-parsing/instruction/qubits_3__x_q0/input.cq new file mode 100644 index 00000000..c7d2954f --- /dev/null +++ b/res/v1x/toy-v1x-parsing/instruction/qubits_3__x_q0/input.cq @@ -0,0 +1,3 @@ +version 3 +qubits 3 +x q[3] diff --git a/res/v1x/toy-v1x-parsing/instruction/qubits_3__x_q3/ast.golden.txt b/res/v1x/toy-v1x-parsing/instruction/qubits_3__x_q3/ast.golden.txt new file mode 100644 index 00000000..e69de29b diff --git a/res/v1x/toy-v1x-parsing/instruction/qubits_3__x_q3/input.cq b/res/v1x/toy-v1x-parsing/instruction/qubits_3__x_q3/input.cq new file mode 100644 index 00000000..c7d2954f --- /dev/null +++ b/res/v1x/toy-v1x-parsing/instruction/qubits_3__x_q3/input.cq @@ -0,0 +1,3 @@ +version 3 +qubits 3 +x q[3] diff --git a/res/v1x/toy-v1x-parsing/instruction/v_1/ast.golden.txt b/res/v1x/toy-v1x-parsing/instruction/v_1/ast.golden.txt new file mode 100644 index 00000000..e69de29b diff --git a/res/v1x/toy-v1x-parsing/instruction/v_1/input.cq b/res/v1x/toy-v1x-parsing/instruction/v_1/input.cq new file mode 100644 index 00000000..935b8bab --- /dev/null +++ b/res/v1x/toy-v1x-parsing/instruction/v_1/input.cq @@ -0,0 +1,2 @@ +version 3 +v 1 diff --git a/res/v1x/toy-v1x-parsing/instruction/x/ast.golden.txt b/res/v1x/toy-v1x-parsing/instruction/x/ast.golden.txt new file mode 100644 index 00000000..e69de29b diff --git a/res/v1x/toy-v1x-parsing/instruction/x/input.cq b/res/v1x/toy-v1x-parsing/instruction/x/input.cq new file mode 100644 index 00000000..a30a2073 --- /dev/null +++ b/res/v1x/toy-v1x-parsing/instruction/x/input.cq @@ -0,0 +1,2 @@ +version 3 +x diff --git a/res/v1x/toy-v1x-parsing/instruction/x_1/ast.golden.txt b/res/v1x/toy-v1x-parsing/instruction/x_1/ast.golden.txt new file mode 100644 index 00000000..e69de29b diff --git a/res/v1x/toy-v1x-parsing/instruction/x_1/input.cq b/res/v1x/toy-v1x-parsing/instruction/x_1/input.cq new file mode 100644 index 00000000..5c2de263 --- /dev/null +++ b/res/v1x/toy-v1x-parsing/instruction/x_1/input.cq @@ -0,0 +1,2 @@ +version 3 +x 1 diff --git a/res/v1x/toy-v1x-parsing/instruction/x_q0/ast.golden.txt b/res/v1x/toy-v1x-parsing/instruction/x_q0/ast.golden.txt new file mode 100644 index 00000000..e69de29b diff --git a/res/v1x/toy-v1x-parsing/instruction/x_q0/input.cq b/res/v1x/toy-v1x-parsing/instruction/x_q0/input.cq new file mode 100644 index 00000000..106acce9 --- /dev/null +++ b/res/v1x/toy-v1x-parsing/instruction/x_q0/input.cq @@ -0,0 +1,2 @@ +version 3 +x q[0] diff --git a/res/v1x/toy-v1x-parsing/mapping/ast.golden.txt b/res/v1x/toy-v1x-parsing/mapping/ast.golden.txt new file mode 100644 index 00000000..e69de29b diff --git a/res/v1x/toy-v1x-parsing/mapping/input.cq b/res/v1x/toy-v1x-parsing/mapping/input.cq new file mode 100644 index 00000000..ee1ac059 --- /dev/null +++ b/res/v1x/toy-v1x-parsing/mapping/input.cq @@ -0,0 +1,3 @@ +version 3 +qubits 3 +map v = q[3] diff --git a/res/v1x/toy-v1x-parsing/mapping/map/ast.golden.txt b/res/v1x/toy-v1x-parsing/mapping/map/ast.golden.txt new file mode 100644 index 00000000..e69de29b diff --git a/res/v1x/toy-v1x-parsing/mapping/map/input.cq b/res/v1x/toy-v1x-parsing/mapping/map/input.cq new file mode 100644 index 00000000..58bebeaa --- /dev/null +++ b/res/v1x/toy-v1x-parsing/mapping/map/input.cq @@ -0,0 +1,2 @@ +version 3 +map diff --git a/res/v1x/toy-v1x-parsing/mapping/map_v/ast.golden.txt b/res/v1x/toy-v1x-parsing/mapping/map_v/ast.golden.txt new file mode 100644 index 00000000..e69de29b diff --git a/res/v1x/toy-v1x-parsing/mapping/map_v/input.cq b/res/v1x/toy-v1x-parsing/mapping/map_v/input.cq new file mode 100644 index 00000000..11719a19 --- /dev/null +++ b/res/v1x/toy-v1x-parsing/mapping/map_v/input.cq @@ -0,0 +1,2 @@ +version 3 +map v diff --git a/res/v1x/toy-v1x-parsing/mapping/map_v_1/ast.golden.txt b/res/v1x/toy-v1x-parsing/mapping/map_v_1/ast.golden.txt new file mode 100644 index 00000000..e69de29b diff --git a/res/v1x/toy-v1x-parsing/mapping/map_v_1/input.cq b/res/v1x/toy-v1x-parsing/mapping/map_v_1/input.cq new file mode 100644 index 00000000..58a5b09b --- /dev/null +++ b/res/v1x/toy-v1x-parsing/mapping/map_v_1/input.cq @@ -0,0 +1,2 @@ +version 3 +map v = 1 diff --git a/res/v1x/toy-v1x-parsing/mapping/map_v_1__map_w_v/ast.golden.txt b/res/v1x/toy-v1x-parsing/mapping/map_v_1__map_w_v/ast.golden.txt new file mode 100644 index 00000000..e69de29b diff --git a/res/v1x/toy-v1x-parsing/mapping/map_v_1__map_w_v/input.cq b/res/v1x/toy-v1x-parsing/mapping/map_v_1__map_w_v/input.cq new file mode 100644 index 00000000..4077eb3b --- /dev/null +++ b/res/v1x/toy-v1x-parsing/mapping/map_v_1__map_w_v/input.cq @@ -0,0 +1,3 @@ +version 3 +map v = 1 +map w = v diff --git a/res/v1x/toy-v1x-parsing/mapping/map_v_3_14/ast.golden.txt b/res/v1x/toy-v1x-parsing/mapping/map_v_3_14/ast.golden.txt new file mode 100644 index 00000000..e69de29b diff --git a/res/v1x/toy-v1x-parsing/mapping/map_v_3_14/input.cq b/res/v1x/toy-v1x-parsing/mapping/map_v_3_14/input.cq new file mode 100644 index 00000000..f934b22b --- /dev/null +++ b/res/v1x/toy-v1x-parsing/mapping/map_v_3_14/input.cq @@ -0,0 +1,2 @@ +version 3 +map v = 3.14 diff --git a/res/v1x/toy-v1x-parsing/mapping/map_v_equals/ast.golden.txt b/res/v1x/toy-v1x-parsing/mapping/map_v_equals/ast.golden.txt new file mode 100644 index 00000000..e69de29b diff --git a/res/v1x/toy-v1x-parsing/mapping/map_v_equals/input.cq b/res/v1x/toy-v1x-parsing/mapping/map_v_equals/input.cq new file mode 100644 index 00000000..a016fd11 --- /dev/null +++ b/res/v1x/toy-v1x-parsing/mapping/map_v_equals/input.cq @@ -0,0 +1,2 @@ +version 3 +map v = diff --git a/res/v1x/toy-v1x-parsing/mapping/map_v_q0/ast.golden.txt b/res/v1x/toy-v1x-parsing/mapping/map_v_q0/ast.golden.txt new file mode 100644 index 00000000..e69de29b diff --git a/res/v1x/toy-v1x-parsing/mapping/map_v_q0/input.cq b/res/v1x/toy-v1x-parsing/mapping/map_v_q0/input.cq new file mode 100644 index 00000000..25af4a2d --- /dev/null +++ b/res/v1x/toy-v1x-parsing/mapping/map_v_q0/input.cq @@ -0,0 +1,2 @@ +version 3 +map v = q[0] diff --git a/res/v1x/toy-v1x-parsing/mapping/map_w_v/ast.golden.txt b/res/v1x/toy-v1x-parsing/mapping/map_w_v/ast.golden.txt new file mode 100644 index 00000000..e69de29b diff --git a/res/v1x/toy-v1x-parsing/mapping/map_w_v/input.cq b/res/v1x/toy-v1x-parsing/mapping/map_w_v/input.cq new file mode 100644 index 00000000..6a3075a2 --- /dev/null +++ b/res/v1x/toy-v1x-parsing/mapping/map_w_v/input.cq @@ -0,0 +1,2 @@ +version 3 +map w = v diff --git a/res/v1x/toy-v1x-parsing/mapping/qubits_3__map_v_q0/ast.golden.txt b/res/v1x/toy-v1x-parsing/mapping/qubits_3__map_v_q0/ast.golden.txt new file mode 100644 index 00000000..e69de29b diff --git a/res/v1x/toy-v1x-parsing/mapping/qubits_3__map_v_q0/input.cq b/res/v1x/toy-v1x-parsing/mapping/qubits_3__map_v_q0/input.cq new file mode 100644 index 00000000..6b9c1fd4 --- /dev/null +++ b/res/v1x/toy-v1x-parsing/mapping/qubits_3__map_v_q0/input.cq @@ -0,0 +1,3 @@ +version 3 +qubits 3 +map v = q[0] diff --git a/res/v1x/toy-v1x-parsing/mapping/qubits_3__map_v_q3/ast.golden.txt b/res/v1x/toy-v1x-parsing/mapping/qubits_3__map_v_q3/ast.golden.txt new file mode 100644 index 00000000..e69de29b diff --git a/res/v1x/toy-v1x-parsing/mapping/qubits_3__map_v_q3/input.cq b/res/v1x/toy-v1x-parsing/mapping/qubits_3__map_v_q3/input.cq new file mode 100644 index 00000000..e69de29b diff --git a/res/v1x/toy-v1x-parsing/program/bad_token_after_version/ast.golden.txt b/res/v1x/toy-v1x-parsing/program/bad_token_after_version/ast.golden.txt new file mode 100644 index 00000000..e69de29b diff --git a/res/v1x/toy-v1x-parsing/program/bad_token_after_version/input.cq b/res/v1x/toy-v1x-parsing/program/bad_token_after_version/input.cq new file mode 100644 index 00000000..11a86311 --- /dev/null +++ b/res/v1x/toy-v1x-parsing/program/bad_token_after_version/input.cq @@ -0,0 +1,2 @@ +version 3 +123abc diff --git a/res/v1x/toy-v1x-parsing/program/empty/ast.golden.txt b/res/v1x/toy-v1x-parsing/program/empty/ast.golden.txt new file mode 100644 index 00000000..e69de29b diff --git a/res/v1x/toy-v1x-parsing/program/empty/input.cq b/res/v1x/toy-v1x-parsing/program/empty/input.cq new file mode 100644 index 00000000..e69de29b diff --git a/res/v1x/toy-v1x-parsing/program/something_before_version/ast.golden.txt b/res/v1x/toy-v1x-parsing/program/something_before_version/ast.golden.txt new file mode 100644 index 00000000..e69de29b diff --git a/res/v1x/toy-v1x-parsing/program/something_before_version/input.cq b/res/v1x/toy-v1x-parsing/program/something_before_version/input.cq new file mode 100644 index 00000000..dbff8824 --- /dev/null +++ b/res/v1x/toy-v1x-parsing/program/something_before_version/input.cq @@ -0,0 +1,2 @@ +blah +version 3 diff --git a/res/v1x/toy-v1x-parsing/qubits/qubits_3/ast.golden.txt b/res/v1x/toy-v1x-parsing/qubits/qubits_3/ast.golden.txt new file mode 100644 index 00000000..e69de29b diff --git a/res/v1x/toy-v1x-parsing/qubits/qubits_3/input.cq b/res/v1x/toy-v1x-parsing/qubits/qubits_3/input.cq new file mode 100644 index 00000000..5527f5c1 --- /dev/null +++ b/res/v1x/toy-v1x-parsing/qubits/qubits_3/input.cq @@ -0,0 +1,2 @@ +version 3 +qubits 3 diff --git a/res/v1x/toy-v1x-parsing/qubits/qubits_abc/ast.golden.txt b/res/v1x/toy-v1x-parsing/qubits/qubits_abc/ast.golden.txt new file mode 100644 index 00000000..e69de29b diff --git a/res/v1x/toy-v1x-parsing/qubits/qubits_abc/input.cq b/res/v1x/toy-v1x-parsing/qubits/qubits_abc/input.cq new file mode 100644 index 00000000..45aa3751 --- /dev/null +++ b/res/v1x/toy-v1x-parsing/qubits/qubits_abc/input.cq @@ -0,0 +1,2 @@ +version 3 +qubits abc diff --git a/res/v1x/toy-v1x-parsing/qubits/qubits_no_number/ast.golden.txt b/res/v1x/toy-v1x-parsing/qubits/qubits_no_number/ast.golden.txt new file mode 100644 index 00000000..e69de29b diff --git a/res/v1x/toy-v1x-parsing/qubits/qubits_no_number/input.cq b/res/v1x/toy-v1x-parsing/qubits/qubits_no_number/input.cq new file mode 100644 index 00000000..bdfd07d2 --- /dev/null +++ b/res/v1x/toy-v1x-parsing/qubits/qubits_no_number/input.cq @@ -0,0 +1,2 @@ +version 3 +qubits diff --git a/res/v1x/toy-v1x-parsing/test_cases.txt b/res/v1x/toy-v1x-parsing/test_cases.txt new file mode 100644 index 00000000..e55936d0 --- /dev/null +++ b/res/v1x/toy-v1x-parsing/test_cases.txt @@ -0,0 +1,62 @@ +* fail empty program +* fail something before version blah; version 3 + +* fail OK version, bad token version 3;123abc + + fail OK version, empty qubits version 3;qubits + fail OK version, wrong qubits version 3;qubits 123abc + OK OK version, OK qubits version 3;qubits 3 + + fail empty map version 3;map + fail empty map id version 3;map v + fail empty map id = version 3;map v = + OK OK map integer version 3;map v = 1 + OK OK map float version 3;map v = 3.14 + fail bad map id version 3;map w = v Syntactically correct, not semantically + OK OK map id version 3;map v = 1;map w = v + fail bad map array, no qubits version 3;map v = q[0] Syntactically correct, not semantically + fail bad map array, out of bounds qubit version 3;qubits 3;map v = q[3] Syntactically correct, not semantically + OK OK map array version 3;qubits 3;map v = q[0] + + fail empty var version 3;var + fail empty var id version 3;var v + fail empty var id : version 3;var v : + fail bad var id version 3;var w : v Syntactically correct, not semantically + OK OK var id version 3;map v = 1;var w : v + + fail empty instruction version 3;x + fail bad id version 3;v 1 Syntactically correct, not semantically + fail bad expression version 3;x 1 Syntactically correct, not semantically + fail bad instruction, no qubits version 3;x q[0] Syntactically correct, not semantically + fail bad instruction, out of bounds qubit version 3;qubits 3;x q[3] Syntactically correct, not semantically + OK OK one qubit instruction version 3;qubits 3;x q[0] + OK OK two qubit instruction version 3;qubits 3;h q[0];h q[1];cnot q[0], q[3] + + fail empty instruction expression version 3;qubits 3;x + fail bad instruction expression version 3;qubits 3;x 123abc + fail bad instruction expression integer version 3;qubits 3;x 1 Syntactically correct, not semantically + fail bad instruction expression float version 3;qubits 3;x 3.14 Syntactically correct, not semantically + fail bad instruction expression id version 3;qubits 3;x v Syntactically correct, not semantically + + + fail bad expression list, no second part version 3;qubits 3;h q[0];h q[1];cnot q[0], + fail bad expression list, bad first part version 3;qubits 3;h q[0];h q[1];cnot 123abc, q[0] + fail bad expression list, bad second part version 3;qubits 3;h q[0];h q[1];cnot q[0], 123abc + + Questions: + - What instructions are supported for the toy version? x, y, z, h? measure? + + Test implementation: + - Have a look at how it is done for v1x + - For semantic issues we probably need to do the checks at the AST level, kind of integration test + - However, I don't see why we cannot work with strings instead of files + + - We could just copy/paste, initially, test/v1x/parsing.cpp, simplifying it, removing instructions and functions + - Even comparing files. But, as I said above, I'd rather compare data structures (e.g. the AST) than files + + - The important stuff for this task would be to implement v3x/cqasm-parse-helper.cpp, + first refactor it like src/cqasm-version.cpp, + then make it call ANTLR + - All the AST stuff I would just copy/paste it from v1 + + - For this task, I will need help from Hans, maybe more than from Pablo diff --git a/res/v1x/toy-v1x-parsing/variable/map_v_1__var_w_v/ast.golden.txt b/res/v1x/toy-v1x-parsing/variable/map_v_1__var_w_v/ast.golden.txt new file mode 100644 index 00000000..e69de29b diff --git a/res/v1x/toy-v1x-parsing/variable/map_v_1__var_w_v/input.cq b/res/v1x/toy-v1x-parsing/variable/map_v_1__var_w_v/input.cq new file mode 100644 index 00000000..2810db24 --- /dev/null +++ b/res/v1x/toy-v1x-parsing/variable/map_v_1__var_w_v/input.cq @@ -0,0 +1,3 @@ +version 3 +map v = 1 +var w : v diff --git a/res/v1x/toy-v1x-parsing/variable/var_v/ast.golden.txt b/res/v1x/toy-v1x-parsing/variable/var_v/ast.golden.txt new file mode 100644 index 00000000..e69de29b diff --git a/res/v1x/toy-v1x-parsing/variable/var_v/input.cq b/res/v1x/toy-v1x-parsing/variable/var_v/input.cq new file mode 100644 index 00000000..f34c4522 --- /dev/null +++ b/res/v1x/toy-v1x-parsing/variable/var_v/input.cq @@ -0,0 +1,2 @@ +version 3 +var v diff --git a/res/v1x/toy-v1x-parsing/variable/var_v_colon/ast.golden.txt b/res/v1x/toy-v1x-parsing/variable/var_v_colon/ast.golden.txt new file mode 100644 index 00000000..e69de29b diff --git a/res/v1x/toy-v1x-parsing/variable/var_v_colon/input.cq b/res/v1x/toy-v1x-parsing/variable/var_v_colon/input.cq new file mode 100644 index 00000000..c6efdb5f --- /dev/null +++ b/res/v1x/toy-v1x-parsing/variable/var_v_colon/input.cq @@ -0,0 +1,2 @@ +version 3 +var v : diff --git a/res/v1x/toy-v1x-parsing/variable/var_w_v/ast.golden.txt b/res/v1x/toy-v1x-parsing/variable/var_w_v/ast.golden.txt new file mode 100644 index 00000000..e69de29b diff --git a/res/v1x/toy-v1x-parsing/variable/var_w_v/input.cq b/res/v1x/toy-v1x-parsing/variable/var_w_v/input.cq new file mode 100644 index 00000000..c7f183fe --- /dev/null +++ b/res/v1x/toy-v1x-parsing/variable/var_w_v/input.cq @@ -0,0 +1,2 @@ +version 3 +var w : v diff --git a/res/v3x/test_cases.txt b/res/v3x/test_cases.txt deleted file mode 100644 index a6bbf332..00000000 --- a/res/v3x/test_cases.txt +++ /dev/null @@ -1,68 +0,0 @@ -fail empty program -fail something before version blah; version 3 - -fail version without number version -fail bad version version blah -fail version not supported version 1.2 Syntactically correct, not semantically -OK OK version, no newline version 3 -OK OK version, semicolon version 3; -OK OK version, newline version 3\n -fail OK version, bad token version 3;123abc - -fail OK version, empty qubits version 3;qubits -fail OK version, wrong qubits version 3;qubits 123abc -OK OK version, OK qubits version 3;qubits 3 - -fail empty map version 3;map -fail empty map id version 3;map v -fail empty map id = version 3;map v = -OK OK map integer version 3;map v = 1 -OK OK map float version 3;map v = 3.14 -fail bad map id version 3;map w = v Syntactically correct, not semantically -OK OK map id version 3;map v = 1;map w = v -fail bad map array, no qubits version 3;map v = q[0] Syntactically correct, not semantically -fail bad map array, out of bounds qubit version 3;qubits 3;map v = q[3] Syntactically correct, not semantically -OK OK map array version 3;qubits 3;map v = q[0] - -fail empty var version 3;var -fail empty var id version 3;var v -fail empty var id : version 3;var v = -fail bad var id version 3;var w : v Syntactically correct, not semantically -OK OK var id version 3;map v : 1;var w : v - -fail empty instruction version 3;x -fail bad id version 3;v 1 Syntactically correct, not semantically -fail bad expression version 3;x 1 Syntactically correct, not semantically -fail bad instruction, no qubits version 3;x q[0] Syntactically correct, not semantically -fail bad instruction, out of bounds qubit version 3;qubits 3;x q[3] Syntactically correct, not semantically -OK OK one qubit instruction version 3;qubits 3;x q[0] -OK OK two qubit instruction version 3;qubits 3;h q[0];h q[1];cnot q[0], q[3] - -fail empty instruction expression version 3;qubits 3;x -fail bad instruction expression version 3;qubits 3;x 123abc -fail bad instruction expression integer version 3;qubits 3;x 1 Syntactically correct, not semantically -fail bad instruction expression float version 3;qubits 3;x 3.14 Syntactically correct, not semantically -fail bad instruction expression id version 3;qubits 3;x v Syntactically correct, not semantically - - -fail bad expression list, no second part version 3;qubits 3;h q[0];h q[1];cnot q[0], -fail bad expression list, bad first part version 3;qubits 3;h q[0];h q[1];cnot 123abc, q[0] -fail bad expression list, bad second part version 3;qubits 3;h q[0];h q[1];cnot q[0], 123abc - -Questions: -- What instructions are supported for the toy version? x, y, z, h? measure? - -Test implementation: -- Have a look at how it is done for v1x -- For semantic issues we probably need to do the checks at the AST level, kind of integration test -- However, I don't see why we cannot work with strings instead of files - -- We could just copy/paste, initially, test/v1x/parsing.cpp, simplifying it, removing instructions and functions -- Even comparing files. But, as I said above, I'd rather compare data structures (e.g. the AST) than files - -- The important stuff for this task would be to implement v3x/cqasm-parse-helper.cpp, - first refactor it like src/cqasm-version.cpp, - then make it call ANTLR -- All the AST stuff I would just copy/paste it from v1 - -- For this task, I will need help from Hans, maybe more than from Pablo From 5f0f2d552894dd1b4b4ecded3981961fb6075f2f Mon Sep 17 00:00:00 2001 From: rturrado <68099809+rturrado@users.noreply.github.com> Date: Tue, 19 Sep 2023 00:12:12 +0200 Subject: [PATCH 12/28] Removed some Flex/Bison warnings due to integral types redefinitions. See explanation of fix here: https://stackoverflow.com/a/77120324/260313. --- src/v1x/cqasm-lexer.l | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/v1x/cqasm-lexer.l b/src/v1x/cqasm-lexer.l index bc3b6bc7..21a357eb 100644 --- a/src/v1x/cqasm-lexer.l +++ b/src/v1x/cqasm-lexer.l @@ -4,6 +4,10 @@ %option reentrant bison-bridge bison-locations %option never-interactive +%top{ + #include +} + %{ /** * \file From a9013e70fb82a5dc31ebf4e7e2b3eb3ad5e7823a Mon Sep 17 00:00:00 2001 From: rturrado <68099809+rturrado@users.noreply.github.com> Date: Tue, 19 Sep 2023 12:01:25 +0200 Subject: [PATCH 13/28] WIP. [skip ci] - src/CMakeLists.txt: - Moved find_package calls to the beginning of the Packages section. - Updated to the last version of tree-gen, which allows to print nodes using fmt. - Added target include directories as debug info. - test/v1x/CMakeLists.txt: temporarily commented out adding of tutorial.cpp. - test/CMakeLists.txt: temporarily commented out adding of v10 and v3x subdirectories. - cqasm-version.cpp: simplified operator<< implementation by using fmt. - parsing.cpp: fixed TestBody code. - res/v1x/toy-v1x-parsing/{ast.golden.txt,input.cq}: removed. - test_cases.txt: cleaned up a bit. --- .../toy-v1x-parsing/mapping/ast.golden.txt | 0 res/v1x/toy-v1x-parsing/mapping/input.cq | 3 - res/v1x/toy-v1x-parsing/test_cases.txt | 105 +++++++----------- scripts/generate_antlr_parser.py | 1 - src/CMakeLists.txt | 40 ++++--- src/cqasm-version.cpp | 12 +- src/v3x/cqasm-parse-helper.cpp | 1 - test/CMakeLists.txt | 4 +- test/v1x/CMakeLists.txt | 2 +- test/v1x/parsing.cpp | 10 +- 10 files changed, 79 insertions(+), 99 deletions(-) delete mode 100644 res/v1x/toy-v1x-parsing/mapping/ast.golden.txt delete mode 100644 res/v1x/toy-v1x-parsing/mapping/input.cq diff --git a/res/v1x/toy-v1x-parsing/mapping/ast.golden.txt b/res/v1x/toy-v1x-parsing/mapping/ast.golden.txt deleted file mode 100644 index e69de29b..00000000 diff --git a/res/v1x/toy-v1x-parsing/mapping/input.cq b/res/v1x/toy-v1x-parsing/mapping/input.cq deleted file mode 100644 index ee1ac059..00000000 --- a/res/v1x/toy-v1x-parsing/mapping/input.cq +++ /dev/null @@ -1,3 +0,0 @@ -version 3 -qubits 3 -map v = q[3] diff --git a/res/v1x/toy-v1x-parsing/test_cases.txt b/res/v1x/toy-v1x-parsing/test_cases.txt index e55936d0..4b26d0c3 100644 --- a/res/v1x/toy-v1x-parsing/test_cases.txt +++ b/res/v1x/toy-v1x-parsing/test_cases.txt @@ -1,62 +1,43 @@ -* fail empty program -* fail something before version blah; version 3 - -* fail OK version, bad token version 3;123abc - - fail OK version, empty qubits version 3;qubits - fail OK version, wrong qubits version 3;qubits 123abc - OK OK version, OK qubits version 3;qubits 3 - - fail empty map version 3;map - fail empty map id version 3;map v - fail empty map id = version 3;map v = - OK OK map integer version 3;map v = 1 - OK OK map float version 3;map v = 3.14 - fail bad map id version 3;map w = v Syntactically correct, not semantically - OK OK map id version 3;map v = 1;map w = v - fail bad map array, no qubits version 3;map v = q[0] Syntactically correct, not semantically - fail bad map array, out of bounds qubit version 3;qubits 3;map v = q[3] Syntactically correct, not semantically - OK OK map array version 3;qubits 3;map v = q[0] - - fail empty var version 3;var - fail empty var id version 3;var v - fail empty var id : version 3;var v : - fail bad var id version 3;var w : v Syntactically correct, not semantically - OK OK var id version 3;map v = 1;var w : v - - fail empty instruction version 3;x - fail bad id version 3;v 1 Syntactically correct, not semantically - fail bad expression version 3;x 1 Syntactically correct, not semantically - fail bad instruction, no qubits version 3;x q[0] Syntactically correct, not semantically - fail bad instruction, out of bounds qubit version 3;qubits 3;x q[3] Syntactically correct, not semantically - OK OK one qubit instruction version 3;qubits 3;x q[0] - OK OK two qubit instruction version 3;qubits 3;h q[0];h q[1];cnot q[0], q[3] - - fail empty instruction expression version 3;qubits 3;x - fail bad instruction expression version 3;qubits 3;x 123abc - fail bad instruction expression integer version 3;qubits 3;x 1 Syntactically correct, not semantically - fail bad instruction expression float version 3;qubits 3;x 3.14 Syntactically correct, not semantically - fail bad instruction expression id version 3;qubits 3;x v Syntactically correct, not semantically - - - fail bad expression list, no second part version 3;qubits 3;h q[0];h q[1];cnot q[0], - fail bad expression list, bad first part version 3;qubits 3;h q[0];h q[1];cnot 123abc, q[0] - fail bad expression list, bad second part version 3;qubits 3;h q[0];h q[1];cnot q[0], 123abc - - Questions: - - What instructions are supported for the toy version? x, y, z, h? measure? - - Test implementation: - - Have a look at how it is done for v1x - - For semantic issues we probably need to do the checks at the AST level, kind of integration test - - However, I don't see why we cannot work with strings instead of files - - - We could just copy/paste, initially, test/v1x/parsing.cpp, simplifying it, removing instructions and functions - - Even comparing files. But, as I said above, I'd rather compare data structures (e.g. the AST) than files - - - The important stuff for this task would be to implement v3x/cqasm-parse-helper.cpp, - first refactor it like src/cqasm-version.cpp, - then make it call ANTLR - - All the AST stuff I would just copy/paste it from v1 - - - For this task, I will need help from Hans, maybe more than from Pablo +fail empty program +fail something before version blah; version 3 + +fail OK version, bad token version 3;123abc + +fail OK version, empty qubits version 3;qubits +fail OK version, wrong qubits version 3;qubits 123abc +OK OK version, OK qubits version 3;qubits 3 + +fail empty map version 3;map +fail empty map id version 3;map v +fail empty map id = version 3;map v = +OK OK map integer version 3;map v = 1 +OK OK map float version 3;map v = 3.14 +fail bad map id version 3;map w = v Syntactically correct, not semantically +OK OK map id version 3;map v = 1;map w = v +fail bad map array, no qubits version 3;map v = q[0] Syntactically correct, not semantically +fail bad map array, out of bounds qubit version 3;qubits 3;map v = q[3] Syntactically correct, not semantically +OK OK map array version 3;qubits 3;map v = q[0] + +fail empty var version 3;var +fail empty var id version 3;var v +fail empty var id : version 3;var v : +fail bad var id version 3;var w : v Syntactically correct, not semantically +OK OK var id version 3;map v = 1;var w : v + +fail empty instruction version 3;x +fail bad id version 3;v 1 Syntactically correct, not semantically +fail bad expression version 3;x 1 Syntactically correct, not semantically +fail bad instruction, no qubits version 3;x q[0] Syntactically correct, not semantically +fail bad instruction, out of bounds qubit version 3;qubits 3;x q[3] Syntactically correct, not semantically +OK OK one qubit instruction version 3;qubits 3;x q[0] +OK OK two qubit instruction version 3;qubits 3;h q[0];h q[1];cnot q[0], q[3] + +fail empty instruction expression version 3;qubits 3;x +fail bad instruction expression version 3;qubits 3;x 123abc +fail bad instruction expression integer version 3;qubits 3;x 1 Syntactically correct, not semantically +fail bad instruction expression float version 3;qubits 3;x 3.14 Syntactically correct, not semantically +fail bad instruction expression id version 3;qubits 3;x v Syntactically correct, not semantically + +fail bad expression list, no second part version 3;qubits 3;h q[0];h q[1];cnot q[0], +fail bad expression list, bad first part version 3;qubits 3;h q[0];h q[1];cnot 123abc, q[0] +fail bad expression list, bad second part version 3;qubits 3;h q[0];h q[1];cnot q[0], 123abc diff --git a/scripts/generate_antlr_parser.py b/scripts/generate_antlr_parser.py index f94e34cf..92a5b538 100644 --- a/scripts/generate_antlr_parser.py +++ b/scripts/generate_antlr_parser.py @@ -54,7 +54,6 @@ def generate_antlr_parser(input_folder, output_folder, antlr_jar_file_path): "java", "-jar", antlr_jar_file_path, - "-no-listener", "-visitor", "-Xexact-output-dir", "-o", diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index f6d29fc1..41346827 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -28,12 +28,22 @@ set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON) # Packages #------------------------------------------------------------------------------- +find_package(antlr4-runtime) +find_package(BISON 3.0) +find_package(FLEX 2.6.4) +if(WIN32) + set(flex_win_compat --wincompat) +else() + set(flex_win_compat) +endif() +find_package(Python3 REQUIRED) + include(FetchContent) # tree-gen, a custom utility to generate classes for typed tree-like structures and enums with variants containing data. # This exposes the generate_tree() function. FetchContent_Declare(tree-gen GIT_REPOSITORY https://github.com/QuTech-Delft/tree-gen.git - GIT_TAG "8a1f25dee6d5529398676ec83a18f89786049ae8" + GIT_TAG "71e5acdf6fd67d6800042aac848e710f99cc79f7" ) FetchContent_MakeAvailable(tree-gen) @@ -43,18 +53,6 @@ FetchContent_MakeAvailable(tree-gen) # This exposes the generate_funcs() function, which should be called once with the header and source file paths. add_subdirectory(func-gen) -# Require flex/bison; if not installed, this will try to build from source. -find_package(BISON 3.0) -find_package(FLEX 2.6.4) -if(WIN32) - set(flex_win_compat --wincompat) -else() - set(flex_win_compat) -endif() - -find_package(antlr4-runtime REQUIRED) -find_package(Python3 REQUIRED) - #------------------------------------------------------------------------------- # cQASM common code generation and inclusion #------------------------------------------------------------------------------- @@ -219,7 +217,7 @@ target_include_directories(cqasm-lib-obj PUBLIC "${CMAKE_CURRENT_BINARY_DIR}/" PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/../include/" PUBLIC "${CMAKE_CURRENT_BINARY_DIR}/../include/" - PRIVATE "${antlr4-runtime_INCLUDE_DIR}" + PUBLIC "${antlr4-runtime_INCLUDE_DIRS}" ) target_compile_features(cqasm-lib-obj PUBLIC @@ -273,6 +271,20 @@ target_link_libraries(cqasm PUBLIC $ ) +#------------------------------------------------------------------------------- +# Debug info +#------------------------------------------------------------------------------- + +message(STATUS + "[${PROJECT_NAME}] Target include directories:\n" + " TREE_LIB_PRIVATE_INCLUDE: ${TREE_LIB_PRIVATE_INCLUDE}\n" + " TREE_LIB_PUBLIC_INCLUDE: ${TREE_LIB_PUBLIC_INCLUDE}\n" + " CMAKE_CURRENT_BINARY_DIR: ${CMAKE_CURRENT_BINARY_DIR}\n" + " CMAKE_CURRENT_SOURCE_DIR/../include/: ${CMAKE_CURRENT_SOURCE_DIR}/../include/\n" + " CMAKE_CURRENT_BINARY_DIR/../include/: ${CMAKE_CURRENT_BINARY_DIR}/../include/\n" + " antlr4-runtime_INCLUDE_DIRS: ${antlr4-runtime_INCLUDE_DIRS}\n" +) + #------------------------------------------------------------------------------- # Install instructions #------------------------------------------------------------------------------- diff --git a/src/cqasm-version.cpp b/src/cqasm-version.cpp index d1e3933a..2e80a00a 100644 --- a/src/cqasm-version.cpp +++ b/src/cqasm-version.cpp @@ -7,6 +7,7 @@ #include "cqasm-version-parser.hpp" #include "cqasm-version-lexer.hpp" +#include #include namespace cqasm::version { @@ -74,16 +75,7 @@ int Version::compare(const std::string &other) const { * Stream << overload for version nodes. */ std::ostream &operator<<(std::ostream &os, const Version &object) { - bool first = true; - for (auto item : object) { - if (first) { - first = false; - } else { - os << "."; - } - os << item; - } - return os; + return os << fmt::format("{}", fmt::join(object, ".")); } diff --git a/src/v3x/cqasm-parse-helper.cpp b/src/v3x/cqasm-parse-helper.cpp index e3d26953..52f49d7f 100644 --- a/src/v3x/cqasm-parse-helper.cpp +++ b/src/v3x/cqasm-parse-helper.cpp @@ -45,7 +45,6 @@ ScannerAntlrFile::ScannerAntlrFile(std::unique_ptr build_ throw error::AnalysisError("ScannerAntlrFile couldn't access file."); } } - ScannerAntlrFile::~ScannerAntlrFile() {} void ScannerAntlrFile::parse(const std::string &file_name, cqasm::v1x::parser::ParseResult &result) { diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 907d53ca..44a0e589 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -5,10 +5,10 @@ add_executable(${PROJECT_NAME}_test) # Subdirectories if(LIBQASM_COMPAT) - add_subdirectory(v10) + #add_subdirectory(v10) endif() add_subdirectory(v1x) -add_subdirectory(v3x) +#add_subdirectory(v3x) # Sources target_sources(${PROJECT_NAME}_test PRIVATE diff --git a/test/v1x/CMakeLists.txt b/test/v1x/CMakeLists.txt index 4abf3c73..501ed712 100644 --- a/test/v1x/CMakeLists.txt +++ b/test/v1x/CMakeLists.txt @@ -1,4 +1,4 @@ target_sources(${PROJECT_NAME}_test PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/parsing.cpp" - "${CMAKE_CURRENT_SOURCE_DIR}/tutorial.cpp" + #"${CMAKE_CURRENT_SOURCE_DIR}/tutorial.cpp" ) diff --git a/test/v1x/parsing.cpp b/test/v1x/parsing.cpp index 306facad..aad0a94d 100644 --- a/test/v1x/parsing.cpp +++ b/test/v1x/parsing.cpp @@ -62,12 +62,12 @@ class ParsingTest : public ::testing::Test { cq1x::parser::ParseResult parse_result{}; auto version = cqasm::version::parse_string(input, "input.cq"); - if (version <= cqasm::version::Version("1.2")) { + if (auto compare_result = version.compare("1.2"); compare_result <= 0) { parse_result = cq1x::parser::parse_string(input, "input.cq"); - } else if (version == cqasm::version::Version("3.0")) { + } else if (auto compare_result = version.compare("3.0"); compare_result == 0) { parse_result = cq3x::parser::parse_string(input, "input.cq"); } else { - parse_result.errors.push_back(fmt::format("detected version ", version)); + parse_result.errors.push_back(fmt::format("detected version {}", version)); } // Check the parse result @@ -272,6 +272,6 @@ void register_v1x_tests(const fs::path& subdir) { } void register_v1x_tests() { - register_v1x_tests("parsing"); - //register_v1x_tests("toy-v1x-parsing"); + //register_v1x_tests("parsing"); + register_v1x_tests("toy-v1x-parsing"); } From 37eef7b798a8314ae5ea5c4220ecb13b956086d2 Mon Sep 17 00:00:00 2001 From: rturrado <68099809+rturrado@users.noreply.github.com> Date: Wed, 20 Sep 2023 19:11:51 +0200 Subject: [PATCH 14/28] Updated v3x parser code (ParseHelper, ScannerAntlr, AST builder, error listener). - src/CMakeLists.txt: - Added 'find_package(fmt 10.1.1)'. - Updated to a version of tree-gen that doesn't fetch fmt if the package is found. - v3x/cqasm-parse-helper: - Changed ScannerAntlr to have a customer error listener as a dependency injection. - Changed the 'parse' API to return a ParseResult. Ideally, a ParseResult should be an interface containing a pointer to a generic AST, not to a tree-gen AST. - v3x/BuildTreeGenAstVisitor: fixed so that all tests are now run. - v3x/CustomErrorListener: added so that the parser throws an exception instead of just printing to standard output. - res/v1x/toy-v1x-parsing: - All implemented tests pass the syntax analysis check. - Updated test_cases.txt. Note: - conanfile.py: temporarily commented out a few lines to be able to work with CLion's Conan Plugin. - test/CMakeLists.txt: temporarily commented out version tests. - test/v1x/parsing.cpp: temporarily commented out semantic checks. --- conanfile.py | 8 +- ...AstVisitor.h => BuildCustomAstVisitor.hpp} | 3 +- ...stVisitor.h => BuildTreeGenAstVisitor.hpp} | 3 +- include/v3x/CustomErrorListener.hpp | 21 +++ include/v3x/cqasm-parse-helper.hpp | 31 ++-- .../out_of_bounds_index/ast.golden.txt | 43 +++++ .../input.cq | 2 +- .../expression/qubits_3__x/ast.golden.txt | 0 .../expression/qubits_3__x/input.cq | 3 - .../expression/qubits_3__x_1/ast.golden.txt | 0 .../qubits_3__x_123abc/ast.golden.txt | 0 .../qubits_3__x_3_14/ast.golden.txt | 0 .../expression/qubits_3__x_3_14/input.cq | 3 - .../expression/qubits_3__x_v/ast.golden.txt | 0 .../expression/qubits_3__x_v/input.cq | 3 - .../bad_first_part/ast.golden.txt | 2 + .../expression_list/bad_first_part/input.cq | 2 +- .../bad_second_part/ast.golden.txt | 2 + .../expression_list/bad_second_part/input.cq | 2 +- .../no_second_part/ast.golden.txt | 2 + .../expression_list/no_second_part/input.cq | 5 +- .../ast.golden.txt | 160 ++++++++++++++++++ .../qubits_3__h_q0__h_q1__cnot_q0_q1/input.cq | 2 +- .../instruction/qubits_3__x_q0/ast.golden.txt | 60 +++++++ .../instruction/qubits_3__x_q0/input.cq | 2 +- .../instruction/qubits_3__x_q3/ast.golden.txt | 0 .../instruction/qubits_3__x_q3/input.cq | 3 - .../instruction/v_1/ast.golden.txt | 39 +++++ .../toy-v1x-parsing/instruction/v_1/input.cq | 2 +- .../instruction/x/ast.golden.txt | 2 + .../toy-v1x-parsing/instruction/x/input.cq | 2 +- .../instruction/x_1/ast.golden.txt | 39 +++++ .../toy-v1x-parsing/instruction/x_1/input.cq | 2 +- .../instruction/x_123abc/ast.golden.txt | 2 + .../x_123abc}/input.cq | 1 - .../instruction/x_3_14/ast.golden.txt | 43 +++++ .../instruction/x_3_14/input.cq | 2 + .../instruction/x_q0/ast.golden.txt | 56 ++++++ .../toy-v1x-parsing/instruction/x_q0/input.cq | 2 +- .../instruction/x_v/ast.golden.txt | 43 +++++ .../x_v}/input.cq | 2 +- .../mapping/map/ast.golden.txt | 2 + res/v1x/toy-v1x-parsing/mapping/map/input.cq | 2 +- .../mapping/map_v/ast.golden.txt | 2 + .../toy-v1x-parsing/mapping/map_v/input.cq | 2 +- .../mapping/map_v_1/ast.golden.txt | 29 ++++ .../toy-v1x-parsing/mapping/map_v_1/input.cq | 2 +- .../mapping/map_v_1__map_w_v/ast.golden.txt | 42 +++++ .../mapping/map_v_1__map_w_v/input.cq | 2 +- .../mapping/map_v_3_14/ast.golden.txt | 29 ++++ .../mapping/map_v_3_14/input.cq | 2 +- .../mapping/map_v_equals/ast.golden.txt | 2 + .../mapping/map_v_equals/input.cq | 2 +- .../mapping/map_v_q0/ast.golden.txt | 46 +++++ .../toy-v1x-parsing/mapping/map_v_q0/input.cq | 2 +- .../mapping/map_w_v/ast.golden.txt | 29 ++++ .../toy-v1x-parsing/mapping/map_w_v/input.cq | 2 +- .../mapping/qubits_3__map_v_q0/ast.golden.txt | 50 ++++++ .../mapping/qubits_3__map_v_q0/input.cq | 2 +- .../mapping/qubits_3__map_v_q3/ast.golden.txt | 0 .../mapping/qubits_3__map_v_q3/input.cq | 0 .../bad_token_after_version/ast.golden.txt | 2 + .../program/empty/ast.golden.txt | 0 .../toy-v1x-parsing/program/empty/input.cq | 0 .../something_before_version/ast.golden.txt | 0 .../qubits/qubits_3/ast.golden.txt | 19 +++ .../toy-v1x-parsing/qubits/qubits_3/input.cq | 2 +- .../qubits/qubits_abc/ast.golden.txt | 19 +++ .../qubits/qubits_abc/input.cq | 2 +- .../qubits/qubits_no_number/ast.golden.txt | 2 + .../qubits/qubits_no_number/input.cq | 2 +- res/v1x/toy-v1x-parsing/test_cases.txt | 69 ++++---- .../variable/map_v_1__var_w_v/ast.golden.txt | 42 +++++ .../variable/var_v/ast.golden.txt | 2 + .../variable/var_v_colon/ast.golden.txt | 2 + .../variable/var_w_v/ast.golden.txt | 33 ++++ .../toy-v1x-parsing/variable/var_w_v/input.cq | 1 + scripts/generate_antlr_parser.py | 1 + src/CMakeLists.txt | 3 +- src/v3x/BuildTreeGenAstVisitor.cpp | 94 +++++----- src/v3x/CMakeLists.txt | 1 + src/v3x/CqasmParser.g4 | 4 +- src/v3x/CustomErrorListener.cpp | 18 ++ src/v3x/cqasm-parse-helper.cpp | 71 ++++---- test/CMakeLists.txt | 2 +- test/v1x/parsing.cpp | 2 + 86 files changed, 1076 insertions(+), 165 deletions(-) rename include/v3x/{BuildCustomAstVisitor.h => BuildCustomAstVisitor.hpp} (85%) rename include/v3x/{BuildTreeGenAstVisitor.h => BuildTreeGenAstVisitor.hpp} (89%) create mode 100644 include/v3x/CustomErrorListener.hpp create mode 100644 res/v1x/toy-v1x-parsing/expression/out_of_bounds_index/ast.golden.txt rename res/v1x/toy-v1x-parsing/expression/{qubits_3__x_1 => out_of_bounds_index}/input.cq (76%) delete mode 100644 res/v1x/toy-v1x-parsing/expression/qubits_3__x/ast.golden.txt delete mode 100644 res/v1x/toy-v1x-parsing/expression/qubits_3__x/input.cq delete mode 100644 res/v1x/toy-v1x-parsing/expression/qubits_3__x_1/ast.golden.txt delete mode 100644 res/v1x/toy-v1x-parsing/expression/qubits_3__x_123abc/ast.golden.txt delete mode 100644 res/v1x/toy-v1x-parsing/expression/qubits_3__x_3_14/ast.golden.txt delete mode 100644 res/v1x/toy-v1x-parsing/expression/qubits_3__x_3_14/input.cq delete mode 100644 res/v1x/toy-v1x-parsing/expression/qubits_3__x_v/ast.golden.txt delete mode 100644 res/v1x/toy-v1x-parsing/expression/qubits_3__x_v/input.cq delete mode 100644 res/v1x/toy-v1x-parsing/instruction/qubits_3__x_q3/ast.golden.txt delete mode 100644 res/v1x/toy-v1x-parsing/instruction/qubits_3__x_q3/input.cq create mode 100644 res/v1x/toy-v1x-parsing/instruction/x_123abc/ast.golden.txt rename res/v1x/toy-v1x-parsing/{expression/qubits_3__x_123abc => instruction/x_123abc}/input.cq (66%) create mode 100644 res/v1x/toy-v1x-parsing/instruction/x_3_14/ast.golden.txt create mode 100644 res/v1x/toy-v1x-parsing/instruction/x_3_14/input.cq create mode 100644 res/v1x/toy-v1x-parsing/instruction/x_v/ast.golden.txt rename res/v1x/toy-v1x-parsing/{program/something_before_version => instruction/x_v}/input.cq (66%) delete mode 100644 res/v1x/toy-v1x-parsing/mapping/qubits_3__map_v_q3/ast.golden.txt delete mode 100644 res/v1x/toy-v1x-parsing/mapping/qubits_3__map_v_q3/input.cq delete mode 100644 res/v1x/toy-v1x-parsing/program/empty/ast.golden.txt delete mode 100644 res/v1x/toy-v1x-parsing/program/empty/input.cq delete mode 100644 res/v1x/toy-v1x-parsing/program/something_before_version/ast.golden.txt create mode 100644 src/v3x/CustomErrorListener.cpp diff --git a/conanfile.py b/conanfile.py index 9a71371f..3e96ae79 100644 --- a/conanfile.py +++ b/conanfile.py @@ -60,8 +60,8 @@ def build_requirements(self): self.tool_requires("bison/3.8.2") if self.settings.arch != "armv8": self.tool_requires("zulu-openjdk/11.0.19") - if self.options.build_tests: - self.requires("gtest/1.14.0") + #if self.options.build_tests: + self.requires("gtest/1.14.0") def requirements(self): self.requires("antlr4-cppruntime/4.13.0") @@ -87,8 +87,8 @@ def layout(self): self.cpp.build.libdirs = ["."] def generate(self): - deps = CMakeDeps(self) - deps.generate() + #deps = CMakeDeps(self) + #deps.generate() tc = CMakeToolchain(self) tc.variables["ASAN_ENABLED"] = self.options.asan_enabled tc.variables["LIBQASM_BUILD_PYTHON"] = self.options.build_python diff --git a/include/v3x/BuildCustomAstVisitor.h b/include/v3x/BuildCustomAstVisitor.hpp similarity index 85% rename from include/v3x/BuildCustomAstVisitor.h rename to include/v3x/BuildCustomAstVisitor.hpp index d31de02d..774a934a 100644 --- a/include/v3x/BuildCustomAstVisitor.h +++ b/include/v3x/BuildCustomAstVisitor.hpp @@ -10,8 +10,9 @@ namespace cqasm::v3x::parser { class BuildCustomAstVisitor : public CqasmParserVisitor { public: - std::any visitProgram(CqasmParser::ProgramContext *context) = 0; + virtual std::any visitProgram(CqasmParser::ProgramContext *context) = 0; std::any visitVersion(CqasmParser::VersionContext *context) = 0; + std::any visitQubits(CqasmParser::QubitsContext *context) = 0; std::any visitStatement(CqasmParser::StatementContext *context) = 0; std::any visitMapping(CqasmParser::MappingContext *context) = 0; std::any visitVariable(CqasmParser::VariableContext *context) = 0; diff --git a/include/v3x/BuildTreeGenAstVisitor.h b/include/v3x/BuildTreeGenAstVisitor.hpp similarity index 89% rename from include/v3x/BuildTreeGenAstVisitor.h rename to include/v3x/BuildTreeGenAstVisitor.hpp index f9d9c833..3bf7ee01 100644 --- a/include/v3x/BuildTreeGenAstVisitor.h +++ b/include/v3x/BuildTreeGenAstVisitor.hpp @@ -1,6 +1,6 @@ #pragma once -#include "v3x/BuildCustomAstVisitor.h" +#include "v3x/BuildCustomAstVisitor.hpp" #include "v3x/CqasmParser.h" #include "v3x/CqasmParserVisitor.h" @@ -13,6 +13,7 @@ class BuildTreeGenAstVisitor : public BuildCustomAstVisitor { public: std::any visitProgram(CqasmParser::ProgramContext *context) override; std::any visitVersion(CqasmParser::VersionContext *context) override; + std::any visitQubits(CqasmParser::QubitsContext *context) override; std::any visitStatement(CqasmParser::StatementContext *context) override; std::any visitMapping(CqasmParser::MappingContext *context) override; std::any visitVariable(CqasmParser::VariableContext *context) override; diff --git a/include/v3x/CustomErrorListener.hpp b/include/v3x/CustomErrorListener.hpp new file mode 100644 index 00000000..4c259840 --- /dev/null +++ b/include/v3x/CustomErrorListener.hpp @@ -0,0 +1,21 @@ +#include +#include +#include + + +namespace cqasm::v3x::parser { + +class CustomErrorListener : public antlr4::BaseErrorListener { + /** + * Name of the file being parsed. + */ + std::string file_name_; +private: + void syntaxError(antlr4::Recognizer *recognizer, antlr4::Token *offendingSymbol, size_t line, + size_t charPositionInLine, const std::string &msg, std::exception_ptr e) override; +public: + explicit CustomErrorListener(const std::string &file_name = "") + : file_name_{ file_name } {} +}; + +} // namespace cqasm::v3x::parser diff --git a/include/v3x/cqasm-parse-helper.hpp b/include/v3x/cqasm-parse-helper.hpp index 07841117..c8fe238a 100644 --- a/include/v3x/cqasm-parse-helper.hpp +++ b/include/v3x/cqasm-parse-helper.hpp @@ -8,11 +8,10 @@ #include "cqasm-annotations.hpp" #include "v1x/cqasm-parse-result.hpp" -#include "v3x/BuildCustomAstVisitor.h" -#include "v3x/BuildTreeGenAstVisitor.h" - -#include "antlr4-runtime/antlr4-runtime.h" +#include "v3x/BuildCustomAstVisitor.hpp" +#include "v3x/CustomErrorListener.hpp" +#include #include // ifstream #include // unique_ptr #include @@ -28,33 +27,37 @@ using SourceLocation = annotations::SourceLocation; struct ScannerAdaptor { virtual ~ScannerAdaptor(); - virtual void parse(const std::string &file_name, cqasm::v1x::parser::ParseResult &result) = 0; + virtual cqasm::v1x::parser::ParseResult parse() = 0; }; class ScannerAntlr : public ScannerAdaptor { std::unique_ptr build_visitor_up_; + std::unique_ptr error_listener_up_; protected: - void parse_(antlr4::ANTLRInputStream &is, const std::string &file_name, cqasm::v1x::parser::ParseResult &result); + cqasm::v1x::parser::ParseResult parse_(antlr4::ANTLRInputStream &is); public: - explicit ScannerAntlr(std::unique_ptr build_visitor_up); + explicit ScannerAntlr(std::unique_ptr build_visitor_up, + std::unique_ptr error_listener_up); ~ScannerAntlr() override; - void parse(const std::string &file_name, cqasm::v1x::parser::ParseResult &result) override = 0; + cqasm::v1x::parser::ParseResult parse() override = 0; }; class ScannerAntlrFile : public ScannerAntlr { - std::ifstream ifs_; + std::string file_path_; public: - ScannerAntlrFile(std::unique_ptr build_visitor_up, const std::string &file_path); + ScannerAntlrFile(std::unique_ptr build_visitor_up, + std::unique_ptr error_listener_up, const std::string &file_path); ~ScannerAntlrFile() override; - void parse(const std::string &file_name, cqasm::v1x::parser::ParseResult &result) override; + cqasm::v1x::parser::ParseResult parse() override; }; class ScannerAntlrString : public ScannerAntlr { std::string data_; public: - ScannerAntlrString(std::unique_ptr build_visitor_up, const std::string &data); + ScannerAntlrString(std::unique_ptr build_visitor_up, + std::unique_ptr error_listener_up, const std::string &data); ~ScannerAntlrString() override; - void parse(const std::string &file_name, cqasm::v1x::parser::ParseResult &result) override; + cqasm::v1x::parser::ParseResult parse() override; }; @@ -83,7 +86,7 @@ class ParseHelper { /** * Name of the file being parsed. */ - std::string file_name; + std::string file_name_; public: explicit ParseHelper(std::unique_ptr scanner_up, std::string file_name = ""); diff --git a/res/v1x/toy-v1x-parsing/expression/out_of_bounds_index/ast.golden.txt b/res/v1x/toy-v1x-parsing/expression/out_of_bounds_index/ast.golden.txt new file mode 100644 index 00000000..6a41e6e0 --- /dev/null +++ b/res/v1x/toy-v1x-parsing/expression/out_of_bounds_index/ast.golden.txt @@ -0,0 +1,43 @@ +SUCCESS +Program( + version: < + Version( + items: 3 + ) + > + num_qubits: < + IntegerLiteral( + value: 3 + ) + > + statements: < + StatementList( + items: [ + Bundle( + items: [ + Instruction( + name: < + Identifier( + name: x + ) + > + condition: - + operands: < + ExpressionList( + items: [ + IntegerLiteral( + value: 1 + ) + ] + ) + > + annotations: [] + ) + ] + annotations: [] + ) + ] + ) + > +) + diff --git a/res/v1x/toy-v1x-parsing/expression/qubits_3__x_1/input.cq b/res/v1x/toy-v1x-parsing/expression/out_of_bounds_index/input.cq similarity index 76% rename from res/v1x/toy-v1x-parsing/expression/qubits_3__x_1/input.cq rename to res/v1x/toy-v1x-parsing/expression/out_of_bounds_index/input.cq index 988ca9b5..4a255d1e 100644 --- a/res/v1x/toy-v1x-parsing/expression/qubits_3__x_1/input.cq +++ b/res/v1x/toy-v1x-parsing/expression/out_of_bounds_index/input.cq @@ -1,3 +1,3 @@ version 3 qubits 3 -x 1 +x q[3] \ No newline at end of file diff --git a/res/v1x/toy-v1x-parsing/expression/qubits_3__x/ast.golden.txt b/res/v1x/toy-v1x-parsing/expression/qubits_3__x/ast.golden.txt deleted file mode 100644 index e69de29b..00000000 diff --git a/res/v1x/toy-v1x-parsing/expression/qubits_3__x/input.cq b/res/v1x/toy-v1x-parsing/expression/qubits_3__x/input.cq deleted file mode 100644 index d28e85d7..00000000 --- a/res/v1x/toy-v1x-parsing/expression/qubits_3__x/input.cq +++ /dev/null @@ -1,3 +0,0 @@ -version 3 -qubits 3 -x diff --git a/res/v1x/toy-v1x-parsing/expression/qubits_3__x_1/ast.golden.txt b/res/v1x/toy-v1x-parsing/expression/qubits_3__x_1/ast.golden.txt deleted file mode 100644 index e69de29b..00000000 diff --git a/res/v1x/toy-v1x-parsing/expression/qubits_3__x_123abc/ast.golden.txt b/res/v1x/toy-v1x-parsing/expression/qubits_3__x_123abc/ast.golden.txt deleted file mode 100644 index e69de29b..00000000 diff --git a/res/v1x/toy-v1x-parsing/expression/qubits_3__x_3_14/ast.golden.txt b/res/v1x/toy-v1x-parsing/expression/qubits_3__x_3_14/ast.golden.txt deleted file mode 100644 index e69de29b..00000000 diff --git a/res/v1x/toy-v1x-parsing/expression/qubits_3__x_3_14/input.cq b/res/v1x/toy-v1x-parsing/expression/qubits_3__x_3_14/input.cq deleted file mode 100644 index 5cbaad32..00000000 --- a/res/v1x/toy-v1x-parsing/expression/qubits_3__x_3_14/input.cq +++ /dev/null @@ -1,3 +0,0 @@ -version 3 -qubits 3 -x 3.14 diff --git a/res/v1x/toy-v1x-parsing/expression/qubits_3__x_v/ast.golden.txt b/res/v1x/toy-v1x-parsing/expression/qubits_3__x_v/ast.golden.txt deleted file mode 100644 index e69de29b..00000000 diff --git a/res/v1x/toy-v1x-parsing/expression/qubits_3__x_v/input.cq b/res/v1x/toy-v1x-parsing/expression/qubits_3__x_v/input.cq deleted file mode 100644 index 6d792cfd..00000000 --- a/res/v1x/toy-v1x-parsing/expression/qubits_3__x_v/input.cq +++ /dev/null @@ -1,3 +0,0 @@ -version 3 -qubits 3 -x v diff --git a/res/v1x/toy-v1x-parsing/expression_list/bad_first_part/ast.golden.txt b/res/v1x/toy-v1x-parsing/expression_list/bad_first_part/ast.golden.txt index e69de29b..9158ecf8 100644 --- a/res/v1x/toy-v1x-parsing/expression_list/bad_first_part/ast.golden.txt +++ b/res/v1x/toy-v1x-parsing/expression_list/bad_first_part/ast.golden.txt @@ -0,0 +1,2 @@ +ERROR +input.cq:5:11: extraneous input ',' expecting {INTEGER_LITERAL, FLOAT_LITERAL, IDENTIFIER} diff --git a/res/v1x/toy-v1x-parsing/expression_list/bad_first_part/input.cq b/res/v1x/toy-v1x-parsing/expression_list/bad_first_part/input.cq index 852d0880..b07ef036 100644 --- a/res/v1x/toy-v1x-parsing/expression_list/bad_first_part/input.cq +++ b/res/v1x/toy-v1x-parsing/expression_list/bad_first_part/input.cq @@ -2,4 +2,4 @@ version 3 qubits 3 h q[0] h q[1] -cnot 123abc, q[0] +cnot 123abc, q[0] \ No newline at end of file diff --git a/res/v1x/toy-v1x-parsing/expression_list/bad_second_part/ast.golden.txt b/res/v1x/toy-v1x-parsing/expression_list/bad_second_part/ast.golden.txt index e69de29b..66c82bf9 100644 --- a/res/v1x/toy-v1x-parsing/expression_list/bad_second_part/ast.golden.txt +++ b/res/v1x/toy-v1x-parsing/expression_list/bad_second_part/ast.golden.txt @@ -0,0 +1,2 @@ +ERROR +input.cq:5:17: mismatched input '' expecting {INTEGER_LITERAL, FLOAT_LITERAL, IDENTIFIER} diff --git a/res/v1x/toy-v1x-parsing/expression_list/bad_second_part/input.cq b/res/v1x/toy-v1x-parsing/expression_list/bad_second_part/input.cq index 5ebbe954..0277e85d 100644 --- a/res/v1x/toy-v1x-parsing/expression_list/bad_second_part/input.cq +++ b/res/v1x/toy-v1x-parsing/expression_list/bad_second_part/input.cq @@ -2,4 +2,4 @@ version 3 qubits 3 h q[0] h q[1] -cnot q[0], 123abc +cnot q[0], 123abc \ No newline at end of file diff --git a/res/v1x/toy-v1x-parsing/expression_list/no_second_part/ast.golden.txt b/res/v1x/toy-v1x-parsing/expression_list/no_second_part/ast.golden.txt index e69de29b..cf5f7ac9 100644 --- a/res/v1x/toy-v1x-parsing/expression_list/no_second_part/ast.golden.txt +++ b/res/v1x/toy-v1x-parsing/expression_list/no_second_part/ast.golden.txt @@ -0,0 +1,2 @@ +ERROR +input.cq:5:10: mismatched input '' expecting {INTEGER_LITERAL, FLOAT_LITERAL, IDENTIFIER} diff --git a/res/v1x/toy-v1x-parsing/expression_list/no_second_part/input.cq b/res/v1x/toy-v1x-parsing/expression_list/no_second_part/input.cq index 88d54d76..1eb112e6 100644 --- a/res/v1x/toy-v1x-parsing/expression_list/no_second_part/input.cq +++ b/res/v1x/toy-v1x-parsing/expression_list/no_second_part/input.cq @@ -1,4 +1,5 @@ version 3 qubits 3 -h q[0];h q[1] -cnot q[0], +h q[0] +h q[1] +cnot q[0], \ No newline at end of file diff --git a/res/v1x/toy-v1x-parsing/instruction/qubits_3__h_q0__h_q1__cnot_q0_q1/ast.golden.txt b/res/v1x/toy-v1x-parsing/instruction/qubits_3__h_q0__h_q1__cnot_q0_q1/ast.golden.txt index e69de29b..118799a5 100644 --- a/res/v1x/toy-v1x-parsing/instruction/qubits_3__h_q0__h_q1__cnot_q0_q1/ast.golden.txt +++ b/res/v1x/toy-v1x-parsing/instruction/qubits_3__h_q0__h_q1__cnot_q0_q1/ast.golden.txt @@ -0,0 +1,160 @@ +SUCCESS +Program( + version: < + Version( + items: 3 + ) + > + num_qubits: < + IntegerLiteral( + value: 3 + ) + > + statements: < + StatementList( + items: [ + Bundle( + items: [ + Instruction( + name: < + Identifier( + name: h + ) + > + condition: - + operands: < + ExpressionList( + items: [ + Index( + expr: < + Identifier( + name: q + ) + > + indices: < + IndexList( + items: [ + IndexItem( + index: < + IntegerLiteral( + value: 0 + ) + > + ) + ] + ) + > + ) + ] + ) + > + annotations: [] + ) + ] + annotations: [] + ) + Bundle( + items: [ + Instruction( + name: < + Identifier( + name: h + ) + > + condition: - + operands: < + ExpressionList( + items: [ + Index( + expr: < + Identifier( + name: q + ) + > + indices: < + IndexList( + items: [ + IndexItem( + index: < + IntegerLiteral( + value: 1 + ) + > + ) + ] + ) + > + ) + ] + ) + > + annotations: [] + ) + ] + annotations: [] + ) + Bundle( + items: [ + Instruction( + name: < + Identifier( + name: cnot + ) + > + condition: - + operands: < + ExpressionList( + items: [ + Index( + expr: < + Identifier( + name: q + ) + > + indices: < + IndexList( + items: [ + IndexItem( + index: < + IntegerLiteral( + value: 0 + ) + > + ) + ] + ) + > + ) + Index( + expr: < + Identifier( + name: q + ) + > + indices: < + IndexList( + items: [ + IndexItem( + index: < + IntegerLiteral( + value: 1 + ) + > + ) + ] + ) + > + ) + ] + ) + > + annotations: [] + ) + ] + annotations: [] + ) + ] + ) + > +) + diff --git a/res/v1x/toy-v1x-parsing/instruction/qubits_3__h_q0__h_q1__cnot_q0_q1/input.cq b/res/v1x/toy-v1x-parsing/instruction/qubits_3__h_q0__h_q1__cnot_q0_q1/input.cq index b9646513..b8791f59 100644 --- a/res/v1x/toy-v1x-parsing/instruction/qubits_3__h_q0__h_q1__cnot_q0_q1/input.cq +++ b/res/v1x/toy-v1x-parsing/instruction/qubits_3__h_q0__h_q1__cnot_q0_q1/input.cq @@ -2,4 +2,4 @@ version 3 qubits 3 h q[0] h q[1] -cnot q[0], q[1] +cnot q[0], q[1] \ No newline at end of file diff --git a/res/v1x/toy-v1x-parsing/instruction/qubits_3__x_q0/ast.golden.txt b/res/v1x/toy-v1x-parsing/instruction/qubits_3__x_q0/ast.golden.txt index e69de29b..b749fc84 100644 --- a/res/v1x/toy-v1x-parsing/instruction/qubits_3__x_q0/ast.golden.txt +++ b/res/v1x/toy-v1x-parsing/instruction/qubits_3__x_q0/ast.golden.txt @@ -0,0 +1,60 @@ +SUCCESS +Program( + version: < + Version( + items: 3 + ) + > + num_qubits: < + IntegerLiteral( + value: 3 + ) + > + statements: < + StatementList( + items: [ + Bundle( + items: [ + Instruction( + name: < + Identifier( + name: x + ) + > + condition: - + operands: < + ExpressionList( + items: [ + Index( + expr: < + Identifier( + name: q + ) + > + indices: < + IndexList( + items: [ + IndexItem( + index: < + IntegerLiteral( + value: 0 + ) + > + ) + ] + ) + > + ) + ] + ) + > + annotations: [] + ) + ] + annotations: [] + ) + ] + ) + > +) + diff --git a/res/v1x/toy-v1x-parsing/instruction/qubits_3__x_q0/input.cq b/res/v1x/toy-v1x-parsing/instruction/qubits_3__x_q0/input.cq index c7d2954f..15ce8146 100644 --- a/res/v1x/toy-v1x-parsing/instruction/qubits_3__x_q0/input.cq +++ b/res/v1x/toy-v1x-parsing/instruction/qubits_3__x_q0/input.cq @@ -1,3 +1,3 @@ version 3 qubits 3 -x q[3] +x q[0] \ No newline at end of file diff --git a/res/v1x/toy-v1x-parsing/instruction/qubits_3__x_q3/ast.golden.txt b/res/v1x/toy-v1x-parsing/instruction/qubits_3__x_q3/ast.golden.txt deleted file mode 100644 index e69de29b..00000000 diff --git a/res/v1x/toy-v1x-parsing/instruction/qubits_3__x_q3/input.cq b/res/v1x/toy-v1x-parsing/instruction/qubits_3__x_q3/input.cq deleted file mode 100644 index c7d2954f..00000000 --- a/res/v1x/toy-v1x-parsing/instruction/qubits_3__x_q3/input.cq +++ /dev/null @@ -1,3 +0,0 @@ -version 3 -qubits 3 -x q[3] diff --git a/res/v1x/toy-v1x-parsing/instruction/v_1/ast.golden.txt b/res/v1x/toy-v1x-parsing/instruction/v_1/ast.golden.txt index e69de29b..4fa0a781 100644 --- a/res/v1x/toy-v1x-parsing/instruction/v_1/ast.golden.txt +++ b/res/v1x/toy-v1x-parsing/instruction/v_1/ast.golden.txt @@ -0,0 +1,39 @@ +SUCCESS +Program( + version: < + Version( + items: 3 + ) + > + num_qubits: - + statements: < + StatementList( + items: [ + Bundle( + items: [ + Instruction( + name: < + Identifier( + name: v + ) + > + condition: - + operands: < + ExpressionList( + items: [ + IntegerLiteral( + value: 1 + ) + ] + ) + > + annotations: [] + ) + ] + annotations: [] + ) + ] + ) + > +) + diff --git a/res/v1x/toy-v1x-parsing/instruction/v_1/input.cq b/res/v1x/toy-v1x-parsing/instruction/v_1/input.cq index 935b8bab..f5db19c4 100644 --- a/res/v1x/toy-v1x-parsing/instruction/v_1/input.cq +++ b/res/v1x/toy-v1x-parsing/instruction/v_1/input.cq @@ -1,2 +1,2 @@ version 3 -v 1 +v 1 \ No newline at end of file diff --git a/res/v1x/toy-v1x-parsing/instruction/x/ast.golden.txt b/res/v1x/toy-v1x-parsing/instruction/x/ast.golden.txt index e69de29b..116dc73a 100644 --- a/res/v1x/toy-v1x-parsing/instruction/x/ast.golden.txt +++ b/res/v1x/toy-v1x-parsing/instruction/x/ast.golden.txt @@ -0,0 +1,2 @@ +ERROR +input.cq:2:1: mismatched input '' expecting {INTEGER_LITERAL, FLOAT_LITERAL, IDENTIFIER} diff --git a/res/v1x/toy-v1x-parsing/instruction/x/input.cq b/res/v1x/toy-v1x-parsing/instruction/x/input.cq index a30a2073..0374faf3 100644 --- a/res/v1x/toy-v1x-parsing/instruction/x/input.cq +++ b/res/v1x/toy-v1x-parsing/instruction/x/input.cq @@ -1,2 +1,2 @@ version 3 -x +x \ No newline at end of file diff --git a/res/v1x/toy-v1x-parsing/instruction/x_1/ast.golden.txt b/res/v1x/toy-v1x-parsing/instruction/x_1/ast.golden.txt index e69de29b..1b3dc83e 100644 --- a/res/v1x/toy-v1x-parsing/instruction/x_1/ast.golden.txt +++ b/res/v1x/toy-v1x-parsing/instruction/x_1/ast.golden.txt @@ -0,0 +1,39 @@ +SUCCESS +Program( + version: < + Version( + items: 3 + ) + > + num_qubits: - + statements: < + StatementList( + items: [ + Bundle( + items: [ + Instruction( + name: < + Identifier( + name: x + ) + > + condition: - + operands: < + ExpressionList( + items: [ + IntegerLiteral( + value: 1 + ) + ] + ) + > + annotations: [] + ) + ] + annotations: [] + ) + ] + ) + > +) + diff --git a/res/v1x/toy-v1x-parsing/instruction/x_1/input.cq b/res/v1x/toy-v1x-parsing/instruction/x_1/input.cq index 5c2de263..3b947d08 100644 --- a/res/v1x/toy-v1x-parsing/instruction/x_1/input.cq +++ b/res/v1x/toy-v1x-parsing/instruction/x_1/input.cq @@ -1,2 +1,2 @@ version 3 -x 1 +x 1 \ No newline at end of file diff --git a/res/v1x/toy-v1x-parsing/instruction/x_123abc/ast.golden.txt b/res/v1x/toy-v1x-parsing/instruction/x_123abc/ast.golden.txt new file mode 100644 index 00000000..ae1d850e --- /dev/null +++ b/res/v1x/toy-v1x-parsing/instruction/x_123abc/ast.golden.txt @@ -0,0 +1,2 @@ +ERROR +input.cq:3:8: mismatched input '' expecting {INTEGER_LITERAL, FLOAT_LITERAL, IDENTIFIER} diff --git a/res/v1x/toy-v1x-parsing/expression/qubits_3__x_123abc/input.cq b/res/v1x/toy-v1x-parsing/instruction/x_123abc/input.cq similarity index 66% rename from res/v1x/toy-v1x-parsing/expression/qubits_3__x_123abc/input.cq rename to res/v1x/toy-v1x-parsing/instruction/x_123abc/input.cq index e5cc1e28..1882aa24 100644 --- a/res/v1x/toy-v1x-parsing/expression/qubits_3__x_123abc/input.cq +++ b/res/v1x/toy-v1x-parsing/instruction/x_123abc/input.cq @@ -1,3 +1,2 @@ version 3 -qubits 3 x 123abc \ No newline at end of file diff --git a/res/v1x/toy-v1x-parsing/instruction/x_3_14/ast.golden.txt b/res/v1x/toy-v1x-parsing/instruction/x_3_14/ast.golden.txt new file mode 100644 index 00000000..458cdae8 --- /dev/null +++ b/res/v1x/toy-v1x-parsing/instruction/x_3_14/ast.golden.txt @@ -0,0 +1,43 @@ +SUCCESS +Program( + version: < + Version( + items: 3 + ) + > + num_qubits: < + IntegerLiteral( + value: 3 + ) + > + statements: < + StatementList( + items: [ + Bundle( + items: [ + Instruction( + name: < + Identifier( + name: x + ) + > + condition: - + operands: < + ExpressionList( + items: [ + FloatLiteral( + value: 3.14 + ) + ] + ) + > + annotations: [] + ) + ] + annotations: [] + ) + ] + ) + > +) + diff --git a/res/v1x/toy-v1x-parsing/instruction/x_3_14/input.cq b/res/v1x/toy-v1x-parsing/instruction/x_3_14/input.cq new file mode 100644 index 00000000..88bdd048 --- /dev/null +++ b/res/v1x/toy-v1x-parsing/instruction/x_3_14/input.cq @@ -0,0 +1,2 @@ +version 3 +x 3.14 \ No newline at end of file diff --git a/res/v1x/toy-v1x-parsing/instruction/x_q0/ast.golden.txt b/res/v1x/toy-v1x-parsing/instruction/x_q0/ast.golden.txt index e69de29b..6e813098 100644 --- a/res/v1x/toy-v1x-parsing/instruction/x_q0/ast.golden.txt +++ b/res/v1x/toy-v1x-parsing/instruction/x_q0/ast.golden.txt @@ -0,0 +1,56 @@ +SUCCESS +Program( + version: < + Version( + items: 3 + ) + > + num_qubits: - + statements: < + StatementList( + items: [ + Bundle( + items: [ + Instruction( + name: < + Identifier( + name: x + ) + > + condition: - + operands: < + ExpressionList( + items: [ + Index( + expr: < + Identifier( + name: q + ) + > + indices: < + IndexList( + items: [ + IndexItem( + index: < + IntegerLiteral( + value: 0 + ) + > + ) + ] + ) + > + ) + ] + ) + > + annotations: [] + ) + ] + annotations: [] + ) + ] + ) + > +) + diff --git a/res/v1x/toy-v1x-parsing/instruction/x_q0/input.cq b/res/v1x/toy-v1x-parsing/instruction/x_q0/input.cq index 106acce9..1dc8fdda 100644 --- a/res/v1x/toy-v1x-parsing/instruction/x_q0/input.cq +++ b/res/v1x/toy-v1x-parsing/instruction/x_q0/input.cq @@ -1,2 +1,2 @@ version 3 -x q[0] +x q[0] \ No newline at end of file diff --git a/res/v1x/toy-v1x-parsing/instruction/x_v/ast.golden.txt b/res/v1x/toy-v1x-parsing/instruction/x_v/ast.golden.txt new file mode 100644 index 00000000..c5de3cc2 --- /dev/null +++ b/res/v1x/toy-v1x-parsing/instruction/x_v/ast.golden.txt @@ -0,0 +1,43 @@ +SUCCESS +Program( + version: < + Version( + items: 3 + ) + > + num_qubits: < + IntegerLiteral( + value: 3 + ) + > + statements: < + StatementList( + items: [ + Bundle( + items: [ + Instruction( + name: < + Identifier( + name: x + ) + > + condition: - + operands: < + ExpressionList( + items: [ + Identifier( + name: v + ) + ] + ) + > + annotations: [] + ) + ] + annotations: [] + ) + ] + ) + > +) + diff --git a/res/v1x/toy-v1x-parsing/program/something_before_version/input.cq b/res/v1x/toy-v1x-parsing/instruction/x_v/input.cq similarity index 66% rename from res/v1x/toy-v1x-parsing/program/something_before_version/input.cq rename to res/v1x/toy-v1x-parsing/instruction/x_v/input.cq index dbff8824..a55730c7 100644 --- a/res/v1x/toy-v1x-parsing/program/something_before_version/input.cq +++ b/res/v1x/toy-v1x-parsing/instruction/x_v/input.cq @@ -1,2 +1,2 @@ -blah version 3 +x v \ No newline at end of file diff --git a/res/v1x/toy-v1x-parsing/mapping/map/ast.golden.txt b/res/v1x/toy-v1x-parsing/mapping/map/ast.golden.txt index e69de29b..cf853eee 100644 --- a/res/v1x/toy-v1x-parsing/mapping/map/ast.golden.txt +++ b/res/v1x/toy-v1x-parsing/mapping/map/ast.golden.txt @@ -0,0 +1,2 @@ +ERROR +input.cq:2:3: mismatched input '' expecting IDENTIFIER diff --git a/res/v1x/toy-v1x-parsing/mapping/map/input.cq b/res/v1x/toy-v1x-parsing/mapping/map/input.cq index 58bebeaa..3a2cf08a 100644 --- a/res/v1x/toy-v1x-parsing/mapping/map/input.cq +++ b/res/v1x/toy-v1x-parsing/mapping/map/input.cq @@ -1,2 +1,2 @@ version 3 -map +map \ No newline at end of file diff --git a/res/v1x/toy-v1x-parsing/mapping/map_v/ast.golden.txt b/res/v1x/toy-v1x-parsing/mapping/map_v/ast.golden.txt index e69de29b..85f7d8a7 100644 --- a/res/v1x/toy-v1x-parsing/mapping/map_v/ast.golden.txt +++ b/res/v1x/toy-v1x-parsing/mapping/map_v/ast.golden.txt @@ -0,0 +1,2 @@ +ERROR +input.cq:2:5: mismatched input '' expecting '=' diff --git a/res/v1x/toy-v1x-parsing/mapping/map_v/input.cq b/res/v1x/toy-v1x-parsing/mapping/map_v/input.cq index 11719a19..22e6aadd 100644 --- a/res/v1x/toy-v1x-parsing/mapping/map_v/input.cq +++ b/res/v1x/toy-v1x-parsing/mapping/map_v/input.cq @@ -1,2 +1,2 @@ version 3 -map v +map v \ No newline at end of file diff --git a/res/v1x/toy-v1x-parsing/mapping/map_v_1/ast.golden.txt b/res/v1x/toy-v1x-parsing/mapping/map_v_1/ast.golden.txt index e69de29b..e8f9318c 100644 --- a/res/v1x/toy-v1x-parsing/mapping/map_v_1/ast.golden.txt +++ b/res/v1x/toy-v1x-parsing/mapping/map_v_1/ast.golden.txt @@ -0,0 +1,29 @@ +SUCCESS +Program( + version: < + Version( + items: 3 + ) + > + num_qubits: - + statements: < + StatementList( + items: [ + Mapping( + alias: < + Identifier( + name: v + ) + > + expr: < + IntegerLiteral( + value: 1 + ) + > + annotations: [] + ) + ] + ) + > +) + diff --git a/res/v1x/toy-v1x-parsing/mapping/map_v_1/input.cq b/res/v1x/toy-v1x-parsing/mapping/map_v_1/input.cq index 58a5b09b..8f441a8c 100644 --- a/res/v1x/toy-v1x-parsing/mapping/map_v_1/input.cq +++ b/res/v1x/toy-v1x-parsing/mapping/map_v_1/input.cq @@ -1,2 +1,2 @@ version 3 -map v = 1 +map v = 1 \ No newline at end of file diff --git a/res/v1x/toy-v1x-parsing/mapping/map_v_1__map_w_v/ast.golden.txt b/res/v1x/toy-v1x-parsing/mapping/map_v_1__map_w_v/ast.golden.txt index e69de29b..ebd8e092 100644 --- a/res/v1x/toy-v1x-parsing/mapping/map_v_1__map_w_v/ast.golden.txt +++ b/res/v1x/toy-v1x-parsing/mapping/map_v_1__map_w_v/ast.golden.txt @@ -0,0 +1,42 @@ +SUCCESS +Program( + version: < + Version( + items: 3 + ) + > + num_qubits: - + statements: < + StatementList( + items: [ + Mapping( + alias: < + Identifier( + name: v + ) + > + expr: < + IntegerLiteral( + value: 1 + ) + > + annotations: [] + ) + Mapping( + alias: < + Identifier( + name: w + ) + > + expr: < + Identifier( + name: v + ) + > + annotations: [] + ) + ] + ) + > +) + diff --git a/res/v1x/toy-v1x-parsing/mapping/map_v_1__map_w_v/input.cq b/res/v1x/toy-v1x-parsing/mapping/map_v_1__map_w_v/input.cq index 4077eb3b..83c67b70 100644 --- a/res/v1x/toy-v1x-parsing/mapping/map_v_1__map_w_v/input.cq +++ b/res/v1x/toy-v1x-parsing/mapping/map_v_1__map_w_v/input.cq @@ -1,3 +1,3 @@ version 3 map v = 1 -map w = v +map w = v \ No newline at end of file diff --git a/res/v1x/toy-v1x-parsing/mapping/map_v_3_14/ast.golden.txt b/res/v1x/toy-v1x-parsing/mapping/map_v_3_14/ast.golden.txt index e69de29b..3a4fd87e 100644 --- a/res/v1x/toy-v1x-parsing/mapping/map_v_3_14/ast.golden.txt +++ b/res/v1x/toy-v1x-parsing/mapping/map_v_3_14/ast.golden.txt @@ -0,0 +1,29 @@ +SUCCESS +Program( + version: < + Version( + items: 3 + ) + > + num_qubits: - + statements: < + StatementList( + items: [ + Mapping( + alias: < + Identifier( + name: v + ) + > + expr: < + FloatLiteral( + value: 3.14 + ) + > + annotations: [] + ) + ] + ) + > +) + diff --git a/res/v1x/toy-v1x-parsing/mapping/map_v_3_14/input.cq b/res/v1x/toy-v1x-parsing/mapping/map_v_3_14/input.cq index f934b22b..7f7c42fb 100644 --- a/res/v1x/toy-v1x-parsing/mapping/map_v_3_14/input.cq +++ b/res/v1x/toy-v1x-parsing/mapping/map_v_3_14/input.cq @@ -1,2 +1,2 @@ version 3 -map v = 3.14 +map v = 3.14 \ No newline at end of file diff --git a/res/v1x/toy-v1x-parsing/mapping/map_v_equals/ast.golden.txt b/res/v1x/toy-v1x-parsing/mapping/map_v_equals/ast.golden.txt index e69de29b..8854bbd5 100644 --- a/res/v1x/toy-v1x-parsing/mapping/map_v_equals/ast.golden.txt +++ b/res/v1x/toy-v1x-parsing/mapping/map_v_equals/ast.golden.txt @@ -0,0 +1,2 @@ +ERROR +input.cq:2:7: mismatched input '' expecting {INTEGER_LITERAL, FLOAT_LITERAL, IDENTIFIER} diff --git a/res/v1x/toy-v1x-parsing/mapping/map_v_equals/input.cq b/res/v1x/toy-v1x-parsing/mapping/map_v_equals/input.cq index a016fd11..570bfad1 100644 --- a/res/v1x/toy-v1x-parsing/mapping/map_v_equals/input.cq +++ b/res/v1x/toy-v1x-parsing/mapping/map_v_equals/input.cq @@ -1,2 +1,2 @@ version 3 -map v = +map v = \ No newline at end of file diff --git a/res/v1x/toy-v1x-parsing/mapping/map_v_q0/ast.golden.txt b/res/v1x/toy-v1x-parsing/mapping/map_v_q0/ast.golden.txt index e69de29b..24d8c787 100644 --- a/res/v1x/toy-v1x-parsing/mapping/map_v_q0/ast.golden.txt +++ b/res/v1x/toy-v1x-parsing/mapping/map_v_q0/ast.golden.txt @@ -0,0 +1,46 @@ +SUCCESS +Program( + version: < + Version( + items: 3 + ) + > + num_qubits: - + statements: < + StatementList( + items: [ + Mapping( + alias: < + Identifier( + name: v + ) + > + expr: < + Index( + expr: < + Identifier( + name: q + ) + > + indices: < + IndexList( + items: [ + IndexItem( + index: < + IntegerLiteral( + value: 0 + ) + > + ) + ] + ) + > + ) + > + annotations: [] + ) + ] + ) + > +) + diff --git a/res/v1x/toy-v1x-parsing/mapping/map_v_q0/input.cq b/res/v1x/toy-v1x-parsing/mapping/map_v_q0/input.cq index 25af4a2d..47f3361d 100644 --- a/res/v1x/toy-v1x-parsing/mapping/map_v_q0/input.cq +++ b/res/v1x/toy-v1x-parsing/mapping/map_v_q0/input.cq @@ -1,2 +1,2 @@ version 3 -map v = q[0] +map v = q[0] \ No newline at end of file diff --git a/res/v1x/toy-v1x-parsing/mapping/map_w_v/ast.golden.txt b/res/v1x/toy-v1x-parsing/mapping/map_w_v/ast.golden.txt index e69de29b..ae2e976d 100644 --- a/res/v1x/toy-v1x-parsing/mapping/map_w_v/ast.golden.txt +++ b/res/v1x/toy-v1x-parsing/mapping/map_w_v/ast.golden.txt @@ -0,0 +1,29 @@ +SUCCESS +Program( + version: < + Version( + items: 3 + ) + > + num_qubits: - + statements: < + StatementList( + items: [ + Mapping( + alias: < + Identifier( + name: w + ) + > + expr: < + Identifier( + name: v + ) + > + annotations: [] + ) + ] + ) + > +) + diff --git a/res/v1x/toy-v1x-parsing/mapping/map_w_v/input.cq b/res/v1x/toy-v1x-parsing/mapping/map_w_v/input.cq index 6a3075a2..8c844cac 100644 --- a/res/v1x/toy-v1x-parsing/mapping/map_w_v/input.cq +++ b/res/v1x/toy-v1x-parsing/mapping/map_w_v/input.cq @@ -1,2 +1,2 @@ version 3 -map w = v +map w = v \ No newline at end of file diff --git a/res/v1x/toy-v1x-parsing/mapping/qubits_3__map_v_q0/ast.golden.txt b/res/v1x/toy-v1x-parsing/mapping/qubits_3__map_v_q0/ast.golden.txt index e69de29b..524e5bf5 100644 --- a/res/v1x/toy-v1x-parsing/mapping/qubits_3__map_v_q0/ast.golden.txt +++ b/res/v1x/toy-v1x-parsing/mapping/qubits_3__map_v_q0/ast.golden.txt @@ -0,0 +1,50 @@ +SUCCESS +Program( + version: < + Version( + items: 3 + ) + > + num_qubits: < + IntegerLiteral( + value: 3 + ) + > + statements: < + StatementList( + items: [ + Mapping( + alias: < + Identifier( + name: v + ) + > + expr: < + Index( + expr: < + Identifier( + name: q + ) + > + indices: < + IndexList( + items: [ + IndexItem( + index: < + IntegerLiteral( + value: 0 + ) + > + ) + ] + ) + > + ) + > + annotations: [] + ) + ] + ) + > +) + diff --git a/res/v1x/toy-v1x-parsing/mapping/qubits_3__map_v_q0/input.cq b/res/v1x/toy-v1x-parsing/mapping/qubits_3__map_v_q0/input.cq index 6b9c1fd4..f533d8a5 100644 --- a/res/v1x/toy-v1x-parsing/mapping/qubits_3__map_v_q0/input.cq +++ b/res/v1x/toy-v1x-parsing/mapping/qubits_3__map_v_q0/input.cq @@ -1,3 +1,3 @@ version 3 qubits 3 -map v = q[0] +map v = q[0] \ No newline at end of file diff --git a/res/v1x/toy-v1x-parsing/mapping/qubits_3__map_v_q3/ast.golden.txt b/res/v1x/toy-v1x-parsing/mapping/qubits_3__map_v_q3/ast.golden.txt deleted file mode 100644 index e69de29b..00000000 diff --git a/res/v1x/toy-v1x-parsing/mapping/qubits_3__map_v_q3/input.cq b/res/v1x/toy-v1x-parsing/mapping/qubits_3__map_v_q3/input.cq deleted file mode 100644 index e69de29b..00000000 diff --git a/res/v1x/toy-v1x-parsing/program/bad_token_after_version/ast.golden.txt b/res/v1x/toy-v1x-parsing/program/bad_token_after_version/ast.golden.txt index e69de29b..facc4901 100644 --- a/res/v1x/toy-v1x-parsing/program/bad_token_after_version/ast.golden.txt +++ b/res/v1x/toy-v1x-parsing/program/bad_token_after_version/ast.golden.txt @@ -0,0 +1,2 @@ +ERROR +input.cq:2:0: extraneous input '123' expecting {, 'qubits', 'map', 'var', IDENTIFIER} diff --git a/res/v1x/toy-v1x-parsing/program/empty/ast.golden.txt b/res/v1x/toy-v1x-parsing/program/empty/ast.golden.txt deleted file mode 100644 index e69de29b..00000000 diff --git a/res/v1x/toy-v1x-parsing/program/empty/input.cq b/res/v1x/toy-v1x-parsing/program/empty/input.cq deleted file mode 100644 index e69de29b..00000000 diff --git a/res/v1x/toy-v1x-parsing/program/something_before_version/ast.golden.txt b/res/v1x/toy-v1x-parsing/program/something_before_version/ast.golden.txt deleted file mode 100644 index e69de29b..00000000 diff --git a/res/v1x/toy-v1x-parsing/qubits/qubits_3/ast.golden.txt b/res/v1x/toy-v1x-parsing/qubits/qubits_3/ast.golden.txt index e69de29b..88a04a39 100644 --- a/res/v1x/toy-v1x-parsing/qubits/qubits_3/ast.golden.txt +++ b/res/v1x/toy-v1x-parsing/qubits/qubits_3/ast.golden.txt @@ -0,0 +1,19 @@ +SUCCESS +Program( + version: < + Version( + items: 3 + ) + > + num_qubits: < + IntegerLiteral( + value: 3 + ) + > + statements: < + StatementList( + items: [] + ) + > +) + diff --git a/res/v1x/toy-v1x-parsing/qubits/qubits_3/input.cq b/res/v1x/toy-v1x-parsing/qubits/qubits_3/input.cq index 5527f5c1..66a75535 100644 --- a/res/v1x/toy-v1x-parsing/qubits/qubits_3/input.cq +++ b/res/v1x/toy-v1x-parsing/qubits/qubits_3/input.cq @@ -1,2 +1,2 @@ version 3 -qubits 3 +qubits 3 \ No newline at end of file diff --git a/res/v1x/toy-v1x-parsing/qubits/qubits_abc/ast.golden.txt b/res/v1x/toy-v1x-parsing/qubits/qubits_abc/ast.golden.txt index e69de29b..2cea5ee1 100644 --- a/res/v1x/toy-v1x-parsing/qubits/qubits_abc/ast.golden.txt +++ b/res/v1x/toy-v1x-parsing/qubits/qubits_abc/ast.golden.txt @@ -0,0 +1,19 @@ +SUCCESS +Program( + version: < + Version( + items: 3 + ) + > + num_qubits: < + Identifier( + name: abc + ) + > + statements: < + StatementList( + items: [] + ) + > +) + diff --git a/res/v1x/toy-v1x-parsing/qubits/qubits_abc/input.cq b/res/v1x/toy-v1x-parsing/qubits/qubits_abc/input.cq index 45aa3751..2aa8f2bf 100644 --- a/res/v1x/toy-v1x-parsing/qubits/qubits_abc/input.cq +++ b/res/v1x/toy-v1x-parsing/qubits/qubits_abc/input.cq @@ -1,2 +1,2 @@ version 3 -qubits abc +qubits abc \ No newline at end of file diff --git a/res/v1x/toy-v1x-parsing/qubits/qubits_no_number/ast.golden.txt b/res/v1x/toy-v1x-parsing/qubits/qubits_no_number/ast.golden.txt index e69de29b..2d19847e 100644 --- a/res/v1x/toy-v1x-parsing/qubits/qubits_no_number/ast.golden.txt +++ b/res/v1x/toy-v1x-parsing/qubits/qubits_no_number/ast.golden.txt @@ -0,0 +1,2 @@ +ERROR +input.cq:2:6: mismatched input '' expecting {INTEGER_LITERAL, FLOAT_LITERAL, IDENTIFIER} diff --git a/res/v1x/toy-v1x-parsing/qubits/qubits_no_number/input.cq b/res/v1x/toy-v1x-parsing/qubits/qubits_no_number/input.cq index bdfd07d2..70b892a6 100644 --- a/res/v1x/toy-v1x-parsing/qubits/qubits_no_number/input.cq +++ b/res/v1x/toy-v1x-parsing/qubits/qubits_no_number/input.cq @@ -1,2 +1,2 @@ version 3 -qubits +qubits \ No newline at end of file diff --git a/res/v1x/toy-v1x-parsing/test_cases.txt b/res/v1x/toy-v1x-parsing/test_cases.txt index 4b26d0c3..bb38b647 100644 --- a/res/v1x/toy-v1x-parsing/test_cases.txt +++ b/res/v1x/toy-v1x-parsing/test_cases.txt @@ -1,43 +1,38 @@ -fail empty program -fail something before version blah; version 3 +Syntactic Semantic Error explanation Suite Description Code +fail - Unexpected token program Bad token after version version 3;123abc -fail OK version, bad token version 3;123abc +fail - Unexpected token (EOF) qubits qubits no number version 3;qubits +fail - Unexpected token qubits qubits abc version 3;qubits 123abc +OK OK qubits qubits 3 version 3;qubits 3 -fail OK version, empty qubits version 3;qubits -fail OK version, wrong qubits version 3;qubits 123abc -OK OK version, OK qubits version 3;qubits 3 +fail - Unexpected token (EOF) map map version 3;map +fail - Unexpected token (EOF) map map v version 3;map v +fail - Unexpected token (EOF) map map v = version 3;map v = +OK OK map Map to integer literal version 3;map v = 1 +OK OK map Map to float literal version 3;map v = 3.14 +OK fail 'v' doesn't exist map Map to inexistent var version 3;map w = v +OK OK map Map to existing var version 3;map v = 1;map w = v +OK fail q[0] doesn't exist map Map to inexistent qubit version 3;map v = q[0] +OK OK map Map to existing qubit version 3;qubits 3;map v = q[0] -fail empty map version 3;map -fail empty map id version 3;map v -fail empty map id = version 3;map v = -OK OK map integer version 3;map v = 1 -OK OK map float version 3;map v = 3.14 -fail bad map id version 3;map w = v Syntactically correct, not semantically -OK OK map id version 3;map v = 1;map w = v -fail bad map array, no qubits version 3;map v = q[0] Syntactically correct, not semantically -fail bad map array, out of bounds qubit version 3;qubits 3;map v = q[3] Syntactically correct, not semantically -OK OK map array version 3;qubits 3;map v = q[0] +fail - Unexpected token (EOF) var var version 3;var +fail - Unexpected token (EOF) var var v version 3;var v +fail - Unexpected token (EOF) var var v : version 3;var v : +OK fail 'v' doesn't exist var Var to inexistent var version 3;var w : v +OK OK var Var to existing var version 3;map v = 1;var w : v -fail empty var version 3;var -fail empty var id version 3;var v -fail empty var id : version 3;var v : -fail bad var id version 3;var w : v Syntactically correct, not semantically -OK OK var id version 3;map v = 1;var w : v +fail - 'x' gate should accept a qubit parameter instruction x version 3;x +OK fail 'v' is not a gate instruction v 1 version 3;v 1 +OK fail 'x' gate should accept a qubit parameter instruction x 1 version 3;x 1 +OK fail 'x' gate should accept a qubit parameter instruction x 3.14 version 3;x 3.14 +OK fail 'x' gate should accept a qubit parameter instruction x v version 3;x v +fail - Unexpected token instruction x 123abc version 3;x 123abc +OK fail q[0] doesn't exist instruction x with inexistent qubit version 3;x q[0] +OK OK instruction x with existing qubit version 3;qubits 3;x q[0] +OK OK instruction cnot with existing qubit version 3;qubits 3;h q[0];h q[1];cnot q[0], q[3] -fail empty instruction version 3;x -fail bad id version 3;v 1 Syntactically correct, not semantically -fail bad expression version 3;x 1 Syntactically correct, not semantically -fail bad instruction, no qubits version 3;x q[0] Syntactically correct, not semantically -fail bad instruction, out of bounds qubit version 3;qubits 3;x q[3] Syntactically correct, not semantically -OK OK one qubit instruction version 3;qubits 3;x q[0] -OK OK two qubit instruction version 3;qubits 3;h q[0];h q[1];cnot q[0], q[3] +OK fail q[3] is out of bounds expression Out of bounds index version 3;qubits 3;x q[3] -fail empty instruction expression version 3;qubits 3;x -fail bad instruction expression version 3;qubits 3;x 123abc -fail bad instruction expression integer version 3;qubits 3;x 1 Syntactically correct, not semantically -fail bad instruction expression float version 3;qubits 3;x 3.14 Syntactically correct, not semantically -fail bad instruction expression id version 3;qubits 3;x v Syntactically correct, not semantically - -fail bad expression list, no second part version 3;qubits 3;h q[0];h q[1];cnot q[0], -fail bad expression list, bad first part version 3;qubits 3;h q[0];h q[1];cnot 123abc, q[0] -fail bad expression list, bad second part version 3;qubits 3;h q[0];h q[1];cnot q[0], 123abc +fail - Unexpected token expression_list Bad first part version 3;qubits 3;h q[0];h q[1];cnot 123abc, q[0] +fail - Unexpected token expression_list Bad second part version 3;qubits 3;h q[0];h q[1];cnot q[0], 123abc +fail - Unexpected token (EOF) expression_list No second part version 3;qubits 3;h q[0];h q[1];cnot q[0], diff --git a/res/v1x/toy-v1x-parsing/variable/map_v_1__var_w_v/ast.golden.txt b/res/v1x/toy-v1x-parsing/variable/map_v_1__var_w_v/ast.golden.txt index e69de29b..4c237ab3 100644 --- a/res/v1x/toy-v1x-parsing/variable/map_v_1__var_w_v/ast.golden.txt +++ b/res/v1x/toy-v1x-parsing/variable/map_v_1__var_w_v/ast.golden.txt @@ -0,0 +1,42 @@ +SUCCESS +Program( + version: < + Version( + items: 3 + ) + > + num_qubits: - + statements: < + StatementList( + items: [ + Mapping( + alias: < + Identifier( + name: v + ) + > + expr: < + IntegerLiteral( + value: 1 + ) + > + annotations: [] + ) + Variables( + names: [ + Identifier( + name: w + ) + ] + typ: < + Identifier( + name: v + ) + > + annotations: [] + ) + ] + ) + > +) + diff --git a/res/v1x/toy-v1x-parsing/variable/var_v/ast.golden.txt b/res/v1x/toy-v1x-parsing/variable/var_v/ast.golden.txt index e69de29b..3e6366d6 100644 --- a/res/v1x/toy-v1x-parsing/variable/var_v/ast.golden.txt +++ b/res/v1x/toy-v1x-parsing/variable/var_v/ast.golden.txt @@ -0,0 +1,2 @@ +ERROR +input.cq:4:0: mismatched input '' expecting ':' diff --git a/res/v1x/toy-v1x-parsing/variable/var_v_colon/ast.golden.txt b/res/v1x/toy-v1x-parsing/variable/var_v_colon/ast.golden.txt index e69de29b..6ae4d839 100644 --- a/res/v1x/toy-v1x-parsing/variable/var_v_colon/ast.golden.txt +++ b/res/v1x/toy-v1x-parsing/variable/var_v_colon/ast.golden.txt @@ -0,0 +1,2 @@ +ERROR +input.cq:4:0: missing IDENTIFIER at '' diff --git a/res/v1x/toy-v1x-parsing/variable/var_w_v/ast.golden.txt b/res/v1x/toy-v1x-parsing/variable/var_w_v/ast.golden.txt index e69de29b..150d7f56 100644 --- a/res/v1x/toy-v1x-parsing/variable/var_w_v/ast.golden.txt +++ b/res/v1x/toy-v1x-parsing/variable/var_w_v/ast.golden.txt @@ -0,0 +1,33 @@ +SUCCESS +Program( + version: < + Version( + items: 3 + ) + > + num_qubits: < + IntegerLiteral( + value: 3 + ) + > + statements: < + StatementList( + items: [ + Variables( + names: [ + Identifier( + name: w + ) + ] + typ: < + Identifier( + name: v + ) + > + annotations: [] + ) + ] + ) + > +) + diff --git a/res/v1x/toy-v1x-parsing/variable/var_w_v/input.cq b/res/v1x/toy-v1x-parsing/variable/var_w_v/input.cq index c7f183fe..310a77e4 100644 --- a/res/v1x/toy-v1x-parsing/variable/var_w_v/input.cq +++ b/res/v1x/toy-v1x-parsing/variable/var_w_v/input.cq @@ -1,2 +1,3 @@ version 3 +qubits 3 var w : v diff --git a/scripts/generate_antlr_parser.py b/scripts/generate_antlr_parser.py index 92a5b538..f94e34cf 100644 --- a/scripts/generate_antlr_parser.py +++ b/scripts/generate_antlr_parser.py @@ -54,6 +54,7 @@ def generate_antlr_parser(input_folder, output_folder, antlr_jar_file_path): "java", "-jar", antlr_jar_file_path, + "-no-listener", "-visitor", "-Xexact-output-dir", "-o", diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 41346827..7a10b3f5 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -36,6 +36,7 @@ if(WIN32) else() set(flex_win_compat) endif() +find_package(fmt 10.1.1) find_package(Python3 REQUIRED) include(FetchContent) @@ -43,7 +44,7 @@ include(FetchContent) # This exposes the generate_tree() function. FetchContent_Declare(tree-gen GIT_REPOSITORY https://github.com/QuTech-Delft/tree-gen.git - GIT_TAG "71e5acdf6fd67d6800042aac848e710f99cc79f7" + GIT_TAG "42b91f0b641cde8e8e162a0574aa0ce20a9e25d2" ) FetchContent_MakeAvailable(tree-gen) diff --git a/src/v3x/BuildTreeGenAstVisitor.cpp b/src/v3x/BuildTreeGenAstVisitor.cpp index db6d66e9..ba595a71 100644 --- a/src/v3x/BuildTreeGenAstVisitor.cpp +++ b/src/v3x/BuildTreeGenAstVisitor.cpp @@ -1,13 +1,10 @@ -#include "cqasm-error.hpp" #include "cqasm-tree.hpp" #include "v1x/cqasm-ast.hpp" -#include "v3x/BuildTreeGenAstVisitor.h" +#include "v3x/BuildTreeGenAstVisitor.hpp" #include // assert -#include // from_chars #include // runtime_error #include // stod, stoll -#include // errc namespace cqasm::v3x::parser { @@ -21,9 +18,9 @@ std::int64_t get_integer_literal_value(antlr4::tree::TerminalNode *node) { try { ret = std::stoll(text); } catch (std::invalid_argument&) { - throw AnalysisError{ "terminal node is not of the expected INTEGER_LITERAL type." }; + throw std::runtime_error{ "terminal node is not of the expected INTEGER_LITERAL type." }; } catch (std::out_of_range&) { - throw AnalysisError{ "terminal node is out of the INTEGER_LITERAL range" }; + throw std::runtime_error{ "terminal node is out of the INTEGER_LITERAL range" }; } return ret; } @@ -34,27 +31,28 @@ double get_float_literal_value(antlr4::tree::TerminalNode *node) { try { ret = std::stod(text); } catch (std::invalid_argument&) { - throw AnalysisError{ "terminal node is not of the expected FLOAT_LITERAL type." }; + throw std::runtime_error{ "terminal node is not of the expected FLOAT_LITERAL type." }; } catch (std::out_of_range&) { - throw AnalysisError{ "terminal node is out of the FLOAT_LITERAL range" }; + throw std::runtime_error{ "terminal node is out of the FLOAT_LITERAL range" }; } return ret; } std::any BuildTreeGenAstVisitor::visitProgram(CqasmParser::ProgramContext *context) { - auto ret = One{}; + auto ret = cqasm::tree::make(); ret->version = std::any_cast>(visitVersion(context->version())); - ret->num_qubits = std::any_cast>(visitExpression(context->expression())); + if (auto qubits_ctx = context->qubits()) { + ret->num_qubits = std::any_cast>(visitQubits(qubits_ctx)); + } ret->statements = cqasm::tree::make(); for (size_t i{ 0 }; i < context->statement().size(); ++i) { - auto statement_ast = visitStatement(context->statement(i)); - ret->statements->items.add(std::any_cast>(statement_ast)); + ret->statements->items.add(std::any_cast>(visitStatement(context->statement(i)))); } return ret; } std::any BuildTreeGenAstVisitor::visitVersion(CqasmParser::VersionContext *context) { - auto ret = One{}; + auto ret = cqasm::tree::make(); for (size_t i{ 0 }; i < context->INTEGER_LITERAL().size(); ++i) { auto number = get_integer_literal_value(context->INTEGER_LITERAL(i)); ret->items.push_back(number); @@ -62,65 +60,83 @@ std::any BuildTreeGenAstVisitor::visitVersion(CqasmParser::VersionContext *conte return ret; } +std::any BuildTreeGenAstVisitor::visitQubits(CqasmParser::QubitsContext *context) { + auto ret = Maybe{}; + if (auto qubits_ctx = context->QUBITS(); qubits_ctx->getText() == "qubits") { + ret.set(std::any_cast>(visitExpression(context->expression())).get_ptr()); + } + return ret; +} + std::any BuildTreeGenAstVisitor::visitStatement(CqasmParser::StatementContext *context) { - if (auto ast = context->mapping()) { - return cqasm::tree::make(std::any_cast(visitMapping(ast))); - } else if (auto ast = context->variable()) { - return cqasm::tree::make(std::any_cast(visitVariable(ast))); - } else if (auto ast = context->instruction()) { - return cqasm::tree::make(std::any_cast(visitInstruction(ast))); + auto ret = One{}; + if (auto mapping_ctx = context->mapping()) { + ret = cqasm::tree::make(std::any_cast(visitMapping(mapping_ctx))); + } else if (auto variable_ctx = context->variable()) { + ret = cqasm::tree::make(std::any_cast(visitVariable(variable_ctx))); + } else if (auto instruction_ctx = context->instruction()) { + ret = cqasm::tree::make(Many{ + std::any_cast>(visitInstruction(instruction_ctx)) + }); } else { - throw AnalysisError{ "unknown statement type" }; + throw std::runtime_error{ "unknown statement type" }; } + return ret; } std::any BuildTreeGenAstVisitor::visitMapping(CqasmParser::MappingContext *context) { auto ret = Mapping{}; - ret.alias = cqasm::tree::make(context->IDENTIFIER()->getText()); - ret.expr = std::any_cast>(visitExpression(context->expression())); + if (auto mapping_ctx = context->MAP(); mapping_ctx->getText() == "map") { + ret.alias = cqasm::tree::make(context->IDENTIFIER()->getText()); + ret.expr = std::any_cast>(visitExpression(context->expression())); + } return ret; } std::any BuildTreeGenAstVisitor::visitVariable(CqasmParser::VariableContext *context) { auto ret = Variables{}; - assert(context->IDENTIFIER().size() == 2); - ret.names.add(cqasm::tree::make(context->IDENTIFIER(0)->getText())); - ret.typ = cqasm::tree::make(context->IDENTIFIER(1)->getText()); + if (auto variable_ctx = context->VAR(); variable_ctx->getText() == "var") { + assert(context->IDENTIFIER().size() == 2); + ret.names.add(cqasm::tree::make(context->IDENTIFIER(0)->getText())); + ret.typ = cqasm::tree::make(context->IDENTIFIER(1)->getText()); + + } return ret; } std::any BuildTreeGenAstVisitor::visitInstruction(CqasmParser::InstructionContext *context) { - auto ret = Instruction{}; - ret.name = cqasm::tree::make(context->IDENTIFIER()->getText()); - auto expression_list_ast = visitExpressionList(context->expressionList()); - ret.operands = cqasm::tree::make(std::any_cast(expression_list_ast)); + auto ret = cqasm::tree::make(); + ret->name = cqasm::tree::make(context->IDENTIFIER()->getText()); + ret->operands = cqasm::tree::make(std::any_cast( + visitExpressionList(context->expressionList()))); return ret; } std::any BuildTreeGenAstVisitor::visitExpressionList(CqasmParser::ExpressionListContext *context) { auto ret = ExpressionList{}; for (size_t i{ 0 }; i < context->expression().size(); ++i) { - auto expression_ast = visitExpression(context->expression(i)); - ret.items.add(std::any_cast>(expression_ast)); + ret.items.add(std::any_cast>(visitExpression(context->expression(i)))); } return ret; } std::any BuildTreeGenAstVisitor::visitExpression(CqasmParser::ExpressionContext *context) { + auto ret = One{}; if (auto integer_literal_ast = context->INTEGER_LITERAL()) { auto integer_literal = get_integer_literal_value(integer_literal_ast); - return cqasm::tree::make(integer_literal); + ret = cqasm::tree::make(integer_literal); } else if (auto float_literal_ast = context->FLOAT_LITERAL()) { auto float_literal = get_float_literal_value(float_literal_ast); - return cqasm::tree::make(float_literal); + ret = cqasm::tree::make(float_literal); } else if (auto id_ast = context->IDENTIFIER()) { auto id = id_ast->getText(); - return cqasm::tree::make(std::move(id)); - } else if (auto index_ast = context->index()) { - return cqasm::tree::make(std::any_cast(visitIndex(index_ast))); + ret = cqasm::tree::make(std::move(id)); + } else if (auto index_ctx = context->index()) { + ret = cqasm::tree::make(std::any_cast(visitIndex(index_ctx))); } else { - throw AnalysisError{ "unknown expression type" }; + throw std::runtime_error{ "unknown expression type" }; } + return ret; } std::any BuildTreeGenAstVisitor::visitIndex(CqasmParser::IndexContext *context) { @@ -128,8 +144,8 @@ std::any BuildTreeGenAstVisitor::visitIndex(CqasmParser::IndexContext *context) auto id = context->IDENTIFIER()->getText(); ret.expr = cqasm::tree::make(std::move(id)); ret.indices = cqasm::tree::make(); - auto expression_ast = visitExpression(context->expression()); - auto index_item = cqasm::tree::make(std::any_cast>(expression_ast)); + auto index_item = cqasm::tree::make(std::any_cast>( + visitExpression(context->expression()))); ret.indices->items.add(std::move(index_item)); return ret; } diff --git a/src/v3x/CMakeLists.txt b/src/v3x/CMakeLists.txt index 49491c1c..9eae3084 100644 --- a/src/v3x/CMakeLists.txt +++ b/src/v3x/CMakeLists.txt @@ -3,5 +3,6 @@ set(CQASM_V3X_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/cqasm.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/cqasm-parse-helper.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/BuildTreeGenAstVisitor.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/CustomErrorListener.cpp" PARENT_SCOPE ) diff --git a/src/v3x/CqasmParser.g4 b/src/v3x/CqasmParser.g4 index 0078a70b..ac3a11ce 100644 --- a/src/v3x/CqasmParser.g4 +++ b/src/v3x/CqasmParser.g4 @@ -5,10 +5,12 @@ options { } // Actual grammar start. -program: version QUBITS expression statement*; +program: version qubits? statement* EOF; version: VERSION INTEGER_LITERAL (DOT INTEGER_LITERAL)?; +qubits: QUBITS expression; + statement: mapping | variable | instruction; mapping: MAP IDENTIFIER EQUAL expression; diff --git a/src/v3x/CustomErrorListener.cpp b/src/v3x/CustomErrorListener.cpp new file mode 100644 index 00000000..c46d36c3 --- /dev/null +++ b/src/v3x/CustomErrorListener.cpp @@ -0,0 +1,18 @@ +#include "cqasm-error.hpp" +#include "v3x/CustomErrorListener.hpp" + +#include +#include + + +namespace cqasm::v3x::parser { + +void CustomErrorListener::syntaxError(antlr4::Recognizer * /* recognizer */, antlr4::Token * /* offendingSymbol */, + size_t line, size_t charPositionInLine, const std::string &msg, std::exception_ptr /* e */) { + + throw std::runtime_error{ + fmt::format("{}:{}:{}: {}", file_name_, line, charPositionInLine, msg) + }; +} + +} // namespace cqasm::v3x::parser diff --git a/src/v3x/cqasm-parse-helper.cpp b/src/v3x/cqasm-parse-helper.cpp index 52f49d7f..02f11de5 100644 --- a/src/v3x/cqasm-parse-helper.cpp +++ b/src/v3x/cqasm-parse-helper.cpp @@ -4,62 +4,67 @@ #include "v1x/cqasm-ast.hpp" #include "v1x/cqasm-parse-result.hpp" -#include "v3x/BuildTreeGenAstVisitor.h" +#include "v3x/BuildTreeGenAstVisitor.hpp" +#include "v3x/cqasm-parse-helper.hpp" #include "v3x/CqasmLexer.h" #include "v3x/CqasmParser.h" -#include "v3x/cqasm-parse-helper.hpp" -#include "antlr4-runtime/antlr4-runtime.h" - -#include #include -#include // ifstream -#include // runtime_error +#include namespace fs = std::filesystem; namespace cqasm::v3x::parser { +using namespace cqasm::v1x::ast; + ScannerAdaptor::~ScannerAdaptor() {} -ScannerAntlr::ScannerAntlr(std::unique_ptr build_visitor_up) -: build_visitor_up_{ std::move(build_visitor_up) } {} +ScannerAntlr::ScannerAntlr(std::unique_ptr build_visitor_up, + std::unique_ptr error_listener_up) +: build_visitor_up_{ std::move(build_visitor_up) } +, error_listener_up_{ std::move(error_listener_up) } {} ScannerAntlr::~ScannerAntlr() {} -void ScannerAntlr::parse_(antlr4::ANTLRInputStream &is, const std::string & /* file_name */, - cqasm::v1x::parser::ParseResult &result) { - +cqasm::v1x::parser::ParseResult ScannerAntlr::parse_(antlr4::ANTLRInputStream &is) { CqasmLexer lexer{ &is }; + lexer.removeErrorListeners(); + lexer.addErrorListener(error_listener_up_.get()); antlr4::CommonTokenStream tokens{ &lexer }; CqasmParser parser{ &tokens }; + parser.removeErrorListeners(); + parser.addErrorListener(error_listener_up_.get()); auto ast = parser.program(); auto custom_ast = build_visitor_up_->visitProgram(ast); - result.root = std::any_cast>(custom_ast); + return cqasm::v1x::parser::ParseResult{ std::any_cast>(custom_ast), {} }; } -ScannerAntlrFile::ScannerAntlrFile(std::unique_ptr build_visitor_up, const std::string &file_path) -: ScannerAntlr{ std::move(build_visitor_up) }, ifs_{ file_path } { - if (!ifs_.is_open()) { - throw error::AnalysisError("ScannerAntlrFile couldn't access file."); +ScannerAntlrFile::ScannerAntlrFile(std::unique_ptr build_visitor_up, + std::unique_ptr error_listener_up, const std::string &file_path) +: ScannerAntlr{ std::move(build_visitor_up), std::move(error_listener_up) }, file_path_{ file_path } { + if (!fs::exists(file_path_) || !fs::is_regular_file(file_path_)) { + throw error::AnalysisError{ fmt::format("ScannerAntlrFile couldn't access file '{}'.", file_path_) }; } } ScannerAntlrFile::~ScannerAntlrFile() {} -void ScannerAntlrFile::parse(const std::string &file_name, cqasm::v1x::parser::ParseResult &result) { - antlr4::ANTLRInputStream is{ ifs_ }; - parse_(is, file_name, result); +cqasm::v1x::parser::ParseResult ScannerAntlrFile::parse() { + antlr4::ANTLRFileStream ifs{}; + ifs.loadFromFile(file_path_); + return parse_(ifs); } -ScannerAntlrString::ScannerAntlrString(std::unique_ptr build_visitor_up, const std::string &data) -: ScannerAntlr{ std::move(build_visitor_up) }, data_{ data } {} +ScannerAntlrString::ScannerAntlrString(std::unique_ptr build_visitor_up, + std::unique_ptr error_listener_up, const std::string &data) +: ScannerAntlr{ std::move(build_visitor_up), std::move(error_listener_up) }, data_{ data } {} ScannerAntlrString::~ScannerAntlrString() {} -void ScannerAntlrString::parse(const std::string &file_name, cqasm::v1x::parser::ParseResult &result) { +cqasm::v1x::parser::ParseResult ScannerAntlrString::parse() { antlr4::ANTLRInputStream is{ data_ }; - parse_(is, file_name, result); + return parse_(is); } /** @@ -69,7 +74,9 @@ void ScannerAntlrString::parse(const std::string &file_name, cqasm::v1x::parser: */ cqasm::v1x::parser::ParseResult parse_file(const std::string &file_path, const std::string &file_name) { auto builder_visitor_up = std::make_unique(); - auto scanner_up = std::make_unique(std::move(builder_visitor_up), file_path); + auto error_listener_up = std::make_unique(file_name); + auto scanner_up = std::make_unique( + std::move(builder_visitor_up), std::move(error_listener_up), file_path); return ParseHelper(std::move(scanner_up), file_name).parse(); } @@ -79,23 +86,29 @@ cqasm::v1x::parser::ParseResult parse_file(const std::string &file_path, const s */ cqasm::v1x::parser::ParseResult parse_string(const std::string &data, const std::string &file_name) { auto builder_visitor_up = std::make_unique(); - auto scanner_up = std::make_unique(std::move(builder_visitor_up), data); + auto error_listener_up = std::make_unique(file_name); + auto scanner_up = std::make_unique( + std::move(builder_visitor_up), std::move(error_listener_up), data); return ParseHelper(std::move(scanner_up), file_name).parse(); } ParseHelper::ParseHelper(std::unique_ptr scanner_up, std::string file_name) -: scanner_up_(std::move(scanner_up)), file_name(std::move(file_name)) {} +: scanner_up_(std::move(scanner_up)), file_name_(std::move(file_name)) {} /** * Does the actual parsing. */ cqasm::v1x::parser::ParseResult ParseHelper::parse() { cqasm::v1x::parser::ParseResult result; - scanner_up_->parse(file_name, result); + try { + result = scanner_up_->parse(); + } catch (const std::runtime_error &err) { + result.errors.emplace_back(err.what()); + } if (result.errors.empty() && !result.root.is_well_formed()) { std::cerr << *result.root; - throw error::AnalysisError( + throw cqasm::error::AnalysisError( "ParseHelper::parse: no parse errors returned, but AST is incomplete. AST was dumped."); } return result; diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 44a0e589..378c6d35 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -12,7 +12,7 @@ add_subdirectory(v1x) # Sources target_sources(${PROJECT_NAME}_test PRIVATE - "${CMAKE_CURRENT_SOURCE_DIR}/cqasm-version.cpp" + #"${CMAKE_CURRENT_SOURCE_DIR}/cqasm-version.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/main.cpp" ) diff --git a/test/v1x/parsing.cpp b/test/v1x/parsing.cpp index aad0a94d..901a0041 100644 --- a/test/v1x/parsing.cpp +++ b/test/v1x/parsing.cpp @@ -90,6 +90,7 @@ class ParsingTest : public ::testing::Test { return; } + /* // Try different API levels for (const auto &api_version : std::vector({"1.0", "1.1", "1.2"})) { // If there were no errors, try semantic analysis. @@ -224,6 +225,7 @@ class ParsingTest : public ::testing::Test { ::tree::base::serialize(analysis_result.root); } } + */ } }; From 0d07e5e314ad55f2a3414eccbce1c5e9ba2de188 Mon Sep 17 00:00:00 2001 From: rturrado <68099809+rturrado@users.noreply.github.com> Date: Thu, 21 Sep 2023 00:34:11 +0200 Subject: [PATCH 15/28] Removed cqasm::v3x::default_analyzer. Just reusing cqasm::v1x::default_analyzer instead. Updated some tests. --- .github/workflows/test.yml | 1 - include/v3x/cqasm.hpp | 7 --- .../out_of_bounds_index/ast.golden.txt | 21 ++++++- .../instruction/x_123abc/ast.golden.txt | 2 +- .../instruction/x_3_14/ast.golden.txt | 6 +- .../instruction/x_v/ast.golden.txt | 6 +- .../variable/var_v/ast.golden.txt | 2 +- .../toy-v1x-parsing/variable/var_v/input.cq | 2 +- .../variable/var_v_colon/ast.golden.txt | 2 +- .../variable/var_v_colon/input.cq | 2 +- .../toy-v1x-parsing/variable/var_w_v/input.cq | 2 +- src/v1x/cqasm.cpp | 2 +- src/v3x/cqasm.cpp | 56 +++---------------- 13 files changed, 35 insertions(+), 76 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 138b4c43..c53c345e 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -4,7 +4,6 @@ on: push: branches: - develop - - toy-v1-use_case_circuit_for_parser_verification pull_request: jobs: diff --git a/include/v3x/cqasm.hpp b/include/v3x/cqasm.hpp index 9c8973e6..2ad4dcc3 100644 --- a/include/v3x/cqasm.hpp +++ b/include/v3x/cqasm.hpp @@ -41,12 +41,5 @@ tree::One analyze_string( const std::string &api_version = "1.0" ); -/** - * Constructs an Analyzer object with the defaults for cQASM 1.0 already loaded into it. - */ -cqasm::v1x::analyzer::Analyzer default_analyzer( - const std::string &api_version = "1.0" -); - } // namespace v3x } // namespace cqasm diff --git a/res/v1x/toy-v1x-parsing/expression/out_of_bounds_index/ast.golden.txt b/res/v1x/toy-v1x-parsing/expression/out_of_bounds_index/ast.golden.txt index 6a41e6e0..65ef5f46 100644 --- a/res/v1x/toy-v1x-parsing/expression/out_of_bounds_index/ast.golden.txt +++ b/res/v1x/toy-v1x-parsing/expression/out_of_bounds_index/ast.golden.txt @@ -25,8 +25,25 @@ Program( operands: < ExpressionList( items: [ - IntegerLiteral( - value: 1 + Index( + expr: < + Identifier( + name: q + ) + > + indices: < + IndexList( + items: [ + IndexItem( + index: < + IntegerLiteral( + value: 3 + ) + > + ) + ] + ) + > ) ] ) diff --git a/res/v1x/toy-v1x-parsing/instruction/x_123abc/ast.golden.txt b/res/v1x/toy-v1x-parsing/instruction/x_123abc/ast.golden.txt index ae1d850e..edc203cc 100644 --- a/res/v1x/toy-v1x-parsing/instruction/x_123abc/ast.golden.txt +++ b/res/v1x/toy-v1x-parsing/instruction/x_123abc/ast.golden.txt @@ -1,2 +1,2 @@ ERROR -input.cq:3:8: mismatched input '' expecting {INTEGER_LITERAL, FLOAT_LITERAL, IDENTIFIER} +input.cq:2:8: mismatched input '' expecting {INTEGER_LITERAL, FLOAT_LITERAL, IDENTIFIER} diff --git a/res/v1x/toy-v1x-parsing/instruction/x_3_14/ast.golden.txt b/res/v1x/toy-v1x-parsing/instruction/x_3_14/ast.golden.txt index 458cdae8..9453b7fb 100644 --- a/res/v1x/toy-v1x-parsing/instruction/x_3_14/ast.golden.txt +++ b/res/v1x/toy-v1x-parsing/instruction/x_3_14/ast.golden.txt @@ -5,11 +5,7 @@ Program( items: 3 ) > - num_qubits: < - IntegerLiteral( - value: 3 - ) - > + num_qubits: - statements: < StatementList( items: [ diff --git a/res/v1x/toy-v1x-parsing/instruction/x_v/ast.golden.txt b/res/v1x/toy-v1x-parsing/instruction/x_v/ast.golden.txt index c5de3cc2..882df4bd 100644 --- a/res/v1x/toy-v1x-parsing/instruction/x_v/ast.golden.txt +++ b/res/v1x/toy-v1x-parsing/instruction/x_v/ast.golden.txt @@ -5,11 +5,7 @@ Program( items: 3 ) > - num_qubits: < - IntegerLiteral( - value: 3 - ) - > + num_qubits: - statements: < StatementList( items: [ diff --git a/res/v1x/toy-v1x-parsing/variable/var_v/ast.golden.txt b/res/v1x/toy-v1x-parsing/variable/var_v/ast.golden.txt index 3e6366d6..13c5eab6 100644 --- a/res/v1x/toy-v1x-parsing/variable/var_v/ast.golden.txt +++ b/res/v1x/toy-v1x-parsing/variable/var_v/ast.golden.txt @@ -1,2 +1,2 @@ ERROR -input.cq:4:0: mismatched input '' expecting ':' +input.cq:2:5: mismatched input '' expecting ':' diff --git a/res/v1x/toy-v1x-parsing/variable/var_v/input.cq b/res/v1x/toy-v1x-parsing/variable/var_v/input.cq index f34c4522..6507d8ea 100644 --- a/res/v1x/toy-v1x-parsing/variable/var_v/input.cq +++ b/res/v1x/toy-v1x-parsing/variable/var_v/input.cq @@ -1,2 +1,2 @@ version 3 -var v +var v \ No newline at end of file diff --git a/res/v1x/toy-v1x-parsing/variable/var_v_colon/ast.golden.txt b/res/v1x/toy-v1x-parsing/variable/var_v_colon/ast.golden.txt index 6ae4d839..964f6e1d 100644 --- a/res/v1x/toy-v1x-parsing/variable/var_v_colon/ast.golden.txt +++ b/res/v1x/toy-v1x-parsing/variable/var_v_colon/ast.golden.txt @@ -1,2 +1,2 @@ ERROR -input.cq:4:0: missing IDENTIFIER at '' +input.cq:2:7: missing IDENTIFIER at '' diff --git a/res/v1x/toy-v1x-parsing/variable/var_v_colon/input.cq b/res/v1x/toy-v1x-parsing/variable/var_v_colon/input.cq index c6efdb5f..fb9143b6 100644 --- a/res/v1x/toy-v1x-parsing/variable/var_v_colon/input.cq +++ b/res/v1x/toy-v1x-parsing/variable/var_v_colon/input.cq @@ -1,2 +1,2 @@ version 3 -var v : +var v : \ No newline at end of file diff --git a/res/v1x/toy-v1x-parsing/variable/var_w_v/input.cq b/res/v1x/toy-v1x-parsing/variable/var_w_v/input.cq index 310a77e4..89e962b4 100644 --- a/res/v1x/toy-v1x-parsing/variable/var_w_v/input.cq +++ b/res/v1x/toy-v1x-parsing/variable/var_w_v/input.cq @@ -1,3 +1,3 @@ version 3 qubits 3 -var w : v +var w : v \ No newline at end of file diff --git a/src/v1x/cqasm.cpp b/src/v1x/cqasm.cpp index 31829eae..c4d18430 100644 --- a/src/v1x/cqasm.cpp +++ b/src/v1x/cqasm.cpp @@ -9,7 +9,7 @@ #include "cqasm-version.hpp" #include "v1x/cqasm.hpp" #include "v1x/cqasm-parse-helper.hpp" -#include "v1x/cqasm-parse-result.hpp" + namespace cqasm { namespace v1x { diff --git a/src/v3x/cqasm.cpp b/src/v3x/cqasm.cpp index 13519f28..1b4179e8 100644 --- a/src/v3x/cqasm.cpp +++ b/src/v3x/cqasm.cpp @@ -7,15 +7,14 @@ */ #include "cqasm-version.hpp" -#include "v1x/cqasm-parse-result.hpp" +#include "v1x/cqasm.hpp" #include "v3x/cqasm.hpp" #include "v3x/cqasm-parse-helper.hpp" #include // runtime_error -namespace cqasm { -namespace v3x { +namespace cqasm::v3x { /** * Parses and analyzes the given file path with the default analyzer, @@ -25,9 +24,9 @@ tree::One analyze( const std::string &file_path, const std::string &api_version ) { - return default_analyzer(api_version).analyze( + return cqasm::v1x::default_analyzer(api_version).analyze( [=](){ return version::parse_file(file_path); }, - [=](){ return parser::parse_file(file_path); } + [=](){ return cqasm::v3x::parser::parse_file(file_path); } ).unwrap(); } @@ -41,51 +40,10 @@ tree::One analyze_string( const std::string &file_name, const std::string &api_version ) { - return default_analyzer(api_version).analyze( + return cqasm::v1x::default_analyzer(api_version).analyze( [=](){ return version::parse_string(data, file_name); }, - [=](){ return parser::parse_string(data, file_name); } + [=](){ return cqasm::v3x::parser::parse_string(data, file_name); } ).unwrap(); } -/** - * Constructs an Analyzer object with the defaults for cQASM 1.0 already loaded into it. - */ -cqasm::v1x::analyzer::Analyzer default_analyzer(const std::string &api_version) { - cqasm::v1x::analyzer::Analyzer analyzer{api_version}; - - // Register the default mappings (true, false, pi, x, y, z, etc.) and - // functions (operators, things like trigonometric functions, etc.). - analyzer.register_default_functions_and_mappings(); - - // Register the error models. - // Originally, depolarizing_channel accepted any number of floating point arguments, - // but the new parser doesn't support that, - // so we just brute-force the first 50 into it and call it a day. - std::ostringstream args; - for (int i = 0; i <= 50; i++) { - analyzer.register_error_model("depolarizing_channel", args.str()); - args << "r"; - } - - // Register a toy version of the cQASM 1.0 instruction set. - analyzer.register_instruction("measure_all", "", false, false); - analyzer.register_instruction("x", "Q"); - analyzer.register_instruction("y", "Q"); - analyzer.register_instruction("z", "Q"); - analyzer.register_instruction("i", "Q"); - analyzer.register_instruction("h", "Q"); - analyzer.register_instruction("prep", "Q", false); - analyzer.register_instruction("prep_x", "Q", false); - analyzer.register_instruction("prep_y", "Q", false); - analyzer.register_instruction("prep_z", "Q", false); - analyzer.register_instruction("measure", "Q", false); - analyzer.register_instruction("measure_x", "Q", false); - analyzer.register_instruction("measure_y", "Q", false); - analyzer.register_instruction("measure_z", "Q", false); - analyzer.register_instruction("cnot", "QQ"); - - return analyzer; -} - -} // namespace v3x -} // namespace cqasm +} // namespace cqasm::v3x From 3fd53bd4437bccb04dfe4876b9c22536316e97b1 Mon Sep 17 00:00:00 2001 From: rturrado <68099809+rturrado@users.noreply.github.com> Date: Thu, 21 Sep 2023 01:15:52 +0200 Subject: [PATCH 16/28] Used make_unique instead of unique_ptr. --- src/cqasm-py.cpp | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/cqasm-py.cpp b/src/cqasm-py.cpp index 208d8c90..05aac4d8 100644 --- a/src/cqasm-py.cpp +++ b/src/cqasm-py.cpp @@ -7,6 +7,8 @@ #include "v1x/cqasm.hpp" #include "v1x/cqasm-parse-helper.hpp" +#include + namespace v1x = cqasm::v1x; /** @@ -20,14 +22,10 @@ namespace v1x = cqasm::v1x; */ V1xAnalyzer::V1xAnalyzer(const std::string &max_version, bool without_defaults) { if (without_defaults) { - a = std::unique_ptr( - new v1x::analyzer::Analyzer(max_version) - ); + a = std::make_unique(max_version); a->register_default_functions_and_mappings(); } else { - a = std::unique_ptr( - new v1x::analyzer::Analyzer(v1x::default_analyzer(max_version)) - ); + a = std::make_unique(v1x::default_analyzer(max_version)); } } From fd327efed8af1616e93ea2915e7a7881daec7702 Mon Sep 17 00:00:00 2001 From: rturrado <68099809+rturrado@users.noreply.github.com> Date: Thu, 21 Sep 2023 01:38:19 +0200 Subject: [PATCH 17/28] Removed temporary comments. --- conanfile.py | 8 ++++---- test/CMakeLists.txt | 6 +++--- test/v1x/CMakeLists.txt | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/conanfile.py b/conanfile.py index 3e96ae79..9a71371f 100644 --- a/conanfile.py +++ b/conanfile.py @@ -60,8 +60,8 @@ def build_requirements(self): self.tool_requires("bison/3.8.2") if self.settings.arch != "armv8": self.tool_requires("zulu-openjdk/11.0.19") - #if self.options.build_tests: - self.requires("gtest/1.14.0") + if self.options.build_tests: + self.requires("gtest/1.14.0") def requirements(self): self.requires("antlr4-cppruntime/4.13.0") @@ -87,8 +87,8 @@ def layout(self): self.cpp.build.libdirs = ["."] def generate(self): - #deps = CMakeDeps(self) - #deps.generate() + deps = CMakeDeps(self) + deps.generate() tc = CMakeToolchain(self) tc.variables["ASAN_ENABLED"] = self.options.asan_enabled tc.variables["LIBQASM_BUILD_PYTHON"] = self.options.build_python diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 378c6d35..907d53ca 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -5,14 +5,14 @@ add_executable(${PROJECT_NAME}_test) # Subdirectories if(LIBQASM_COMPAT) - #add_subdirectory(v10) + add_subdirectory(v10) endif() add_subdirectory(v1x) -#add_subdirectory(v3x) +add_subdirectory(v3x) # Sources target_sources(${PROJECT_NAME}_test PRIVATE - #"${CMAKE_CURRENT_SOURCE_DIR}/cqasm-version.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/cqasm-version.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/main.cpp" ) diff --git a/test/v1x/CMakeLists.txt b/test/v1x/CMakeLists.txt index 501ed712..4abf3c73 100644 --- a/test/v1x/CMakeLists.txt +++ b/test/v1x/CMakeLists.txt @@ -1,4 +1,4 @@ target_sources(${PROJECT_NAME}_test PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/parsing.cpp" - #"${CMAKE_CURRENT_SOURCE_DIR}/tutorial.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/tutorial.cpp" ) From 4cefec04b923aca9990728827f0e60635bf9b106 Mon Sep 17 00:00:00 2001 From: rturrado <68099809+rturrado@users.noreply.github.com> Date: Fri, 22 Sep 2023 01:48:38 +0200 Subject: [PATCH 18/28] Updated README.md. --- README.md | 50 +++++++++++++++++++++----------------------------- 1 file changed, 21 insertions(+), 29 deletions(-) diff --git a/README.md b/README.md index 6cc1e8a1..a5459512 100644 --- a/README.md +++ b/README.md @@ -28,13 +28,17 @@ The following folders may be generated: ## Dependencies -* CMake >= 3.12 +* C++ compiler with C++20 support (gcc 11, clang 14, msvc 17) +* `CMake` >= 3.12 * conan 2.0 -* gcc and g++ capable of C++20 standard * git -* Python3 +* Python3 plus pip -### ARM specific dependencies +### ARM-specific dependencies + +We are having problems when using the `m4` and `zulu-opendjk` Conan packages on an ARMv8 architecture. +`m4` is required by Flex/Bison and `zulu-openjdk` provides the Java JRE required by the ANTLR generator. +So, for the time being, we are installing Flex/Bison and Java manually for this platform. * Flex >= 2.6.4 * Bison >= 3.0 @@ -42,29 +46,25 @@ The following folders may be generated: ## Build -This version of libqasm can only be compiled via `conan`. - -`conan` is a package manager that is very convenient for managing dependencies. It is installed via `pip`. - -``` -pip install conan -``` - -You'll need to create a default profile before using it: - -``` -conan profile detect -``` +This version of `libqasm` can only be compiled via the `conan` package manager. +You'll need to create a default profile before using it for the first time. -The installation of `libqasm` dependencies, as well as the compilation, can be done in one go.
-Notice the command below is building `libqasm` in Debug mode with tests. +The installation of dependencies, as well as the compilation, can be done in one go. Notice: +- the `conan profile` command only has to be run once. +- the `conan build` command is building `libqasm` in Debug mode with tests. ``` git clone https://github.com/QuTech-Delft/libqasm.git cd libqasm +conan profile detect conan build . -s:h compiler.cppstd=20 -s:h libqasm/*:build_type=Debug -o libqasm/*:build_tests=True -b missing ``` +You may want to add one or more options to the `conan` command: + +- -o libqasm/*:compat=True: enables installation of the headers for the original API, on top of the ones for the new API. +- -o libqasm/*:shared=True: builds a shared object library instead of a static library, if applicable. + ## Install ### From Python @@ -72,7 +72,7 @@ conan build . -s:h compiler.cppstd=20 -s:h libqasm/*:build_type=Debug -o libqasm Install from the project root directory as follows: ``` -python -m pip install --verbose . +python3 -m pip install --verbose . ``` or if you'd rather use conda: @@ -85,7 +85,7 @@ conda install libqasm --use-local You can test if it works by running: ``` -python -m pytest +python3 -m pytest ``` ### From C++ @@ -96,12 +96,6 @@ The `CMakeLists.txt` file in the root directory includes install targets: conan create --version 0.4.1 . -s:h compiler.cppstd=20 -s:h libqasm/*:build_type=Debug -o libqasm/*:build_tests=True -b missing ``` -You may want to add one or more options to the `conan` command: - - - -o libqasm/*:compat=True: enables installation of the headers for the original API, on top of the ones for the new API. - - -o libqasm/*:shared=True: builds a shared object library instead of a static library, if applicable. - - You can test if it works by doing: ``` @@ -120,8 +114,6 @@ The new API doesn't have Python bindings yet. The easiest way to use libqasm in a CMake project is to fetch the library and then link against it. -Note that the Java JRE is required for libqasm to build: - ``` include(FetchContent) FetchContent_Declare(cqasm From 27a104a004dbfab8a3b6cbcdae801fdc552bef2a Mon Sep 17 00:00:00 2001 From: rturrado <68099809+rturrado@users.noreply.github.com> Date: Fri, 22 Sep 2023 22:01:10 +0200 Subject: [PATCH 19/28] Addressed some of the comments from Pablo's code review. - BuildCustomAstVisitor.hpp: made methods virtual. - BuildTreeGenAstVisitor.cpp: removed unnecessary checks that should be done by the lexer/parser. - cqasm.cpp: lambdas use references instead of copies now. - cqasm-parse-helper.{hpp,cpp}: moved scanner code into separate files. - ScannerAntlr.{hpp,cpp}: moved scanner code into separate files. - test.yml: fixed comment. --- .github/workflows/test.yml | 2 +- include/v3x/BuildCustomAstVisitor.hpp | 20 +++--- include/v3x/ScannerAntlr.hpp | 57 +++++++++++++++++ include/v3x/cqasm-parse-helper.hpp | 46 +------------- src/v3x/BuildTreeGenAstVisitor.cpp | 88 ++++++++++----------------- src/v3x/CMakeLists.txt | 1 + src/v3x/ScannerAntlr.cpp | 72 ++++++++++++++++++++++ src/v3x/cqasm-parse-helper.cpp | 59 +----------------- src/v3x/cqasm.cpp | 8 +-- 9 files changed, 178 insertions(+), 175 deletions(-) create mode 100644 include/v3x/ScannerAntlr.hpp create mode 100644 src/v3x/ScannerAntlr.cpp diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index c53c345e..eb0ac044 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -114,7 +114,7 @@ jobs: run: | sudo apt-get install -y swig echo "LIBQASM_BUILD_TYPE=Debug" >> $GITHUB_ENV - - name: Install flex/bison and SWIG, and set build type (MacOS) + - name: Install SWIG, and set build type (MacOS) if: matrix.os == 'macos-latest' run: | brew install swig diff --git a/include/v3x/BuildCustomAstVisitor.hpp b/include/v3x/BuildCustomAstVisitor.hpp index 774a934a..e42fe575 100644 --- a/include/v3x/BuildCustomAstVisitor.hpp +++ b/include/v3x/BuildCustomAstVisitor.hpp @@ -1,4 +1,4 @@ -#pragma once + #pragma once #include "v3x/CqasmParser.h" #include "v3x/CqasmParserVisitor.h" @@ -11,15 +11,15 @@ namespace cqasm::v3x::parser { class BuildCustomAstVisitor : public CqasmParserVisitor { public: virtual std::any visitProgram(CqasmParser::ProgramContext *context) = 0; - std::any visitVersion(CqasmParser::VersionContext *context) = 0; - std::any visitQubits(CqasmParser::QubitsContext *context) = 0; - std::any visitStatement(CqasmParser::StatementContext *context) = 0; - std::any visitMapping(CqasmParser::MappingContext *context) = 0; - std::any visitVariable(CqasmParser::VariableContext *context) = 0; - std::any visitInstruction(CqasmParser::InstructionContext *context) = 0; - std::any visitExpressionList(CqasmParser::ExpressionListContext *context) = 0; - std::any visitExpression(CqasmParser::ExpressionContext *context) = 0; - std::any visitIndex(CqasmParser::IndexContext *context) = 0; + virtual std::any visitVersion(CqasmParser::VersionContext *context) = 0; + virtual std::any visitQubits(CqasmParser::QubitsContext *context) = 0; + virtual std::any visitStatement(CqasmParser::StatementContext *context) = 0; + virtual std::any visitMapping(CqasmParser::MappingContext *context) = 0; + virtual std::any visitVariable(CqasmParser::VariableContext *context) = 0; + virtual std::any visitInstruction(CqasmParser::InstructionContext *context) = 0; + virtual std::any visitExpressionList(CqasmParser::ExpressionListContext *context) = 0; + virtual std::any visitExpression(CqasmParser::ExpressionContext *context) = 0; + virtual std::any visitIndex(CqasmParser::IndexContext *context) = 0; }; } // namespace cqasm::v3x::parser diff --git a/include/v3x/ScannerAntlr.hpp b/include/v3x/ScannerAntlr.hpp new file mode 100644 index 00000000..1874f6b4 --- /dev/null +++ b/include/v3x/ScannerAntlr.hpp @@ -0,0 +1,57 @@ +#pragma once + +#include "v3x/BuildCustomAstVisitor.hpp" +#include "v3x/CustomErrorListener.hpp" + +#include // unique_ptr +#include + + +namespace cqasm::v3x::parser { + +struct ScannerAdaptor { + virtual ~ScannerAdaptor(); + + virtual cqasm::v1x::parser::ParseResult parse() = 0; +}; + +class ScannerAntlr : public ScannerAdaptor { + std::unique_ptr build_visitor_up_; + std::unique_ptr error_listener_up_; +protected: + cqasm::v1x::parser::ParseResult parse_(antlr4::ANTLRInputStream &is); + +public: + explicit ScannerAntlr(std::unique_ptr build_visitor_up, + std::unique_ptr error_listener_up); + + ~ScannerAntlr() override; + + cqasm::v1x::parser::ParseResult parse() override = 0; +}; + +class ScannerAntlrFile : public ScannerAntlr { + std::string file_path_; +public: + ScannerAntlrFile(std::unique_ptr build_visitor_up, + std::unique_ptr error_listener_up, + const std::string &file_path); + + ~ScannerAntlrFile() override; + + cqasm::v1x::parser::ParseResult parse() override; +}; + +class ScannerAntlrString : public ScannerAntlr { + std::string data_; +public: + ScannerAntlrString(std::unique_ptr build_visitor_up, + std::unique_ptr error_listener_up, + const std::string &data); + + ~ScannerAntlrString() override; + + cqasm::v1x::parser::ParseResult parse() override; +}; + +} // namespace cqasm::v3x::parser diff --git a/include/v3x/cqasm-parse-helper.hpp b/include/v3x/cqasm-parse-helper.hpp index c8fe238a..8af3bff7 100644 --- a/include/v3x/cqasm-parse-helper.hpp +++ b/include/v3x/cqasm-parse-helper.hpp @@ -8,59 +8,15 @@ #include "cqasm-annotations.hpp" #include "v1x/cqasm-parse-result.hpp" -#include "v3x/BuildCustomAstVisitor.hpp" -#include "v3x/CustomErrorListener.hpp" +#include "v3x/ScannerAntlr.hpp" #include -#include // ifstream #include // unique_ptr #include namespace cqasm::v3x::parser { -// SourceLocation used to live in this namespace, before the v3x namespace was a thing. -// Make sure it exists here for compatibility. -using SourceLocation = annotations::SourceLocation; - - -struct ScannerAdaptor { - virtual ~ScannerAdaptor(); - - virtual cqasm::v1x::parser::ParseResult parse() = 0; -}; - -class ScannerAntlr : public ScannerAdaptor { - std::unique_ptr build_visitor_up_; - std::unique_ptr error_listener_up_; -protected: - cqasm::v1x::parser::ParseResult parse_(antlr4::ANTLRInputStream &is); -public: - explicit ScannerAntlr(std::unique_ptr build_visitor_up, - std::unique_ptr error_listener_up); - ~ScannerAntlr() override; - cqasm::v1x::parser::ParseResult parse() override = 0; -}; - -class ScannerAntlrFile : public ScannerAntlr { - std::string file_path_; -public: - ScannerAntlrFile(std::unique_ptr build_visitor_up, - std::unique_ptr error_listener_up, const std::string &file_path); - ~ScannerAntlrFile() override; - cqasm::v1x::parser::ParseResult parse() override; -}; - -class ScannerAntlrString : public ScannerAntlr { - std::string data_; -public: - ScannerAntlrString(std::unique_ptr build_visitor_up, - std::unique_ptr error_listener_up, const std::string &data); - ~ScannerAntlrString() override; - cqasm::v1x::parser::ParseResult parse() override; -}; - - /** * Parse using the given file path. * Throws an AnalysisError if this fails. diff --git a/src/v3x/BuildTreeGenAstVisitor.cpp b/src/v3x/BuildTreeGenAstVisitor.cpp index ba595a71..b5bdd7c0 100644 --- a/src/v3x/BuildTreeGenAstVisitor.cpp +++ b/src/v3x/BuildTreeGenAstVisitor.cpp @@ -2,6 +2,7 @@ #include "v1x/cqasm-ast.hpp" #include "v3x/BuildTreeGenAstVisitor.hpp" +#include // for_each #include // assert #include // runtime_error #include // stod, stoll @@ -13,29 +14,11 @@ using namespace cqasm::v1x::ast; using namespace cqasm::error; std::int64_t get_integer_literal_value(antlr4::tree::TerminalNode *node) { - auto text = node->getText(); - std::int64_t ret{}; - try { - ret = std::stoll(text); - } catch (std::invalid_argument&) { - throw std::runtime_error{ "terminal node is not of the expected INTEGER_LITERAL type." }; - } catch (std::out_of_range&) { - throw std::runtime_error{ "terminal node is out of the INTEGER_LITERAL range" }; - } - return ret; + return std::stoll(node->getText()); } double get_float_literal_value(antlr4::tree::TerminalNode *node) { - auto text = node->getText(); - double ret{}; - try { - ret = std::stod(text); - } catch (std::invalid_argument&) { - throw std::runtime_error{ "terminal node is not of the expected FLOAT_LITERAL type." }; - } catch (std::out_of_range&) { - throw std::runtime_error{ "terminal node is out of the FLOAT_LITERAL range" }; - } - return ret; + return std::stod(node->getText()); } std::any BuildTreeGenAstVisitor::visitProgram(CqasmParser::ProgramContext *context) { @@ -45,27 +28,27 @@ std::any BuildTreeGenAstVisitor::visitProgram(CqasmParser::ProgramContext *conte ret->num_qubits = std::any_cast>(visitQubits(qubits_ctx)); } ret->statements = cqasm::tree::make(); - for (size_t i{ 0 }; i < context->statement().size(); ++i) { - ret->statements->items.add(std::any_cast>(visitStatement(context->statement(i)))); - } + const auto &statements = context->statement(); + std::for_each(statements.begin(), statements.end(), [this, &ret](auto &statement_ctx) { + ret->statements->items.add(std::any_cast>(visitStatement(statement_ctx))); + }); return ret; } std::any BuildTreeGenAstVisitor::visitVersion(CqasmParser::VersionContext *context) { auto ret = cqasm::tree::make(); - for (size_t i{ 0 }; i < context->INTEGER_LITERAL().size(); ++i) { - auto number = get_integer_literal_value(context->INTEGER_LITERAL(i)); + const auto& integer_literals = context->INTEGER_LITERAL(); + std::for_each(integer_literals.begin(), integer_literals.end(), [this, &ret](auto *integer_literal_node) { + auto number = get_integer_literal_value(integer_literal_node); ret->items.push_back(number); - } + }); return ret; } std::any BuildTreeGenAstVisitor::visitQubits(CqasmParser::QubitsContext *context) { - auto ret = Maybe{}; - if (auto qubits_ctx = context->QUBITS(); qubits_ctx->getText() == "qubits") { - ret.set(std::any_cast>(visitExpression(context->expression())).get_ptr()); - } - return ret; + return Maybe{ + std::any_cast>(visitExpression(context->expression())).get_ptr() + }; } std::any BuildTreeGenAstVisitor::visitStatement(CqasmParser::StatementContext *context) { @@ -78,30 +61,22 @@ std::any BuildTreeGenAstVisitor::visitStatement(CqasmParser::StatementContext *c ret = cqasm::tree::make(Many{ std::any_cast>(visitInstruction(instruction_ctx)) }); - } else { - throw std::runtime_error{ "unknown statement type" }; } return ret; } std::any BuildTreeGenAstVisitor::visitMapping(CqasmParser::MappingContext *context) { auto ret = Mapping{}; - if (auto mapping_ctx = context->MAP(); mapping_ctx->getText() == "map") { - ret.alias = cqasm::tree::make(context->IDENTIFIER()->getText()); - ret.expr = std::any_cast>(visitExpression(context->expression())); - } + ret.alias = cqasm::tree::make(context->IDENTIFIER()->getText()); + ret.expr = std::any_cast>(visitExpression(context->expression())); return ret; } std::any BuildTreeGenAstVisitor::visitVariable(CqasmParser::VariableContext *context) { - auto ret = Variables{}; - if (auto variable_ctx = context->VAR(); variable_ctx->getText() == "var") { - assert(context->IDENTIFIER().size() == 2); - ret.names.add(cqasm::tree::make(context->IDENTIFIER(0)->getText())); - ret.typ = cqasm::tree::make(context->IDENTIFIER(1)->getText()); - - } - return ret; + return Variables{ + Many{ cqasm::tree::make(context->IDENTIFIER(0)->getText()) }, // names + cqasm::tree::make(context->IDENTIFIER(1)->getText()) // typ + }; } std::any BuildTreeGenAstVisitor::visitInstruction(CqasmParser::InstructionContext *context) { @@ -114,27 +89,26 @@ std::any BuildTreeGenAstVisitor::visitInstruction(CqasmParser::InstructionContex std::any BuildTreeGenAstVisitor::visitExpressionList(CqasmParser::ExpressionListContext *context) { auto ret = ExpressionList{}; - for (size_t i{ 0 }; i < context->expression().size(); ++i) { - ret.items.add(std::any_cast>(visitExpression(context->expression(i)))); - } + const auto &expressions = context->expression(); + std::for_each(expressions.begin(), expressions.end(), [this, &ret](auto &expression_ctx) { + ret.items.add(std::any_cast>(visitExpression(expression_ctx))); + }); return ret; } std::any BuildTreeGenAstVisitor::visitExpression(CqasmParser::ExpressionContext *context) { auto ret = One{}; - if (auto integer_literal_ast = context->INTEGER_LITERAL()) { - auto integer_literal = get_integer_literal_value(integer_literal_ast); + if (auto *integer_literal_node = context->INTEGER_LITERAL()) { + auto integer_literal = get_integer_literal_value(integer_literal_node); ret = cqasm::tree::make(integer_literal); - } else if (auto float_literal_ast = context->FLOAT_LITERAL()) { - auto float_literal = get_float_literal_value(float_literal_ast); + } else if (auto *float_literal_node = context->FLOAT_LITERAL()) { + auto float_literal = get_float_literal_value(float_literal_node); ret = cqasm::tree::make(float_literal); - } else if (auto id_ast = context->IDENTIFIER()) { - auto id = id_ast->getText(); + } else if (auto *id_node = context->IDENTIFIER()) { + auto id = id_node->getText(); ret = cqasm::tree::make(std::move(id)); } else if (auto index_ctx = context->index()) { ret = cqasm::tree::make(std::any_cast(visitIndex(index_ctx))); - } else { - throw std::runtime_error{ "unknown expression type" }; } return ret; } @@ -146,7 +120,7 @@ std::any BuildTreeGenAstVisitor::visitIndex(CqasmParser::IndexContext *context) ret.indices = cqasm::tree::make(); auto index_item = cqasm::tree::make(std::any_cast>( visitExpression(context->expression()))); - ret.indices->items.add(std::move(index_item)); + ret.indices->items.add(index_item); return ret; } diff --git a/src/v3x/CMakeLists.txt b/src/v3x/CMakeLists.txt index 9eae3084..67285710 100644 --- a/src/v3x/CMakeLists.txt +++ b/src/v3x/CMakeLists.txt @@ -4,5 +4,6 @@ set(CQASM_V3X_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/cqasm-parse-helper.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/BuildTreeGenAstVisitor.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/CustomErrorListener.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/ScannerAntlr.cpp" PARENT_SCOPE ) diff --git a/src/v3x/ScannerAntlr.cpp b/src/v3x/ScannerAntlr.cpp new file mode 100644 index 00000000..a8c5e637 --- /dev/null +++ b/src/v3x/ScannerAntlr.cpp @@ -0,0 +1,72 @@ +#include "v1x/cqasm-ast.hpp" +#include "v1x/cqasm-parse-result.hpp" +#include "v3x/BuildTreeGenAstVisitor.hpp" +#include "v3x/CqasmLexer.h" +#include "v3x/CqasmParser.h" +#include "v3x/ScannerAntlr.hpp" + +#include +#include + +namespace fs = std::filesystem; + + +namespace cqasm::v3x::parser { + +ScannerAdaptor::~ScannerAdaptor() {} + +ScannerAntlr::ScannerAntlr(std::unique_ptr build_visitor_up, + std::unique_ptr error_listener_up) +: build_visitor_up_{ std::move(build_visitor_up) } +, error_listener_up_{std::move(error_listener_up)} {} + +ScannerAntlr::~ScannerAntlr() {} + +cqasm::v1x::parser::ParseResult ScannerAntlr::parse_(antlr4::ANTLRInputStream &is) { + CqasmLexer lexer{ &is }; + lexer.removeErrorListeners(); + lexer.addErrorListener(error_listener_up_.get()); + antlr4::CommonTokenStream tokens{ &lexer }; + CqasmParser parser{ &tokens }; + parser.removeErrorListeners(); + parser.addErrorListener(error_listener_up_.get()); + auto ast = parser.program(); + auto custom_ast = build_visitor_up_->visitProgram(ast); + return cqasm::v1x::parser::ParseResult{ + std::any_cast> (custom_ast), // root + {} // error + }; +} + +ScannerAntlrFile::ScannerAntlrFile(std::unique_ptr build_visitor_up, + std::unique_ptr error_listener_up, + const std::string &file_path) +: ScannerAntlr{ std::move(build_visitor_up) , std::move(error_listener_up) } +, file_path_{file_path } { + if (!fs::exists(file_path_) || !fs::is_regular_file(file_path_)) { + throw cqasm::error::AnalysisError{ fmt::format("ScannerAntlrFile couldn't access file '{}'.", file_path_) }; + } +} + +ScannerAntlrFile::~ScannerAntlrFile() {} + +cqasm::v1x::parser::ParseResult ScannerAntlrFile::parse() { + antlr4::ANTLRFileStream ifs{}; + ifs.loadFromFile(file_path_); + return parse_(ifs); +} + +ScannerAntlrString::ScannerAntlrString(std::unique_ptr build_visitor_up, + std::unique_ptr error_listener_up, + const std::string &data) +: ScannerAntlr{ std::move(build_visitor_up), std::move(error_listener_up) } +, data_{ data } {} + +ScannerAntlrString::~ScannerAntlrString() {} + +cqasm::v1x::parser::ParseResult ScannerAntlrString::parse() { + antlr4::ANTLRInputStream is{ data_ }; + return parse_(is); +} + +} // namespace cqasm::v3x::parser diff --git a/src/v3x/cqasm-parse-helper.cpp b/src/v3x/cqasm-parse-helper.cpp index 02f11de5..c1fd1f66 100644 --- a/src/v3x/cqasm-parse-helper.cpp +++ b/src/v3x/cqasm-parse-helper.cpp @@ -2,71 +2,14 @@ * Implementation for \ref include/v3x/cqasm-parse-helper.hpp "v3x/cqasm-parse-helper.hpp". */ -#include "v1x/cqasm-ast.hpp" #include "v1x/cqasm-parse-result.hpp" #include "v3x/BuildTreeGenAstVisitor.hpp" #include "v3x/cqasm-parse-helper.hpp" -#include "v3x/CqasmLexer.h" -#include "v3x/CqasmParser.h" - -#include -#include - -namespace fs = std::filesystem; +#include "v3x/ScannerAntlr.hpp" namespace cqasm::v3x::parser { -using namespace cqasm::v1x::ast; - -ScannerAdaptor::~ScannerAdaptor() {} - -ScannerAntlr::ScannerAntlr(std::unique_ptr build_visitor_up, - std::unique_ptr error_listener_up) -: build_visitor_up_{ std::move(build_visitor_up) } -, error_listener_up_{ std::move(error_listener_up) } {} - -ScannerAntlr::~ScannerAntlr() {} - -cqasm::v1x::parser::ParseResult ScannerAntlr::parse_(antlr4::ANTLRInputStream &is) { - CqasmLexer lexer{ &is }; - lexer.removeErrorListeners(); - lexer.addErrorListener(error_listener_up_.get()); - antlr4::CommonTokenStream tokens{ &lexer }; - CqasmParser parser{ &tokens }; - parser.removeErrorListeners(); - parser.addErrorListener(error_listener_up_.get()); - auto ast = parser.program(); - auto custom_ast = build_visitor_up_->visitProgram(ast); - return cqasm::v1x::parser::ParseResult{ std::any_cast>(custom_ast), {} }; -} - -ScannerAntlrFile::ScannerAntlrFile(std::unique_ptr build_visitor_up, - std::unique_ptr error_listener_up, const std::string &file_path) -: ScannerAntlr{ std::move(build_visitor_up), std::move(error_listener_up) }, file_path_{ file_path } { - if (!fs::exists(file_path_) || !fs::is_regular_file(file_path_)) { - throw error::AnalysisError{ fmt::format("ScannerAntlrFile couldn't access file '{}'.", file_path_) }; - } -} -ScannerAntlrFile::~ScannerAntlrFile() {} - -cqasm::v1x::parser::ParseResult ScannerAntlrFile::parse() { - antlr4::ANTLRFileStream ifs{}; - ifs.loadFromFile(file_path_); - return parse_(ifs); -} - -ScannerAntlrString::ScannerAntlrString(std::unique_ptr build_visitor_up, - std::unique_ptr error_listener_up, const std::string &data) -: ScannerAntlr{ std::move(build_visitor_up), std::move(error_listener_up) }, data_{ data } {} - -ScannerAntlrString::~ScannerAntlrString() {} - -cqasm::v1x::parser::ParseResult ScannerAntlrString::parse() { - antlr4::ANTLRInputStream is{ data_ }; - return parse_(is); -} - /** * Parse using the given file path. * Throws an AnalysisError if the file does not exist. diff --git a/src/v3x/cqasm.cpp b/src/v3x/cqasm.cpp index 1b4179e8..ed5e3a41 100644 --- a/src/v3x/cqasm.cpp +++ b/src/v3x/cqasm.cpp @@ -25,8 +25,8 @@ tree::One analyze( const std::string &api_version ) { return cqasm::v1x::default_analyzer(api_version).analyze( - [=](){ return version::parse_file(file_path); }, - [=](){ return cqasm::v3x::parser::parse_file(file_path); } + [&file_path]() { return version::parse_file(file_path); }, + [&file_path]() { return cqasm::v3x::parser::parse_file(file_path); } ).unwrap(); } @@ -41,8 +41,8 @@ tree::One analyze_string( const std::string &api_version ) { return cqasm::v1x::default_analyzer(api_version).analyze( - [=](){ return version::parse_string(data, file_name); }, - [=](){ return cqasm::v3x::parser::parse_string(data, file_name); } + [&data, &file_name]() { return version::parse_string(data, file_name); }, + [&data, &file_name]() { return cqasm::v3x::parser::parse_string(data, file_name); } ).unwrap(); } From e2e4b81d73cd25603064d48b474b7f916118ce24 Mon Sep 17 00:00:00 2001 From: rturrado <68099809+rturrado@users.noreply.github.com> Date: Fri, 22 Sep 2023 22:46:37 +0200 Subject: [PATCH 20/28] Trying to fix MacOS build error. --- src/v3x/BuildTreeGenAstVisitor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/v3x/BuildTreeGenAstVisitor.cpp b/src/v3x/BuildTreeGenAstVisitor.cpp index b5bdd7c0..d0bac5f3 100644 --- a/src/v3x/BuildTreeGenAstVisitor.cpp +++ b/src/v3x/BuildTreeGenAstVisitor.cpp @@ -38,7 +38,7 @@ std::any BuildTreeGenAstVisitor::visitProgram(CqasmParser::ProgramContext *conte std::any BuildTreeGenAstVisitor::visitVersion(CqasmParser::VersionContext *context) { auto ret = cqasm::tree::make(); const auto& integer_literals = context->INTEGER_LITERAL(); - std::for_each(integer_literals.begin(), integer_literals.end(), [this, &ret](auto *integer_literal_node) { + std::for_each(integer_literals.begin(), integer_literals.end(), [&ret](auto *integer_literal_node) { auto number = get_integer_literal_value(integer_literal_node); ret->items.push_back(number); }); From 0e6b95163842dd47ba7f431f2ce24522a129e2c9 Mon Sep 17 00:00:00 2001 From: rturrado <68099809+rturrado@users.noreply.github.com> Date: Sat, 23 Sep 2023 00:56:46 +0200 Subject: [PATCH 21/28] Updated tree-gen commit ID, now to one in master. --- src/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 7a10b3f5..daf78680 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -44,7 +44,7 @@ include(FetchContent) # This exposes the generate_tree() function. FetchContent_Declare(tree-gen GIT_REPOSITORY https://github.com/QuTech-Delft/tree-gen.git - GIT_TAG "42b91f0b641cde8e8e162a0574aa0ce20a9e25d2" + GIT_TAG "64819883ff88d4bfa5ec160df86e6c9167c97a7e" ) FetchContent_MakeAvailable(tree-gen) From 60db46c61e0670afe93333a426aa026faad2d697 Mon Sep 17 00:00:00 2001 From: rturrado <68099809+rturrado@users.noreply.github.com> Date: Tue, 26 Sep 2023 15:45:18 +0200 Subject: [PATCH 22/28] Addressed some of the comments from Pablo's code review. - BuildTreeGenAstVisitor checks for out of range exceptions when converting integer and float string literals. Also, although unrelated, took the opportunity to do some CMake changes: - Added LANGUAGES to 'project(cqasm)' at CMakeLists.txt. - Updated tree-gen to a version that fixes some warnings. --- CMakeLists.txt | 2 +- include/v3x/BuildTreeGenAstVisitor.hpp | 10 +++++ include/v3x/ScannerAntlr.hpp | 12 +++--- .../out_of_range_float_literal/ast.golden.txt | 2 + .../out_of_range_float_literal/input.cq | 2 + .../ast.golden.txt | 2 + .../out_of_range_integer_literal/input.cq | 2 + src/CMakeLists.txt | 2 +- src/v3x/BuildTreeGenAstVisitor.cpp | 40 ++++++++++++++++--- src/v3x/ScannerAntlr.cpp | 17 ++++---- src/v3x/cqasm-parse-helper.cpp | 4 +- 11 files changed, 72 insertions(+), 23 deletions(-) create mode 100644 res/v1x/toy-v1x-parsing/expression/out_of_range_float_literal/ast.golden.txt create mode 100644 res/v1x/toy-v1x-parsing/expression/out_of_range_float_literal/input.cq create mode 100644 res/v1x/toy-v1x-parsing/expression/out_of_range_integer_literal/ast.golden.txt create mode 100644 res/v1x/toy-v1x-parsing/expression/out_of_range_integer_literal/input.cq diff --git a/CMakeLists.txt b/CMakeLists.txt index 662c22ff..a1aa6e94 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -13,7 +13,7 @@ if(POLICY CMP0148) cmake_policy(SET CMP0148 NEW) endif() -project(cqasm C CXX) +project(cqasm LANGUAGES C CXX) # If cqasm was already included elsewhere in the project, don't include it again. # There should be only one place for it and one version per project. diff --git a/include/v3x/BuildTreeGenAstVisitor.hpp b/include/v3x/BuildTreeGenAstVisitor.hpp index 3bf7ee01..aeaf7d4d 100644 --- a/include/v3x/BuildTreeGenAstVisitor.hpp +++ b/include/v3x/BuildTreeGenAstVisitor.hpp @@ -10,6 +10,13 @@ namespace cqasm::v3x::parser { class BuildTreeGenAstVisitor : public BuildCustomAstVisitor { + /** + * Name of the file being parsed. + */ + std::string file_name_; + + std::int64_t get_integer_literal_value(antlr4::tree::TerminalNode *node); + double get_float_literal_value(antlr4::tree::TerminalNode *node); public: std::any visitProgram(CqasmParser::ProgramContext *context) override; std::any visitVersion(CqasmParser::VersionContext *context) override; @@ -21,6 +28,9 @@ class BuildTreeGenAstVisitor : public BuildCustomAstVisitor { std::any visitExpressionList(CqasmParser::ExpressionListContext *context) override; std::any visitExpression(CqasmParser::ExpressionContext *context) override; std::any visitIndex(CqasmParser::IndexContext *context) override; + + explicit BuildTreeGenAstVisitor(const std::string &file_name = "") + : file_name_{ file_name } {} }; } // namespace cqasm::v3x::parser diff --git a/include/v3x/ScannerAntlr.hpp b/include/v3x/ScannerAntlr.hpp index 1874f6b4..d9fa23e1 100644 --- a/include/v3x/ScannerAntlr.hpp +++ b/include/v3x/ScannerAntlr.hpp @@ -22,8 +22,8 @@ class ScannerAntlr : public ScannerAdaptor { cqasm::v1x::parser::ParseResult parse_(antlr4::ANTLRInputStream &is); public: - explicit ScannerAntlr(std::unique_ptr build_visitor_up, - std::unique_ptr error_listener_up); + ScannerAntlr(std::unique_ptr build_visitor_up, + std::unique_ptr error_listener_up); ~ScannerAntlr() override; @@ -34,8 +34,8 @@ class ScannerAntlrFile : public ScannerAntlr { std::string file_path_; public: ScannerAntlrFile(std::unique_ptr build_visitor_up, - std::unique_ptr error_listener_up, - const std::string &file_path); + std::unique_ptr error_listener_up, + const std::string &file_path); ~ScannerAntlrFile() override; @@ -46,8 +46,8 @@ class ScannerAntlrString : public ScannerAntlr { std::string data_; public: ScannerAntlrString(std::unique_ptr build_visitor_up, - std::unique_ptr error_listener_up, - const std::string &data); + std::unique_ptr error_listener_up, + const std::string &data); ~ScannerAntlrString() override; diff --git a/res/v1x/toy-v1x-parsing/expression/out_of_range_float_literal/ast.golden.txt b/res/v1x/toy-v1x-parsing/expression/out_of_range_float_literal/ast.golden.txt new file mode 100644 index 00000000..e6ef2e2b --- /dev/null +++ b/res/v1x/toy-v1x-parsing/expression/out_of_range_float_literal/ast.golden.txt @@ -0,0 +1,2 @@ +ERROR +input.cq:2:2: value '1.79769313486231570e+309' is out of the FLOATING_LITERAL range diff --git a/res/v1x/toy-v1x-parsing/expression/out_of_range_float_literal/input.cq b/res/v1x/toy-v1x-parsing/expression/out_of_range_float_literal/input.cq new file mode 100644 index 00000000..d81158d9 --- /dev/null +++ b/res/v1x/toy-v1x-parsing/expression/out_of_range_float_literal/input.cq @@ -0,0 +1,2 @@ +version 3 +x 1.79769313486231570e+309 # biggest double is 1.79769313486231570e+308 \ No newline at end of file diff --git a/res/v1x/toy-v1x-parsing/expression/out_of_range_integer_literal/ast.golden.txt b/res/v1x/toy-v1x-parsing/expression/out_of_range_integer_literal/ast.golden.txt new file mode 100644 index 00000000..904ef894 --- /dev/null +++ b/res/v1x/toy-v1x-parsing/expression/out_of_range_integer_literal/ast.golden.txt @@ -0,0 +1,2 @@ +ERROR +input.cq:2:2: value '18446744073709551616' is out of the INTEGER_LITERAL range diff --git a/res/v1x/toy-v1x-parsing/expression/out_of_range_integer_literal/input.cq b/res/v1x/toy-v1x-parsing/expression/out_of_range_integer_literal/input.cq new file mode 100644 index 00000000..1d828f30 --- /dev/null +++ b/res/v1x/toy-v1x-parsing/expression/out_of_range_integer_literal/input.cq @@ -0,0 +1,2 @@ +version 3 +x 18446744073709551616 # biggest 64-bit integer is 18446744073709551615 \ No newline at end of file diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index daf78680..fc8b3fc3 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -44,7 +44,7 @@ include(FetchContent) # This exposes the generate_tree() function. FetchContent_Declare(tree-gen GIT_REPOSITORY https://github.com/QuTech-Delft/tree-gen.git - GIT_TAG "64819883ff88d4bfa5ec160df86e6c9167c97a7e" + GIT_TAG "6a1339ea1ccb74b5ded2a86405a9143c7ef1a067" ) FetchContent_MakeAvailable(tree-gen) diff --git a/src/v3x/BuildTreeGenAstVisitor.cpp b/src/v3x/BuildTreeGenAstVisitor.cpp index d0bac5f3..8403941b 100644 --- a/src/v3x/BuildTreeGenAstVisitor.cpp +++ b/src/v3x/BuildTreeGenAstVisitor.cpp @@ -3,7 +3,7 @@ #include "v3x/BuildTreeGenAstVisitor.hpp" #include // for_each -#include // assert +#include #include // runtime_error #include // stod, stoll @@ -13,12 +13,40 @@ namespace cqasm::v3x::parser { using namespace cqasm::v1x::ast; using namespace cqasm::error; -std::int64_t get_integer_literal_value(antlr4::tree::TerminalNode *node) { - return std::stoll(node->getText()); +std::int64_t BuildTreeGenAstVisitor::get_integer_literal_value(antlr4::tree::TerminalNode *node) { + auto text = node->getText(); + std::int64_t ret{}; + try { + ret = std::stoll(text); + } catch (std::out_of_range&) { + const auto &token = node->getSymbol(); + throw std::runtime_error{ + fmt::format("{}:{}:{}: value '{}' is out of the INTEGER_LITERAL range", + file_name_, + token->getLine(), + token->getCharPositionInLine(), + text + )}; + } + return ret; } -double get_float_literal_value(antlr4::tree::TerminalNode *node) { - return std::stod(node->getText()); +double BuildTreeGenAstVisitor::get_float_literal_value(antlr4::tree::TerminalNode *node) { + auto text = node->getText(); + double ret{}; + try { + ret = std::stod(text); + } catch (std::out_of_range&) { + const auto &token = node->getSymbol(); + throw std::runtime_error{ + fmt::format("{}:{}:{}: value '{}' is out of the FLOATING_LITERAL range", + file_name_, + token->getLine(), + token->getCharPositionInLine(), + text + )}; + } + return ret; } std::any BuildTreeGenAstVisitor::visitProgram(CqasmParser::ProgramContext *context) { @@ -38,7 +66,7 @@ std::any BuildTreeGenAstVisitor::visitProgram(CqasmParser::ProgramContext *conte std::any BuildTreeGenAstVisitor::visitVersion(CqasmParser::VersionContext *context) { auto ret = cqasm::tree::make(); const auto& integer_literals = context->INTEGER_LITERAL(); - std::for_each(integer_literals.begin(), integer_literals.end(), [&ret](auto *integer_literal_node) { + std::for_each(integer_literals.begin(), integer_literals.end(), [this, &ret](auto *integer_literal_node) { auto number = get_integer_literal_value(integer_literal_node); ret->items.push_back(number); }); diff --git a/src/v3x/ScannerAntlr.cpp b/src/v3x/ScannerAntlr.cpp index a8c5e637..da045e8c 100644 --- a/src/v3x/ScannerAntlr.cpp +++ b/src/v3x/ScannerAntlr.cpp @@ -16,7 +16,7 @@ namespace cqasm::v3x::parser { ScannerAdaptor::~ScannerAdaptor() {} ScannerAntlr::ScannerAntlr(std::unique_ptr build_visitor_up, - std::unique_ptr error_listener_up) + std::unique_ptr error_listener_up) : build_visitor_up_{ std::move(build_visitor_up) } , error_listener_up_{std::move(error_listener_up)} {} @@ -26,23 +26,26 @@ cqasm::v1x::parser::ParseResult ScannerAntlr::parse_(antlr4::ANTLRInputStream &i CqasmLexer lexer{ &is }; lexer.removeErrorListeners(); lexer.addErrorListener(error_listener_up_.get()); + antlr4::CommonTokenStream tokens{ &lexer }; + CqasmParser parser{ &tokens }; parser.removeErrorListeners(); parser.addErrorListener(error_listener_up_.get()); + auto ast = parser.program(); auto custom_ast = build_visitor_up_->visitProgram(ast); return cqasm::v1x::parser::ParseResult{ - std::any_cast> (custom_ast), // root + std::any_cast>(custom_ast), // root {} // error }; } ScannerAntlrFile::ScannerAntlrFile(std::unique_ptr build_visitor_up, - std::unique_ptr error_listener_up, - const std::string &file_path) + std::unique_ptr error_listener_up, + const std::string &file_path) : ScannerAntlr{ std::move(build_visitor_up) , std::move(error_listener_up) } -, file_path_{file_path } { +, file_path_{ file_path } { if (!fs::exists(file_path_) || !fs::is_regular_file(file_path_)) { throw cqasm::error::AnalysisError{ fmt::format("ScannerAntlrFile couldn't access file '{}'.", file_path_) }; } @@ -57,8 +60,8 @@ cqasm::v1x::parser::ParseResult ScannerAntlrFile::parse() { } ScannerAntlrString::ScannerAntlrString(std::unique_ptr build_visitor_up, - std::unique_ptr error_listener_up, - const std::string &data) + std::unique_ptr error_listener_up, + const std::string &data) : ScannerAntlr{ std::move(build_visitor_up), std::move(error_listener_up) } , data_{ data } {} diff --git a/src/v3x/cqasm-parse-helper.cpp b/src/v3x/cqasm-parse-helper.cpp index c1fd1f66..45190a1d 100644 --- a/src/v3x/cqasm-parse-helper.cpp +++ b/src/v3x/cqasm-parse-helper.cpp @@ -16,7 +16,7 @@ namespace cqasm::v3x::parser { * A file_name may be given in addition for use within error messages. */ cqasm::v1x::parser::ParseResult parse_file(const std::string &file_path, const std::string &file_name) { - auto builder_visitor_up = std::make_unique(); + auto builder_visitor_up = std::make_unique(file_name); auto error_listener_up = std::make_unique(file_name); auto scanner_up = std::make_unique( std::move(builder_visitor_up), std::move(error_listener_up), file_path); @@ -28,7 +28,7 @@ cqasm::v1x::parser::ParseResult parse_file(const std::string &file_path, const s * A file_name may be given in addition for use within error messages. */ cqasm::v1x::parser::ParseResult parse_string(const std::string &data, const std::string &file_name) { - auto builder_visitor_up = std::make_unique(); + auto builder_visitor_up = std::make_unique(file_name); auto error_listener_up = std::make_unique(file_name); auto scanner_up = std::make_unique( std::move(builder_visitor_up), std::move(error_listener_up), data); From d0a4e0fe9d5a7bde99118fafecdff2d65c690c37 Mon Sep 17 00:00:00 2001 From: rturrado <68099809+rturrado@users.noreply.github.com> Date: Wed, 27 Sep 2023 00:49:09 +0200 Subject: [PATCH 23/28] Changed grammar to use alternative labels. This simplifies a bit the visitor, since you don't need neither the visitStatement nor the visitExpression methods. Furthermore, you avoid having a block consisting of a sequence of if-else statements as implementation for these methods. --- include/v3x/BuildCustomAstVisitor.hpp | 5 +- include/v3x/BuildTreeGenAstVisitor.hpp | 5 +- src/v3x/BuildTreeGenAstVisitor.cpp | 102 ++++++++++--------------- src/v3x/CqasmParser.g4 | 23 +++--- 4 files changed, 57 insertions(+), 78 deletions(-) diff --git a/include/v3x/BuildCustomAstVisitor.hpp b/include/v3x/BuildCustomAstVisitor.hpp index e42fe575..a84a3749 100644 --- a/include/v3x/BuildCustomAstVisitor.hpp +++ b/include/v3x/BuildCustomAstVisitor.hpp @@ -13,12 +13,13 @@ class BuildCustomAstVisitor : public CqasmParserVisitor { virtual std::any visitProgram(CqasmParser::ProgramContext *context) = 0; virtual std::any visitVersion(CqasmParser::VersionContext *context) = 0; virtual std::any visitQubits(CqasmParser::QubitsContext *context) = 0; - virtual std::any visitStatement(CqasmParser::StatementContext *context) = 0; virtual std::any visitMapping(CqasmParser::MappingContext *context) = 0; virtual std::any visitVariable(CqasmParser::VariableContext *context) = 0; virtual std::any visitInstruction(CqasmParser::InstructionContext *context) = 0; virtual std::any visitExpressionList(CqasmParser::ExpressionListContext *context) = 0; - virtual std::any visitExpression(CqasmParser::ExpressionContext *context) = 0; + virtual std::any visitIntegerLiteral(CqasmParser::IntegerLiteralContext *context) = 0; + virtual std::any visitFloatLiteral(CqasmParser::FloatLiteralContext *context) = 0; + virtual std::any visitIdentifier(CqasmParser::IdentifierContext *context) = 0; virtual std::any visitIndex(CqasmParser::IndexContext *context) = 0; }; diff --git a/include/v3x/BuildTreeGenAstVisitor.hpp b/include/v3x/BuildTreeGenAstVisitor.hpp index aeaf7d4d..4526199c 100644 --- a/include/v3x/BuildTreeGenAstVisitor.hpp +++ b/include/v3x/BuildTreeGenAstVisitor.hpp @@ -21,12 +21,13 @@ class BuildTreeGenAstVisitor : public BuildCustomAstVisitor { std::any visitProgram(CqasmParser::ProgramContext *context) override; std::any visitVersion(CqasmParser::VersionContext *context) override; std::any visitQubits(CqasmParser::QubitsContext *context) override; - std::any visitStatement(CqasmParser::StatementContext *context) override; std::any visitMapping(CqasmParser::MappingContext *context) override; std::any visitVariable(CqasmParser::VariableContext *context) override; std::any visitInstruction(CqasmParser::InstructionContext *context) override; std::any visitExpressionList(CqasmParser::ExpressionListContext *context) override; - std::any visitExpression(CqasmParser::ExpressionContext *context) override; + std::any visitIntegerLiteral(CqasmParser::IntegerLiteralContext *context) override; + std::any visitFloatLiteral(CqasmParser::FloatLiteralContext *context) override; + std::any visitIdentifier(CqasmParser::IdentifierContext *context) override; std::any visitIndex(CqasmParser::IndexContext *context) override; explicit BuildTreeGenAstVisitor(const std::string &file_name = "") diff --git a/src/v3x/BuildTreeGenAstVisitor.cpp b/src/v3x/BuildTreeGenAstVisitor.cpp index 8403941b..0b428732 100644 --- a/src/v3x/BuildTreeGenAstVisitor.cpp +++ b/src/v3x/BuildTreeGenAstVisitor.cpp @@ -22,10 +22,7 @@ std::int64_t BuildTreeGenAstVisitor::get_integer_literal_value(antlr4::tree::Ter const auto &token = node->getSymbol(); throw std::runtime_error{ fmt::format("{}:{}:{}: value '{}' is out of the INTEGER_LITERAL range", - file_name_, - token->getLine(), - token->getCharPositionInLine(), - text + file_name_, token->getLine(), token->getCharPositionInLine(), text )}; } return ret; @@ -40,10 +37,7 @@ double BuildTreeGenAstVisitor::get_float_literal_value(antlr4::tree::TerminalNod const auto &token = node->getSymbol(); throw std::runtime_error{ fmt::format("{}:{}:{}: value '{}' is out of the FLOATING_LITERAL range", - file_name_, - token->getLine(), - token->getCharPositionInLine(), - text + file_name_, token->getLine(), token->getCharPositionInLine(), text )}; } return ret; @@ -58,7 +52,7 @@ std::any BuildTreeGenAstVisitor::visitProgram(CqasmParser::ProgramContext *conte ret->statements = cqasm::tree::make(); const auto &statements = context->statement(); std::for_each(statements.begin(), statements.end(), [this, &ret](auto &statement_ctx) { - ret->statements->items.add(std::any_cast>(visitStatement(statement_ctx))); + ret->statements->items.add(std::any_cast>(statement_ctx->accept(this))); }); return ret; } @@ -75,81 +69,67 @@ std::any BuildTreeGenAstVisitor::visitVersion(CqasmParser::VersionContext *conte std::any BuildTreeGenAstVisitor::visitQubits(CqasmParser::QubitsContext *context) { return Maybe{ - std::any_cast>(visitExpression(context->expression())).get_ptr() + std::any_cast>(context->expression()->accept(this)).get_ptr() }; } -std::any BuildTreeGenAstVisitor::visitStatement(CqasmParser::StatementContext *context) { - auto ret = One{}; - if (auto mapping_ctx = context->mapping()) { - ret = cqasm::tree::make(std::any_cast(visitMapping(mapping_ctx))); - } else if (auto variable_ctx = context->variable()) { - ret = cqasm::tree::make(std::any_cast(visitVariable(variable_ctx))); - } else if (auto instruction_ctx = context->instruction()) { - ret = cqasm::tree::make(Many{ - std::any_cast>(visitInstruction(instruction_ctx)) - }); - } - return ret; -} - std::any BuildTreeGenAstVisitor::visitMapping(CqasmParser::MappingContext *context) { - auto ret = Mapping{}; - ret.alias = cqasm::tree::make(context->IDENTIFIER()->getText()); - ret.expr = std::any_cast>(visitExpression(context->expression())); - return ret; + auto ret = cqasm::tree::make(); + ret->alias = cqasm::tree::make(context->IDENTIFIER()->getText()); + ret->expr = std::any_cast>(context->expression()->accept(this)); + return One{ ret }; } std::any BuildTreeGenAstVisitor::visitVariable(CqasmParser::VariableContext *context) { - return Variables{ - Many{ cqasm::tree::make(context->IDENTIFIER(0)->getText()) }, // names - cqasm::tree::make(context->IDENTIFIER(1)->getText()) // typ - }; + auto ret = cqasm::tree::make(); + ret->names = Many{ cqasm::tree::make(context->IDENTIFIER(0)->getText()) }; + ret->typ = cqasm::tree::make(context->IDENTIFIER(1)->getText()); + return One{ ret }; } std::any BuildTreeGenAstVisitor::visitInstruction(CqasmParser::InstructionContext *context) { - auto ret = cqasm::tree::make(); - ret->name = cqasm::tree::make(context->IDENTIFIER()->getText()); - ret->operands = cqasm::tree::make(std::any_cast( - visitExpressionList(context->expressionList()))); - return ret; + auto ret = cqasm::tree::make(); + auto instruction = cqasm::tree::make(); + instruction->name = cqasm::tree::make(context->IDENTIFIER()->getText()); + instruction->operands = std::any_cast>(visitExpressionList(context->expressionList())); + ret->items.add(instruction); + return One{ ret }; } std::any BuildTreeGenAstVisitor::visitExpressionList(CqasmParser::ExpressionListContext *context) { - auto ret = ExpressionList{}; + auto ret = cqasm::tree::make(); const auto &expressions = context->expression(); std::for_each(expressions.begin(), expressions.end(), [this, &ret](auto &expression_ctx) { - ret.items.add(std::any_cast>(visitExpression(expression_ctx))); + ret->items.add(std::any_cast>(expression_ctx->accept(this))); }); return ret; } -std::any BuildTreeGenAstVisitor::visitExpression(CqasmParser::ExpressionContext *context) { - auto ret = One{}; - if (auto *integer_literal_node = context->INTEGER_LITERAL()) { - auto integer_literal = get_integer_literal_value(integer_literal_node); - ret = cqasm::tree::make(integer_literal); - } else if (auto *float_literal_node = context->FLOAT_LITERAL()) { - auto float_literal = get_float_literal_value(float_literal_node); - ret = cqasm::tree::make(float_literal); - } else if (auto *id_node = context->IDENTIFIER()) { - auto id = id_node->getText(); - ret = cqasm::tree::make(std::move(id)); - } else if (auto index_ctx = context->index()) { - ret = cqasm::tree::make(std::any_cast(visitIndex(index_ctx))); - } - return ret; +std::any BuildTreeGenAstVisitor::visitIntegerLiteral(CqasmParser::IntegerLiteralContext *context) { + auto value = get_integer_literal_value(context->INTEGER_LITERAL()); + auto ret = cqasm::tree::make(value); + return One{ ret }; +} + +std::any BuildTreeGenAstVisitor::visitFloatLiteral(CqasmParser::FloatLiteralContext *context) { + auto value = get_float_literal_value(context->FLOAT_LITERAL()); + auto ret = cqasm::tree::make(value); + return One{ ret }; +} + +std::any BuildTreeGenAstVisitor::visitIdentifier(CqasmParser::IdentifierContext *context) { + auto ret = cqasm::tree::make(context->IDENTIFIER()->getText()); + return One{ ret }; } std::any BuildTreeGenAstVisitor::visitIndex(CqasmParser::IndexContext *context) { - auto ret = Index{}; - auto id = context->IDENTIFIER()->getText(); - ret.expr = cqasm::tree::make(std::move(id)); - ret.indices = cqasm::tree::make(); + auto ret = cqasm::tree::make(); + ret->expr = cqasm::tree::make(context->IDENTIFIER()->getText()); + ret->indices = cqasm::tree::make(); auto index_item = cqasm::tree::make(std::any_cast>( - visitExpression(context->expression()))); - ret.indices->items.add(index_item); - return ret; + context->expression()->accept(this))); + ret->indices->items.add(index_item); + return One{ ret }; } } // namespace cqasm::v3x::parser diff --git a/src/v3x/CqasmParser.g4 b/src/v3x/CqasmParser.g4 index ac3a11ce..21535864 100644 --- a/src/v3x/CqasmParser.g4 +++ b/src/v3x/CqasmParser.g4 @@ -11,23 +11,20 @@ version: VERSION INTEGER_LITERAL (DOT INTEGER_LITERAL)?; qubits: QUBITS expression; -statement: mapping | variable | instruction; - -mapping: MAP IDENTIFIER EQUAL expression; - -variable: VAR IDENTIFIER COLON IDENTIFIER; - -instruction: IDENTIFIER expressionList; +statement: + MAP IDENTIFIER EQUAL expression # mapping + | VAR IDENTIFIER COLON IDENTIFIER # variable + | IDENTIFIER expressionList # instruction + ; expressionList: expression (COMMA expression)?; expression: - INTEGER_LITERAL - | FLOAT_LITERAL - | IDENTIFIER - | index; - -index: IDENTIFIER OPEN_BRACKET expression CLOSE_BRACKET; + INTEGER_LITERAL # integerLiteral + | FLOAT_LITERAL # floatLiteral + | IDENTIFIER # identifier + | IDENTIFIER OPEN_BRACKET expression CLOSE_BRACKET # index + ; /* * Things we are leaving out at the moment: From 153536509cfae58557ab74a1f1b95abd30310fec Mon Sep 17 00:00:00 2001 From: rturrado <68099809+rturrado@users.noreply.github.com> Date: Wed, 27 Sep 2023 11:55:42 +0200 Subject: [PATCH 24/28] Added asserts for checking the type of the terminal node at get_integer_literal_value and get_float_literal_value. --- src/v3x/BuildTreeGenAstVisitor.cpp | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/src/v3x/BuildTreeGenAstVisitor.cpp b/src/v3x/BuildTreeGenAstVisitor.cpp index 0b428732..922ea2b8 100644 --- a/src/v3x/BuildTreeGenAstVisitor.cpp +++ b/src/v3x/BuildTreeGenAstVisitor.cpp @@ -4,6 +4,7 @@ #include // for_each #include +#include // assert #include // runtime_error #include // stod, stoll @@ -14,33 +15,31 @@ using namespace cqasm::v1x::ast; using namespace cqasm::error; std::int64_t BuildTreeGenAstVisitor::get_integer_literal_value(antlr4::tree::TerminalNode *node) { - auto text = node->getText(); - std::int64_t ret{}; + const auto &token = node->getSymbol(); + const auto &text = node->getText(); + assert(token->getType() == CqasmParser::INTEGER_LITERAL); try { - ret = std::stoll(text); + return std::stoll(text); } catch (std::out_of_range&) { - const auto &token = node->getSymbol(); throw std::runtime_error{ fmt::format("{}:{}:{}: value '{}' is out of the INTEGER_LITERAL range", file_name_, token->getLine(), token->getCharPositionInLine(), text )}; } - return ret; } double BuildTreeGenAstVisitor::get_float_literal_value(antlr4::tree::TerminalNode *node) { - auto text = node->getText(); - double ret{}; + const auto &token = node->getSymbol(); + const auto &text = node->getText(); + assert(token->getType() == CqasmParser::FLOAT_LITERAL); try { - ret = std::stod(text); + return std::stod(text); } catch (std::out_of_range&) { - const auto &token = node->getSymbol(); throw std::runtime_error{ fmt::format("{}:{}:{}: value '{}' is out of the FLOATING_LITERAL range", file_name_, token->getLine(), token->getCharPositionInLine(), text )}; } - return ret; } std::any BuildTreeGenAstVisitor::visitProgram(CqasmParser::ProgramContext *context) { From 56f6dff3e7b8232527062092a74945d2753256dc Mon Sep 17 00:00:00 2001 From: rturrado <68099809+rturrado@users.noreply.github.com> Date: Wed, 27 Sep 2023 13:16:53 +0200 Subject: [PATCH 25/28] Updated README.md (added 'WIP: cQASM v3.0' section) to explain that the work on the v3 version of the parser is still completely unsupported. --- README.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index a5459512..cda3f99a 100644 --- a/README.md +++ b/README.md @@ -23,9 +23,15 @@ The new API lives in `v1x` directories, and the older API in `v10` directories. The following folders may be generated: -- `build/`: the C++ library outptu files generated by `conan`.
+- `build/`: the C++ library output files generated by `conan`.
- `pybuild`: the Python library output files generated by `setup.py`. +### WIP: cQASM v3.0 + +We have started working on the parsing of cQASM v3.0 files, and that's why you will also see some `v3x` folders around. + +However, the development of the new parser is still in a very early stage so its use through the API is completely unsupported. + ## Dependencies * C++ compiler with C++20 support (gcc 11, clang 14, msvc 17) From a920f6e979cf33cf1d3674dc57c0a732e818fc45 Mon Sep 17 00:00:00 2001 From: rturrado <68099809+rturrado@users.noreply.github.com> Date: Wed, 27 Sep 2023 16:46:24 +0200 Subject: [PATCH 26/28] Updated tree-gen commit ID, now to one in master. --- src/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index fc8b3fc3..3b01976e 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -44,7 +44,7 @@ include(FetchContent) # This exposes the generate_tree() function. FetchContent_Declare(tree-gen GIT_REPOSITORY https://github.com/QuTech-Delft/tree-gen.git - GIT_TAG "6a1339ea1ccb74b5ded2a86405a9143c7ef1a067" + GIT_TAG "9f54878240f6ae5df9c35cbf273cfbfb6f76679f" ) FetchContent_MakeAvailable(tree-gen) From fbd83f79fac0eed14012f99aad7d9e7c6ff884f4 Mon Sep 17 00:00:00 2001 From: rturrado <68099809+rturrado@users.noreply.github.com> Date: Fri, 29 Sep 2023 03:04:44 +0200 Subject: [PATCH 27/28] Preparing everything for the merge. - v1x/cqasm-analyzer: I've put back the API for parsing and analyzing a file path, a file pointer and a data string. There is at least some code in OpenQL (src/ql/ir/compat/detail/cqasm_reader.cc, ReaderImpl::string2circuit and ReaderImple::file2circuit) that is still using this API, so we shouldn't remove it yet. - test/CMakeLists.txt: commented out v3x tests (they are unimplemented). - test/v1x/parsing.cpp: commented out Toy v1 tests (they would otherwise fail the semantic checks, as they would fail the analyze version check at src/v1x/cqasm-analyzer.cpp; we could temporarily change this check, but I don't think it is worth for this task). --- include/v1x/cqasm-analyzer.hpp | 16 ++++++++++++++++ src/v1x/cqasm-analyzer.cpp | 32 ++++++++++++++++++++++++++++++++ src/v1x/cqasm.cpp | 16 +++------------- test/CMakeLists.txt | 2 +- test/v1x/parsing.cpp | 12 ++++-------- 5 files changed, 56 insertions(+), 22 deletions(-) diff --git a/include/v1x/cqasm-analyzer.hpp b/include/v1x/cqasm-analyzer.hpp index 1ad7b389..ff9db1bb 100644 --- a/include/v1x/cqasm-analyzer.hpp +++ b/include/v1x/cqasm-analyzer.hpp @@ -316,6 +316,22 @@ class Analyzer { const std::function &file_parser ) const; + /** + * Parses and analyzes the given file. + */ + AnalysisResult analyze(const std::string &filename) const; + + /** + * Parses and analyzes the given file pointer. The optional filename + * argument will be used only for error messages. + */ + AnalysisResult analyze(FILE *file, const std::string &filename = "") const; + + /** + * Parses and analyzes the given string. The optional filename argument + * will be used only for error messages. + */ + AnalysisResult analyze_string(const std::string &data, const std::string &filename = "") const; }; } // namespace analyzer diff --git a/src/v1x/cqasm-analyzer.cpp b/src/v1x/cqasm-analyzer.cpp index 4a5e7006..35a7a11f 100644 --- a/src/v1x/cqasm-analyzer.cpp +++ b/src/v1x/cqasm-analyzer.cpp @@ -535,6 +535,38 @@ AnalysisResult Analyzer::analyze( return analyze(file_parser()); } +/** + * Parses and analyzes the given file. + */ +AnalysisResult Analyzer::analyze(const std::string &filename) const { + return analyze( + [=](){ return version::parse_file(filename); }, + [=](){ return parser::parse_file(filename); } + ); +} + +/** + * Parses and analyzes the given file pointer. The optional filename + * argument will be used only for error messages. + */ +AnalysisResult Analyzer::analyze(FILE *file, const std::string &filename) const { + return analyze( + [=](){ return version::parse_file(file, filename); }, + [=](){ return parser::parse_file(file, filename); } + ); +} + +/** + * Parses and analyzes the given string. The optional filename argument + * will be used only for error messages. + */ +AnalysisResult Analyzer::analyze_string(const std::string &data, const std::string &filename) const { + return analyze( + [=](){ return version::parse_string(data, filename); }, + [=](){ return parser::parse_string(data, filename); } + ); +} + /** * Analyzes the given AST using the given analyzer. */ diff --git a/src/v1x/cqasm.cpp b/src/v1x/cqasm.cpp index c4d18430..7393a384 100644 --- a/src/v1x/cqasm.cpp +++ b/src/v1x/cqasm.cpp @@ -8,7 +8,6 @@ #include "cqasm-version.hpp" #include "v1x/cqasm.hpp" -#include "v1x/cqasm-parse-helper.hpp" namespace cqasm { @@ -22,10 +21,7 @@ tree::One analyze( const std::string &file_path, const std::string &api_version ) { - return default_analyzer(api_version).analyze( - [=](){ return version::parse_file(file_path); }, - [=](){ return parser::parse_file(file_path); } - ).unwrap(); + return default_analyzer(api_version).analyze(file_path).unwrap(); } /** @@ -38,10 +34,7 @@ tree::One analyze( const std::string &file_name, const std::string &api_version ) { - return default_analyzer(api_version).analyze( - [=](){ return version::parse_file(fp, file_name); }, - [=](){ return parser::parse_file(fp, file_name); } - ).unwrap(); + return default_analyzer(api_version).analyze(fp, file_name).unwrap(); } /** @@ -54,10 +47,7 @@ tree::One analyze_string( const std::string &file_name, const std::string &api_version ) { - return default_analyzer(api_version).analyze( - [=](){ return version::parse_string(data, file_name); }, - [=](){ return parser::parse_string(data, file_name); } - ).unwrap(); + return default_analyzer(api_version).analyze_string(data, file_name).unwrap(); } /** diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 907d53ca..43e5425b 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -8,7 +8,7 @@ if(LIBQASM_COMPAT) add_subdirectory(v10) endif() add_subdirectory(v1x) -add_subdirectory(v3x) +#add_subdirectory(v3x) # Sources target_sources(${PROJECT_NAME}_test PRIVATE diff --git a/test/v1x/parsing.cpp b/test/v1x/parsing.cpp index 901a0041..5f565e32 100644 --- a/test/v1x/parsing.cpp +++ b/test/v1x/parsing.cpp @@ -1,12 +1,10 @@ #include "parsing.hpp" #include "v1x/cqasm.hpp" #include "v1x/cqasm-parse-helper.hpp" -#include "v3x/cqasm.hpp" #include "v3x/cqasm-parse-helper.hpp" #include #include -#include #include #include #include @@ -64,7 +62,7 @@ class ParsingTest : public ::testing::Test { if (auto compare_result = version.compare("1.2"); compare_result <= 0) { parse_result = cq1x::parser::parse_string(input, "input.cq"); - } else if (auto compare_result = version.compare("3.0"); compare_result == 0) { + } else if (compare_result = version.compare("3.0"); compare_result == 0) { parse_result = cq3x::parser::parse_string(input, "input.cq"); } else { parse_result.errors.push_back(fmt::format("detected version {}", version)); @@ -90,7 +88,6 @@ class ParsingTest : public ::testing::Test { return; } - /* // Try different API levels for (const auto &api_version : std::vector({"1.0", "1.1", "1.2"})) { // If there were no errors, try semantic analysis. @@ -215,7 +212,7 @@ class ParsingTest : public ::testing::Test { semantic_actual_file_contents = fmt::format("ERROR\n{}\n", fmt::join(analysis_result.errors, "\n")); } auto semantic_actual_file_path = path_ / fmt::format("semantic.{}.actual.txt", api_version); - write_file(path_ / std::move(semantic_actual_file_path), semantic_actual_file_contents); + write_file(semantic_actual_file_path, semantic_actual_file_contents); std::string semantic_golden_file_contents{}; auto semantic_golden_file_path = path_ / fmt::format("semantic.{}.golden.txt", api_version); EXPECT_TRUE(read_file(semantic_golden_file_path, semantic_golden_file_contents)); @@ -225,7 +222,6 @@ class ParsingTest : public ::testing::Test { ::tree::base::serialize(analysis_result.root); } } - */ } }; @@ -274,6 +270,6 @@ void register_v1x_tests(const fs::path& subdir) { } void register_v1x_tests() { - //register_v1x_tests("parsing"); - register_v1x_tests("toy-v1x-parsing"); + register_v1x_tests("parsing"); + //register_v1x_tests("toy-v1x-parsing"); } From a1a31dbc4eaba3639d79457699296d1566721537 Mon Sep 17 00:00:00 2001 From: rturrado <68099809+rturrado@users.noreply.github.com> Date: Fri, 29 Sep 2023 23:19:14 +0200 Subject: [PATCH 28/28] BuildCustomAstVisitor class can be empty. --- include/v3x/BuildCustomAstVisitor.hpp | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/include/v3x/BuildCustomAstVisitor.hpp b/include/v3x/BuildCustomAstVisitor.hpp index a84a3749..0845d596 100644 --- a/include/v3x/BuildCustomAstVisitor.hpp +++ b/include/v3x/BuildCustomAstVisitor.hpp @@ -8,19 +8,6 @@ namespace cqasm::v3x::parser { -class BuildCustomAstVisitor : public CqasmParserVisitor { -public: - virtual std::any visitProgram(CqasmParser::ProgramContext *context) = 0; - virtual std::any visitVersion(CqasmParser::VersionContext *context) = 0; - virtual std::any visitQubits(CqasmParser::QubitsContext *context) = 0; - virtual std::any visitMapping(CqasmParser::MappingContext *context) = 0; - virtual std::any visitVariable(CqasmParser::VariableContext *context) = 0; - virtual std::any visitInstruction(CqasmParser::InstructionContext *context) = 0; - virtual std::any visitExpressionList(CqasmParser::ExpressionListContext *context) = 0; - virtual std::any visitIntegerLiteral(CqasmParser::IntegerLiteralContext *context) = 0; - virtual std::any visitFloatLiteral(CqasmParser::FloatLiteralContext *context) = 0; - virtual std::any visitIdentifier(CqasmParser::IdentifierContext *context) = 0; - virtual std::any visitIndex(CqasmParser::IndexContext *context) = 0; -}; +class BuildCustomAstVisitor : public CqasmParserVisitor {}; } // namespace cqasm::v3x::parser