5 #define _USE_MATH_DEFINES 6 #include <unordered_set> 31 for (
const auto &error :
errors) {
32 out << error << std::endl;
41 : api_version(api_version), resolve_instructions(false), resolve_error_model(false)
43 if (api_version.compare(
"1.2") > 0) {
44 throw std::invalid_argument(
"this analyzer only supports up to cQASM 1.2");
52 : api_version(api_version), resolve_instructions(false), resolve_error_model(false)
54 if (api_version.
compare(
"1.2") > 0) {
55 throw std::invalid_argument(
"this analyzer only supports up to cQASM 1.2");
64 mappings.
add(name, value);
71 const std::string &name,
75 functions.
add(name, param_types, impl);
84 const std::string &name,
85 const std::string ¶m_types,
115 resolve_instructions =
true;
116 instruction_set.
add(instruction);
124 const std::string &name,
125 const std::string ¶m_types,
126 bool allow_conditional,
128 bool allow_reused_qubits,
129 bool allow_different_index_sizes
132 name, param_types, allow_conditional, allow_parallel,
133 allow_reused_qubits, allow_different_index_sizes));
143 resolve_error_model =
true;
144 error_models.
add(error_model);
152 const std::string &name,
153 const std::string ¶m_types
203 functions(functions),
204 instruction_set(instruction_set),
237 std::list<std::pair<tree::Maybe<semantic::GotoInstruction>, std::string>>
gotos;
266 Scope &get_current_scope();
271 Scope &get_global_scope();
308 void analyze_bundle_ext(
const ast::Bundle &bundle);
426 template<
class Type,
class... TypeArgs>
429 TypeArgs... type_args
447 template<
class ElType,
class ElVal,
class MatLit,
class MatVal>
449 size_t nrows,
size_t ncols,
450 const std::vector<values::Value> &vals
478 const std::string &name,
491 if (result.
errors.empty() && !result.
root.is_well_formed()) {
492 std::cerr << *result.
root;
493 throw std::runtime_error(
"internal error: no semantic errors returned, but semantic tree is incomplete. Tree was dumped.");
503 if (!parse_result.
errors.empty()) {
521 auto file_version = version_parser();
522 if (file_version > api_version) {
523 std::ostringstream ss;
524 ss <<
"cQASM file version is " << file_version <<
", but at most ";
525 ss << api_version <<
" is supported here";
526 result.
errors.push_back(ss.str());
577 scope_stack({
Scope(analyzer.mappings, analyzer.functions, analyzer.instruction_set)})
582 result.
root.set(tree::make<semantic::Program>());
584 result.
root->api_version = analyzer.api_version;
592 if (!ast.num_qubits.empty()) {
594 }
else if (ast.version->items.compare(
"1.1") < 0) {
597 result.
root->num_qubits = 0;
604 if (ast.version->items.compare(
"1.2") >= 0) {
607 std::map<std::string, tree::Maybe<semantic::Subcircuit>> subcircuits;
608 for (
const auto &subcircuit : result.
root->subcircuits) {
610 auto insert_result = subcircuits.insert({subcircuit->name, subcircuit});
611 if (!insert_result.second) {
612 std::ostringstream ss;
613 ss <<
"duplicate subcircuit name \"" << subcircuit->name <<
"\"";
615 ss <<
"; previous definition was at " << *loc;
626 for (
const auto &it : gotos) {
628 auto it2 = subcircuits.find(it.second);
629 if (it2 == subcircuits.end()) {
631 "failed to resolve subcircuit \"" + it.second +
"\"" 634 it.first->target = it2->second;
645 const auto &name = it.first;
646 const auto &value = it.second.first;
647 const auto &ast_node = it.second.second;
650 if (ast_node.empty()) {
658 auto mapping = tree::make<semantic::Mapping>(
663 result.
root->mappings.add(mapping);
671 result.
root->mappings.begin(), result.
root->mappings.end(),
675 if (lhsa->filename < rhsa->filename)
return true;
676 if (rhsa->filename < lhsa->filename)
return false;
677 if (lhsa->first_line < rhsa->first_line)
return true;
678 if (rhsa->first_line < lhsa->first_line)
return false;
679 return lhsa->first_column < rhsa->first_column;
697 result.
root->version = tree::make<semantic::Version>();
698 result.
root->version->items = analyzer.api_version;
701 for (
auto item : ast.
items) {
707 std::ostringstream ss{};
708 ss <<
"the maximum cQASM version supported is " << analyzer.api_version;
709 ss <<
", but the cQASM file is version " << ast.
items;
731 result.
root->num_qubits = 0;
735 if (result.
root->num_qubits < 1) {
744 auto vi = tree::make<values::ConstInt>(i);
770 if (result.
root->subcircuits.empty()) {
771 auto subcircuit_node = tree::make<semantic::Subcircuit>(
"", 1);
773 if (analyzer.api_version.
compare(
"1.2") >= 0) {
774 subcircuit_node->body = tree::make<semantic::Block>();
776 result.
root->subcircuits.add(subcircuit_node);
780 return result.
root->subcircuits.back();
788 return scope_stack.back();
795 return scope_stack.front();
807 if (!scope.block.empty()) {
822 block->statements.add(stmt);
828 block_loc->expand_to_include(stmt_loc->first_line, stmt_loc->first_column);
829 block_loc->expand_to_include(stmt_loc->last_line, stmt_loc->last_column);
842 for (
const auto &stmt : statements.
items) {
844 if (
auto bundle = stmt->as_bundle()) {
845 if (analyzer.api_version.
compare(
"1.2") >= 0) {
850 }
else if (
auto mapping = stmt->as_mapping()) {
852 }
else if (
auto variables = stmt->as_variables()) {
854 }
else if (
auto subcircuit = stmt->as_subcircuit()) {
856 }
else if (
auto structured = stmt->as_structured()) {
857 if (result.
root->version->items.compare(
"1.2") < 0) {
862 throw std::runtime_error(
"unexpected statement node");
895 scope_stack.pop_back();
912 if (bundle.
items.size() == 1) {
920 auto node = tree::make<semantic::Bundle>();
921 for (
const auto &insn : bundle.
items) {
927 if (node->items.size() > 1) {
928 for (
const auto &insn : node->items) {
930 if (!insn->instruction.empty()) {
931 if (!insn->instruction->allow_parallel) {
932 std::ostringstream ss;
933 ss <<
"instruction ";
934 ss << insn->instruction->name;
935 ss <<
" with parameter pack ";
936 ss << insn->instruction->param_types;
937 ss <<
" is not parallelizable, but is bundled with ";
938 ss << (node->items.size() - 1);
939 ss <<
" other instruction";
940 if (node->items.size() != 2) {
956 if (node->items.empty()) {
985 if (bundle.
items.size() == 1) {
993 auto node = tree::make<semantic::BundleExt>();
994 for (
const auto &insn : bundle.
items) {
1006 if (node->items.size() > 1) {
1007 for (
const auto &insn_base : node->items) {
1009 if (
auto insn = insn_base->as_instruction()) {
1010 if (!insn->instruction.empty()) {
1011 if (!insn->instruction->allow_parallel) {
1012 std::ostringstream ss;
1013 ss <<
"instruction ";
1014 ss << insn->instruction->name;
1015 ss <<
" with parameter pack ";
1016 ss << insn->instruction->param_types;
1017 ss <<
" is not parallelizable, but is bundled with ";
1018 ss << (node->items.size() - 1);
1019 ss <<
" other instruction";
1020 if (node->items.size() != 2) {
1037 if (node->items.empty()) {
1065 for (
auto operand_expr : insn.
operands->items) {
1071 if (analyzer.resolve_instructions) {
1074 node.set(tree::make<semantic::Instruction>(
1082 if (!node->instruction.empty() && !node->instruction->allow_conditional) {
1084 "conditional execution is not supported for this instruction");
1087 node->condition =
values::promote(condition_val, tree::make<types::Bool>());
1088 if (node->condition.empty()) {
1094 if (
auto x = node->condition->as_const_bool()) {
1101 node->condition.set(tree::make<values::ConstBool>(
true));
1105 if (!node->instruction.empty() && !node->instruction->allow_reused_qubits) {
1106 std::unordered_set<primitives::Int> qubits_used;
1107 for (
const auto &operand : operands) {
1108 if (
auto x = operand->as_qubit_refs()) {
1109 for (
auto index : x->index) {
1110 if (!qubits_used.insert(index->value).second) {
1112 "qubit with index " + std::to_string(index->value)
1113 +
" is used more than once");
1125 if (!node->instruction.empty() && !node->instruction->allow_different_index_sizes) {
1126 size_t num_refs = 0;
1128 for (
const auto &operand : operands) {
1130 if (
auto x = operand->as_qubit_refs()) {
1131 indices = &x->index;
1132 }
else if (
auto x = operand->as_bit_refs()) {
1133 indices = &x->index;
1137 num_refs = indices->size();
1138 }
else if (num_refs != indices->size()) {
1139 std::ostringstream ss;
1140 ss <<
"the number of indices (" << indices->size() <<
") ";
1141 ss <<
"doesn't match previously found number of indices ";
1142 ss <<
"(" << num_refs <<
")";
1144 ss <<
" at " << *num_refs_loc;
1148 if (!num_refs_loc) {
1178 if (insn.
operands->items.size() != 2) {
1191 node->condition =
values::promote(condition_val, tree::make<types::Bool>());
1192 if (node->condition.empty()) {
1198 if (
auto x = node->condition->as_const_bool()) {
1204 node->condition.set(tree::make<values::ConstBool>(
true));
1234 if (!lhs->as_reference()) {
1236 "left-hand side of assignment statement must be assignable" 1242 target_type->assignable =
false;
1244 if (rhs_promoted.empty()) {
1245 std::ostringstream ss;
1247 ss <<
"could not be coerced to left-hand side (" <<
values::type_of(lhs) <<
")";
1268 if (insn.
operands->items.size() != 1) {
1270 "goto instruction must have a single operand" 1274 if (
auto identifier = insn.
operands->items[0]->as_identifier()) {
1275 target = identifier->name;
1278 "goto instruction operand must be a subcircuit identifier" 1284 node.set(tree::make<semantic::GotoInstruction>());
1289 gotos.emplace_back(node, target);
1294 node->condition =
values::promote(condition_val, tree::make<types::Bool>());
1295 if (node->condition.empty()) {
1301 if (
auto x = node->condition->as_const_bool()) {
1307 node->condition.set(tree::make<values::ConstBool>(
true));
1332 if (!result.
root->error_model.empty()) {
1333 auto ss = std::ostringstream();
1334 ss <<
"error model can only be specified once";
1336 ss <<
", previous specification was at " << *loc;
1342 const auto &arg_exprs = insn.
operands->items;
1343 if (arg_exprs.empty()) {
1347 if (
auto name_ident = arg_exprs[0]->as_identifier()) {
1348 name = name_ident->name;
1351 "first argument of an error model must be its name as an identifier");
1356 for (
auto arg_expr_it = arg_exprs.begin() + 1; arg_expr_it < arg_exprs.end(); arg_expr_it++) {
1364 if (analyzer.resolve_error_model) {
1365 result.
root->error_model.set(
1366 analyzer.error_models.
resolve(
1369 result.
root->error_model.set(
1370 tree::make<semantic::ErrorModel>(
1394 mapping.
alias->name,
1396 tree::make<ast::Mapping>(mapping)
1413 if (result.
root->version->items.compare(
"1.1") < 0) {
1420 if (type_name ==
"qubit") {
1421 type = tree::make<types::Qubit>();
1422 }
else if (type_name ==
"bool" || type_name ==
"bit") {
1423 type = tree::make<types::Bool>();
1424 }
else if (type_name ==
"int") {
1425 type = tree::make<types::Int>();
1426 }
else if (type_name ==
"real") {
1427 type = tree::make<types::Real>();
1428 }
else if (type_name ==
"complex") {
1429 type = tree::make<types::Complex>();
1433 type->assignable =
true;
1436 for (
const auto &identifier : variables.
names) {
1440 auto var = tree::make<semantic::Variable>(identifier->name, type.clone());
1442 result.
root->variables.add(var);
1447 tree::make<values::VariableRef>(var),
1465 if (scope_stack.size() > 1) {
1471 if (iterations < 1) {
1473 "subcircuit iteration count must be positive, but is " 1474 + std::to_string(iterations), &*subcircuit.
iterations);
1477 auto node = tree::make<semantic::Subcircuit>(
1478 subcircuit.
name->name,
1483 if (analyzer.api_version.
compare(
"1.2") >= 0) {
1484 node->body = tree::make<semantic::Block>();
1487 result.
root->subcircuits.add(node);
1505 if (
auto if_else = structured.
as_if_else()) {
1507 }
else if (
auto for_loop = structured.
as_for_loop()) {
1520 "cannot use break outside of a structured loop" 1530 "cannot use continue outside of a structured loop" 1536 throw std::runtime_error(
"unexpected statement node");
1570 for (
const auto &branch : if_else.
branches) {
1575 if (condition.empty()) {
1583 node->branches.emplace(condition, body);
1594 for (
size_t idx = 0; idx < node->branches.size(); ) {
1595 if (
auto val = node->branches[idx]->condition->as_const_bool()) {
1600 node->otherwise = node->branches[idx]->body;
1601 while (node->branches.size() > idx) node->branches.remove();
1606 node->branches.remove(idx);
1615 if (node->branches.empty()) {
1616 if (!node->otherwise.empty()) {
1617 for (
const auto &stmt : node->otherwise->statements) {
1650 node->condition =
values::promote(condition, tree::make<types::Bool>());
1651 if (node->condition.empty()) {
1656 if (!for_loop.
update.empty()) {
1684 if (node->lhs.empty()) {
1712 node->condition =
values::promote(condition, tree::make<types::Bool>());
1713 if (node->condition.empty()) {
1721 if (
auto cond = node->condition->as_const_bool()) {
1747 node->condition =
values::promote(condition, tree::make<types::Bool>());
1748 if (node->condition.empty()) {
1753 if (
auto cond = node->condition->as_const_bool()) {
1755 for (
const auto &stmt : node->body->statements) {
1774 for (
auto annotation_ast : annotations) {
1776 auto annotation = tree::make<semantic::AnnotationData>();
1777 annotation->interface = annotation_ast->interface->name;
1778 annotation->operation = annotation_ast->operation->name;
1779 for (
auto expression_ast : annotation_ast->operands->items) {
1788 retval.add(annotation);
1805 retval.set(tree::make<values::ConstInt>(int_lit->value));
1807 retval.set(tree::make<values::ConstReal>(float_lit->value));
1809 retval.set(tree::make<values::ConstString>(string_lit->value));
1811 retval.set(tree::make<values::ConstJson>(json_lit->value));
1816 }
else if (
auto index = expression.
as_index()) {
1820 }
else if (
auto negate = expression.
as_negate()) {
1826 }
else if (
auto power = expression.
as_power()) {
1828 }
else if (
auto mult = expression.
as_multiply()) {
1830 }
else if (
auto div = expression.
as_divide()) {
1834 }
else if (
auto mod = expression.
as_modulo()) {
1836 }
else if (
auto add = expression.
as_add()) {
1846 }
else if (
auto cmpeq = expression.
as_cmp_eq()) {
1848 }
else if (
auto cmpne = expression.
as_cmp_ne()) {
1850 }
else if (
auto cmpgt = expression.
as_cmp_gt()) {
1852 }
else if (
auto cmpge = expression.
as_cmp_ge()) {
1854 }
else if (
auto cmplt = expression.
as_cmp_lt()) {
1856 }
else if (
auto cmple = expression.
as_cmp_le()) {
1871 retval.set(
analyze_operator(
"?:", tcond->cond, tcond->if_true, tcond->if_false));
1873 throw std::runtime_error(
"unexpected expression node");
1875 if (!retval.empty() && (retval->as_function() || retval->as_variable_ref())) {
1876 if (analyzer.api_version.
compare(
"1.1") < 0) {
1884 if (retval.empty()) {
1885 throw std::runtime_error(
1886 "analyze_expression returned nonsense, this should never happen");
1897 template <
class Type,
class... TypeArgs>
1907 auto value = analyze_as<types::Int>(expression);
1908 if (value.empty()) {
1911 if (
auto int_value = value->as_const_int()) {
1912 return int_value->value;
1930 size_t nrows = matrix_lit.
rows.size();
1931 size_t ncols = matrix_lit.
rows[0]->items.size();
1932 for (
auto row : matrix_lit.
rows) {
1933 if (row->items.size() != ncols) {
1937 std::vector<values::Value> vals;
1938 for (
size_t row = 0; row < nrows; row++) {
1939 for (
size_t col = 0; col < ncols; col++) {
1948 >(nrows, ncols, vals);
1949 if (!value.empty()) {
1957 >(nrows, ncols, vals);
1958 if (!value.empty()) {
1965 throw error::AnalysisError(
"only matrices of constant real or complex numbers are currently supported");
1974 template <
class ElType,
class ElVal,
class MatLit,
class MatVal>
1976 size_t nrows,
size_t ncols,
1977 const std::vector<values::Value> &vals
1979 auto matrix = MatLit(nrows, ncols);
1980 for (
size_t row = 0; row < nrows; row++) {
1981 for (
size_t col = 0; col < ncols; col++) {
1982 auto val =
values::promote(vals[row * ncols + col], tree::make<ElType>());
1986 auto val_real = val.template as<ElVal>();
1987 if (val_real.empty()) {
1990 matrix.at(row + 1, col + 1) = val_real->value;
1995 return tree::make<MatVal>(matrix);
2003 if (
auto qubit_refs = expr->as_qubit_refs()) {
2007 for (
auto idx : indices) {
2008 idx->value = qubit_refs->index[idx->value]->value;
2010 return tree::make<values::QubitRefs>(indices);
2012 }
else if (
auto bit_refs = expr->as_bit_refs()) {
2016 for (
auto idx : indices) {
2017 idx->value = bit_refs->index[idx->value]->value;
2019 return tree::make<values::BitRefs>(indices);
2025 std::ostringstream ss;
2026 ss <<
"indexation is not supported for value of type " <<
values::type_of(expr);
2037 for (
auto entry : index_list.
items) {
2038 if (
auto item = entry->as_index_item()) {
2042 if (index < 0 || (
unsigned long)index >= size) {
2044 "index " + std::to_string(index)
2045 +
" out of range (size " + std::to_string(size) +
")",
2048 auto index_val = tree::make<values::ConstInt>(index);
2050 retval.add(index_val);
2052 }
else if (
auto range = entry->as_index_range()) {
2056 if (first < 0 || (
unsigned long)first >= size) {
2058 "index " + std::to_string(first)
2059 +
" out of range (size " + std::to_string(size) +
")",
2063 if (last < 0 || (
unsigned long)last >= size) {
2065 "index " + std::to_string(last)
2066 +
" out of range (size " + std::to_string(size) +
")",
2072 for (
auto index = (
size_t)first; index <= (size_t)last; index++) {
2073 auto index_val = tree::make<values::ConstInt>(index);
2075 retval.add(index_val);
2079 throw std::runtime_error(
"unknown IndexEntry AST node");
2090 for (
auto arg : args.
items) {
2094 if (retval.empty()) {
2095 throw std::runtime_error(
"function implementation returned empty value");
2104 const std::string &name,
Main class used for analyzing cQASM files.
The file version identifier.
tree::Maybe< semantic::Block > block
The block associated with this scope, if any.
Many< ExpressionList > rows
The list of rows in the matrix.
void add(const error_model::ErrorModel &type)
Registers an error model.
cqasm::v1::primitives::Version items
The list of version components, ordered major to minor.
void add(const std::string &name, const values::Value &value, const tree::Maybe< ast::Mapping > &node=tree::Maybe< ast::Mapping >())
Adds a mapping.
virtual IntegerLiteral * as_integer_literal()
Interprets this node to a node of type IntegerLiteral.
virtual Identifier * as_identifier()
Interprets this node to a node of type Identifier.
One< Expression > lhs
Reference to the variable used for looping.
const std::unordered_map< std::string, std::pair< const values::Value, tree::Maybe< ast::Mapping > > > & get_table() const
Grants read access to the underlying map.
Many< Identifier > names
Name of the variables.
Many< IndexEntry > items
The list of indices.
virtual ShiftRightArith * as_shift_right_arith()
Interprets this node to a node of type ShiftRightArith.
std::complex< double > Complex
Complex number primitive used within the semantic trees.
const std::string & get_message() const
Constructs the message string.
virtual Power * as_power()
Interprets this node to a node of type Power.
virtual IntDivide * as_int_divide()
Interprets this node to a node of type IntDivide.
This file contains the Analyzer class and support classes, used to manage semantic analysis...
virtual Multiply * as_multiply()
Interprets this node to a node of type Multiply.
::tree::base::Maybe< T > Maybe
AnalysisResult analyze(const ast::Program &program) const
Analyzes the given program AST node.
Matrix< Complex > CMatrix
Matrix of complex numbers.
Type of a real number (IEEE double).
virtual TernaryCond * as_ternary_cond()
Interprets this node to a node of type TernaryCond.
values::Value analyze_index(const ast::Index &index)
Parses an index operator.
virtual FloatLiteral * as_float_literal()
Interprets this node to a node of type FloatLiteral.
Exception thrown by AnalysisResult::unwrap() when the cQASM file fails to parse.
tree::Maybe< semantic::WhileLoop > analyze_while_loop(const ast::WhileLoop &while_loop)
Analyzes the given while loop.
Maybe< Expression > iterations
An optional integer expression representing the number of iterations for this subcircuit.
One< Identifier > name
The name of the subcircuit.
resolver::InstructionTable instruction_set
The instruction set visible within this scope.
types::Type type_of(const Value &value)
Returns the type of the given value.
Analyzer(const std::string &api_version="1.0")
Creates a new semantic analyzer.
std::vector< std::string > errors
List of accumulated errors.
A list of parallel instructions.
virtual ForeachLoop * as_foreach_loop()
Interprets this node to a node of type ForeachLoop.
Version parse_file(const std::string &filename)
Parse the given file to get its version number.
virtual BitwiseOr * as_bitwise_or()
Interprets this node to a node of type BitwiseOr.
virtual Negate * as_negate()
Interprets this node to a node of type Negate.
Many< IfElseBranch > branches
The if-else branches.
Types from_spec(const std::string &spec)
Constructs a set of types from a shorthand string representation.
Toplevel namespace with entry points for the new API.
values::Value analyze_function(const ast::Identifier &name, const ast::ExpressionList &args)
Parses a function.
resolver::MappingTable mappings
The mappings visible within this scope.
Defines various utility functions.
Maybe< Assignment > initialize
The optional initializing assignment, run before the loop starts.
One< Expression > to
The last value.
Scope & get_current_scope()
Returns a reference to the current scope.
Header file generated by func-gen.
void analyze_subcircuit(const ast::Subcircuit &subcircuit)
Analyzes the given subcircuit header and, if valid, adds it to the subcircuit list.
A mapping (alias) for an expression.
Source location annotation object, containing source file line numbers etc.
virtual Subtract * as_subtract()
Interprets this node to a node of type Subtract.
values::Value analyze_matrix_helper(size_t nrows, size_t ncols, const std::vector< values::Value > &vals)
Helper for parsing a matrix.
virtual LogicalNot * as_logical_not()
Interprets this node to a node of type LogicalNot.
virtual ContinueStatement * as_continue_statement()
Interprets this node to a node of type ContinueStatement.
tree::Maybe< semantic::ForeachLoop > analyze_foreach_loop(const ast::ForeachLoop &foreach_loop)
Analyzes the given static for loop.
std::list< std::pair< tree::Maybe< semantic::GotoInstruction >, std::string > > gotos
List of all goto instructions in the program, for name resolution when all other analysis completes...
One< StatementList > body
The loop body.
One< Expression > expr
The expression being indexed.
void analyze_mapping(const ast::Mapping &mapping)
Analyzes the given mapping and, if valid, adds it to the current scope.
Table of the supported instructions and their overloads.
std::int64_t Int
Integer primitive used within the AST and semantic trees.
friend class AnalyzerHelper
tree::Any< Node > Values
Zero or more cQASM values.
void analyze_qubits(const ast::Expression &count)
Checks the qubits statement and updates the scope accordingly.
One< Identifier > name
Name identifying the instruction.
A list of one or more indices.
tree::Maybe< semantic::IfElse > analyze_if_else(const ast::IfElse &if_else)
Analyzes the given if-else chain.
virtual LogicalOr * as_logical_or()
Interprets this node to a node of type LogicalOr.
A version 1.2+ assignment instruction.
Version number primitive used within the AST and semantic trees.
virtual CmpLt * as_cmp_lt()
Interprets this node to a node of type CmpLt.
std::vector< std::string > errors
List of accumulated errors.
ast::One< semantic::Program > root
Root node of the semantic tree, if analysis was successful.
Represents a value of type complex.
Maybe< StatementList > otherwise
The final else block, if any.
tree::Maybe< semantic::GotoInstruction > analyze_goto_instruction(const ast::Instruction &insn)
Analyzes the given cQASM 1.2+ goto instruction.
Represents a value of type bool.
One< Expression > frm
The first value.
Representation of an error model.
std::list< Scope > scope_stack
Scope stack.
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.
One< Expression > condition
The condition for starting another iteration.
Representation of an available instruction (also known as gate) in the instruction set...
AnalysisResult result
The analysis result being constructed.
tree::Maybe< semantic::SetInstruction > analyze_set_instruction_operands(const ast::Expression &lhs_expr, const ast::Expression &rhs_expr)
Analyzes the given two operands as lhs and rhs of a set instruction.
void register_into(resolver::FunctionTable &table)
Registers a bunch of functions usable during constant propagation into the given function table...
One or more variable declaration for some type.
Value promote(const Value &value, const types::Type &type)
Type-checks and (if necessary) promotes the given value to the given type.
virtual CmpEq * as_cmp_eq()
Interprets this node to a node of type CmpEq.
values::Value analyze_operator(const std::string &name, const tree::One< ast::Expression > &a, const tree::One< ast::Expression > &b=tree::One< ast::Expression >(), const tree::One< ast::Expression > &c=tree::One< ast::Expression >())
Parses an operator.
values::Value analyze_as(const ast::Expression &expression, TypeArgs... type_args)
Shorthand for parsing an expression and promoting it to the given type, constructed in-place with the...
Represents a matrix literal.
tree::Many< values::ConstInt > analyze_index_list(const ast::IndexList &index_list, size_t size)
Parses an index list.
One< IndexList > indices
The list of indices.
cqasm::tree::One< T > One
Any version 1.2+ structured control-flow statement.
virtual LogicalAnd * as_logical_and()
Interprets this node to a node of type LogicalAnd.
cqasm::v1::primitives::Str name
The identifier.
Table of all overloads of all constant propagation functions.
One< ExpressionList > operands
Operands for the instruction.
Scope(const resolver::MappingTable &mappings, const resolver::FunctionTable &functions, const resolver::InstructionTable &instruction_set)
Creates the global scope.
AnalyzerHelper(const Analyzer &analyzer, const ast::Program &ast)
Analyzes the given AST using the given analyzer.
void register_error_model(const error_model::ErrorModel &error_model)
Registers an error model.
virtual CmpNe * as_cmp_ne()
Interprets this node to a node of type CmpNe.
virtual IfElse * as_if_else()
Interprets this node to a node of type IfElse.
virtual Add * as_add()
Interprets this node to a node of type Add.
Matrix< Real > RMatrix
Matrix of real numbers.
virtual RepeatUntilLoop * as_repeat_until_loop()
Interprets this node to a node of type RepeatUntilLoop.
One< StatementList > body
The loop body.
void analyze_bundle_ext(const ast::Bundle &bundle)
Analyzes the given bundle and, if valid, adds it to the current scope/block using API version 1...
void analyze_statements(const ast::StatementList &statements)
Analyzes the given statement list, adding the analyzed statements to the current subcircuit (API 1...
tree::Maybe< semantic::SetInstruction > analyze_set_instruction(const ast::Instruction &insn)
Analyzes the given cQASM 1.2+ set instruction.
Namespace for the "new" cQASM 1.x API.
virtual Modulo * as_modulo()
Interprets this node to a node of type Modulo.
bool case_insensitive_equals(const std::string &lhs, const std::string &rhs)
Case-insensitive string compare.
tree::Maybe< semantic::Block > get_current_block(const tree::Annotatable &source)
Returns a reference to the block that's currently being built (1.2+).
bool within_loop
Whether we're within at least one for, foreach, while, or repeat-until loop.
virtual FunctionCall * as_function_call()
Interprets this node to a node of type FunctionCall.
primitives::Int analyze_as_const_int(const ast::Expression &expression)
Shorthand for parsing an expression to a constant integer.
void analyze_variables(const ast::Variables &variables)
Analyzes the given declaration of one or more variables and, if valid, adds them to the current scope...
void analyze_structured(const ast::Structured &structured)
Analyzes the given structured control-flow statement and, if valid, adds it to the current scope/bloc...
values::Value analyze_matrix(const ast::MatrixLiteral &matrix_lit)
Parses a matrix.
ast::One< ast::Root > root
Root node of the AST, if analysis was sufficiently successful.
virtual JsonLiteral * as_json_literal()
Interprets this node to a node of type JsonLiteral.
Represents a value of type real_matrix.
void register_instruction(const instruction::Instruction &instruction)
Registers an instruction type.
tree::One< Node > Value
A cQASM value, either known at compile-time or an expression for something only known at runtime...
virtual MatrixLiteral * as_matrix_literal()
Interprets this node to a node of type MatrixLiteral.
virtual CmpLe * as_cmp_le()
Interprets this node to a node of type CmpLe.
virtual BitwiseNot * as_bitwise_not()
Interprets this node to a node of type BitwiseNot.
tree::Maybe< semantic::RepeatUntilLoop > analyze_repeat_until_loop(const ast::RepeatUntilLoop &repeat_until_loop)
Analyzes the given repeat-until loop.
One< Identifier > alias
The identifier used to refer to the expression.
tree::One< TypeBase > Type
A cQASM type.
::tree::base::Any< T > Any
Type of a complex number (2x IEEE double).
resolver::FunctionTable functions
The functions visible within this scope.
Table of all mappings within a certain scope.
::tree::base::Many< T > Many
Many< Instruction > items
The list of parallel instructions.
void add_to_current_block(const tree::Maybe< semantic::Statement > &stmt)
Adds an analyzed statement to the current block (1.2+).
virtual ShiftLeft * as_shift_left()
Interprets this node to a node of type ShiftLeft.
virtual Divide * as_divide()
Interprets this node to a node of type Divide.
tree::Any< TypeBase > Types
Zero or more cQASM types.
virtual LogicalXor * as_logical_xor()
Interprets this node to a node of type LogicalXor.
tree::One< semantic::ErrorModel > resolve(const std::string &name, const values::Values &args) const
Resolves an error model.
void add(const instruction::Instruction &type)
Registers an instruction type.
tree::Maybe< semantic::Subcircuit > get_current_subcircuit(const tree::Annotatable &source)
Returns a reference to the subcircuit that's currently being built.
Parse result information.
tree::Maybe< semantic::Instruction > analyze_instruction(const ast::Instruction &insn)
Analyzes the given instruction.
ParseResult parse_string(const std::string &data, const std::string &filename)
Parse the given string.
virtual ShiftRightLogic * as_shift_right_logic()
Interprets this node to a node of type ShiftRightLogic.
Any< Statement > items
The list of statements.
One< Identifier > typ
Name of the type.
virtual BitwiseXor * as_bitwise_xor()
Interprets this node to a node of type BitwiseXor.
void register_function(const std::string &name, const types::Types ¶m_types, const resolver::FunctionImpl &impl)
Registers a function, usable within expressions.
tree::Maybe< semantic::ForLoop > analyze_for_loop(const ast::ForLoop &for_loop)
Analyzes the given C-style for loop.
Any< Expression > items
The list of expressions.
One< StatementList > body
The loop body.
std::string lowercase(const std::string &name)
Makes a string lowercase.
One< Expression > expr
The aliased expression.
Maybe< Assignment > update
The updating assignment, done at the end of the loop body and upon continue.
values::Value analyze_expression(const ast::Expression &expression)
Parses any kind of expression.
virtual CmpGt * as_cmp_gt()
Interprets this node to a node of type CmpGt.
Helper class for analyzing a single AST.
One< Expression > condition
The condition for starting another iteration.
void analyze_bundle(const ast::Bundle &bundle)
Analyzes the given bundle and, if valid, adds it to the current subcircuit using API version 1...
Maybe< Expression > condition
Optional conditional expression.
virtual Index * as_index()
Interprets this node to a node of type Index.
void register_default_functions_and_mappings()
Registers a number of default functions and mappings, such as the operator functions, the usual trigonometric functions, mappings for pi, eu (aka e, 2.718...), im (imaginary unit) and so on.
Represents a value of type real.
void analyze_version(const ast::Version &ast)
Parses the version tag.
values::Value call(const std::string &name, const values::Values &args) const
Calls a function.
::tree::base::One< T > One
virtual CmpGe * as_cmp_ge()
Interprets this node to a node of type CmpGe.
tree::Maybe< semantic::Block > analyze_subblock(const ast::StatementList &statements, bool is_loop)
Analyzes a statement list corresponding to a structured control-flow subblock (1.2+).
const Analyzer & analyzer
The analyzer associated with this helper.
Version parse_string(const std::string &data, const std::string &filename)
Parse the given string as a file to get its version number.
void add(const std::string &name, const types::Types ¶m_types, const FunctionImpl &impl)
Registers a function.
Represents a value of type complex_matrix.
Scope & get_global_scope()
Returns a reference to the global scope.
virtual StringLiteral * as_string_literal()
Interprets this node to a node of type StringLiteral.
One< StatementList > body
The loop body.
virtual ForLoop * as_for_loop()
Interprets this node to a node of type ForLoop.
void context(const tree::Annotatable &node)
Sets the context of this error to the SourceLocation annotation of the given node, if the error doesn't already have such a context.
std::function< values::Value(const values::Values &)> FunctionImpl
C++ function representing (one of the overloads of) a function usable in cQASM constant expressions...
virtual BreakStatement * as_break_statement()
Interprets this node to a node of type BreakStatement.
int compare(const Version &other) const
Compares this version against the other version.
void analyze_error_model(const ast::Instruction &insn)
Analyzes the error model meta-instruction and, if valid, adds it to the analysis result.
Represents a comma-separated list of expressions.
::tree::annotatable::Annotatable Annotatable
ParseResult parse_file(const std::string &filename)
Parse the given file.
AnalysisResult analyze_string(const std::string &data, const std::string &filename="<unknown>") const
Parses and analyzes the given string.
One< Expression > condition
The condition for stopping iteration.
virtual WhileLoop * as_while_loop()
Interprets this node to a node of type WhileLoop.
void register_mapping(const std::string &name, const values::Value &value)
Registers an initial mapping from the given name to the given value.
ast::One< semantic::Program > unwrap(std::ostream &out=std::cerr) const
"Unwraps" the result (as you would in Rust) to get the program node or an exception.
Exception used for analysis errors.
Any< AnnotationData > annotations
Zero or more annotations attached to this object.
tree::Any< semantic::AnnotationData > analyze_annotations(const tree::Any< ast::AnnotationData > &annotations)
Analyzes the given list of annotations.
virtual BitwiseAnd * as_bitwise_and()
Interprets this node to a node of type BitwiseAnd.