diff --git a/CHANGELOG.md b/CHANGELOG.md index 0f5d6bcf..b32f5370 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,12 +9,22 @@ This project adheres to [Semantic Versioning](http://semver.org/). - **Fixed** for any bug fixes. - **Removed** for now removed features. +## [ 1.4.1 ] - [ 2026-06-15 ] + +### Fixed +- Aliases `measureX`, `measureY`, and `measureZ`, for the `measure` instruction, recognized as tokens by the lexer. + + ## [ 1.4.0 ] - [ 2026-06-05 ] ### Added - `CV`, `CY`, `DCNOT`, `ECR`, `ISWAP`, `InvSqrtSWAP`, `M`, `MS`, `SqrtISWAP`, and `SqrtSWAP` unitary instructions. - Aliases `measureX`, `measureY`, and `measureZ`, for the `measure` instruction along the respective axes. +<<<<<<< HEAD +======= + +>>>>>>> develop ## [ 1.3.0 ] - [ 2026-03-23 ] ### Added diff --git a/conan/profiles/tests-debug-local b/conan/profiles/tests-debug-local new file mode 100644 index 00000000..123b67b8 --- /dev/null +++ b/conan/profiles/tests-debug-local @@ -0,0 +1,7 @@ +include(tests-debug) + +[platform_tool_requires] +m4/1.4.19 + +[buildenv] +PATH+=(path)C:/msys64/usr/bin diff --git a/emscripten/test_libqasm.ts b/emscripten/test_libqasm.ts index ebc49a09..677d5d4e 100644 --- a/emscripten/test_libqasm.ts +++ b/emscripten/test_libqasm.ts @@ -8,7 +8,7 @@ wrapper().then(function(result: any) { try { let output = cqasm.get_version() - let expected_output = "1.4.0" + let expected_output = "1.4.1" console.log("\nThe version of libqasm compiled with emscripten is:", output); if (output !== expected_output) { console.log("\tExpected output:", expected_output) diff --git a/include/libqasm/versioning.hpp b/include/libqasm/versioning.hpp index a147618c..863268fb 100644 --- a/include/libqasm/versioning.hpp +++ b/include/libqasm/versioning.hpp @@ -2,7 +2,7 @@ namespace cqasm { -static const char* version{ "1.4.0" }; +static const char* version{ "1.4.1" }; static const char* release_year{ "2026" }; [[nodiscard]] [[maybe_unused]] static const char* get_version() { diff --git a/package.json b/package.json index 5836d16a..5f5fec6b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "libqasm", - "version": "1.4.0", + "version": "1.4.1", "repository": { "type": "git", "url": "https://github.com/QuTech-Delft/libqasm.git" diff --git a/src/v3x/CqasmLexer.g4 b/src/v3x/CqasmLexer.g4 index 23140ae5..d99d0cd5 100644 --- a/src/v3x/CqasmLexer.g4 +++ b/src/v3x/CqasmLexer.g4 @@ -49,7 +49,7 @@ TERNARY_CONDITIONAL_OP: '?'; // Keywords VERSION: 'version' -> pushMode(VERSION_STATEMENT); // version -MEASURE: 'measure'; // non-unitary instructions +MEASURE: 'measure' ('X' | 'Y' | 'Z')?; // non-unitary instructions RESET: 'reset'; INIT: 'init'; BARRIER: 'barrier'; diff --git a/test/v3x/cpp/test_analyzer.cpp b/test/v3x/cpp/test_analyzer.cpp index 82a411bc..a908a677 100644 --- a/test/v3x/cpp/test_analyzer.cpp +++ b/test/v3x/cpp/test_analyzer.cpp @@ -1,3 +1,4 @@ +#include #include #include @@ -48,6 +49,36 @@ TEST_F(AnalyzerAnalyzeTest, parser_returns_errors) { EXPECT_THAT(error.what(), ::testing::HasSubstr(parse_error_message)); } +TEST_F(AnalyzerAnalyzeTest, analyze_string_with_measure_aliases) { + auto analyzer = Analyzer{}; + analyzer.register_default_constants(); + analyzer.register_default_functions(); + analyzer.register_default_instructions(); + + const auto program = std::string{ + "version 3\n" + "qubit qx\n" + "qubit qy\n" + "qubit qz\n" + "bit bx\n" + "bit by\n" + "bit bz\n" + "bx = measureX qx\n" + "by = measureY qy\n" + "bz = measureZ qz\n" + }; + + const auto& analysis_result = analyzer.analyze_string(program, "input.cq"); + + EXPECT_TRUE(analysis_result.errors.empty()); + ASSERT_TRUE(analysis_result.root.is_well_formed()); + + const auto semantic_dump = fmt::format("{}", *analysis_result.root); + EXPECT_THAT(semantic_dump, ::testing::HasSubstr("instruction_ref: measureX(bit, qubit)")); + EXPECT_THAT(semantic_dump, ::testing::HasSubstr("instruction_ref: measureY(bit, qubit)")); + EXPECT_THAT(semantic_dump, ::testing::HasSubstr("instruction_ref: measureZ(bit, qubit)")); +} + //--------------// // AnalyzerTest // //--------------// diff --git a/test/v3x/python/test_v3x_analyzer.py b/test/v3x/python/test_v3x_analyzer.py index 207d4d13..4a9b4715 100644 --- a/test/v3x/python/test_v3x_analyzer.py +++ b/test/v3x/python/test_v3x_analyzer.py @@ -25,6 +25,34 @@ def test_measure_instruction_overload(self): expected_errors = ["Error at :1:29..36: instruction 'measure' does not have an overload with 2 parameters."] self.assertEqual(errors, expected_errors) + def test_measure_aliases(self): + program_str = ( + "version 3;" + "qubit qx;qubit qy;qubit qz;" + "bit bx;bit by;bit bz;" + "bx = measureX qx;" + "by = measureY qy;" + "bz = measureZ qz" + ) + v3x_analyzer = cq.Analyzer() + ast = v3x_analyzer.analyze_string(program_str) + + for statement, expected_name, expected_bit, expected_qubit in zip( + ast.block.statements, + ("measureX", "measureY", "measureZ"), + ("bx", "by", "bz"), + ("qx", "qy", "qz"), + ): + self.assertEqual(statement.name, expected_name) + + bit_operand = statement.operands[0] + self.assertEqual(bit_operand.variable.name, expected_bit) + self.assertIsInstance(bit_operand.variable.typ, cq.types.Bit) + + qubit_operand = statement.operands[1] + self.assertEqual(qubit_operand.variable.name, expected_qubit) + self.assertIsInstance(qubit_operand.variable.typ, cq.types.Qubit) + def test_parse_string_returning_ast(self): program_str = "version 3;qubit[5] q;bit[5] b;H q[0:4];b = measure q" v3x_analyzer = cq.Analyzer()