diff --git a/integration_tests/CMakeLists.txt b/integration_tests/CMakeLists.txt index f76a802599..37e6c2806e 100644 --- a/integration_tests/CMakeLists.txt +++ b/integration_tests/CMakeLists.txt @@ -540,7 +540,6 @@ RUN(NAME generics_list_01 LABELS cpython llvm c) RUN(NAME test_statistics LABELS cpython llvm) RUN(NAME test_str_attributes LABELS cpython llvm c) RUN(NAME kwargs_01 LABELS cpython llvm c) -RUN(NAME test_01_goto LABELS cpython llvm c) RUN(NAME func_inline_01 LABELS llvm c wasm) RUN(NAME func_inline_02 LABELS cpython llvm c) diff --git a/integration_tests/test_01_goto.py b/integration_tests/test_01_goto.py deleted file mode 100644 index a0842344d4..0000000000 --- a/integration_tests/test_01_goto.py +++ /dev/null @@ -1,35 +0,0 @@ -from lpython import with_goto, i32 - -@with_goto -def f() -> i32: - i:i32 - for i in range(10): - if i == 5: - goto .end - - label .end - assert i == 5 - return i - -@with_goto -def g(size: i32) -> i32: - i:i32 - - i = 0 - label .loop - if i >= size: - goto .end - i += 1 - goto .loop - - label .end - return i - -def test_goto(): - print(f()) - print(g(10)) - print(g(20)) - assert g(30) == 30 - assert g(40) == 40 - -test_goto() diff --git a/src/lpython/semantics/python_ast_to_asr.cpp b/src/lpython/semantics/python_ast_to_asr.cpp index 44fcdf5811..8c4dbbc497 100644 --- a/src/lpython/semantics/python_ast_to_asr.cpp +++ b/src/lpython/semantics/python_ast_to_asr.cpp @@ -3793,8 +3793,6 @@ class SymbolTableVisitor : public CommonVisitor { vectorize = true; } else if (name == "restriction") { is_restriction = true; - } else if (name == "with_goto") { - // TODO: Use goto attribute in function? } else if (name == "inline") { is_inline = true; } else if (name == "static") { @@ -4337,8 +4335,6 @@ class BodyVisitor : public CommonVisitor { public: ASR::asr_t *asr; - std::map> goto_name2id; - int64_t gotoids; std::vector do_loop_variables; // Stores the name of imported functions and the modules they are imported from std::map imported_functions; @@ -4348,13 +4344,12 @@ class BodyVisitor : public CommonVisitor { bool main_module, std::map &ast_overload, bool allow_implicit_casting_) : CommonVisitor(al, lm, nullptr, diagnostics, main_module, ast_overload, "", {}, allow_implicit_casting_), - asr{unit}, gotoids{0} + asr{unit} {} // Transforms statements to a list of ASR statements // In addition, it also inserts the following nodes if needed: // * ImplicitDeallocate - // * GoToTarget // The `body` Vec must already be reserved void transform_stmts(Vec &body, size_t n_body, AST::stmt_t **m_body) { tmp = nullptr; @@ -4505,8 +4500,6 @@ class BodyVisitor : public CommonVisitor { } void visit_FunctionDef(const AST::FunctionDef_t &x) { - goto_name2id.clear(); - gotoids = 0; SymbolTable *old_scope = current_scope; ASR::symbol_t *t = current_scope->get_symbol(x.m_name); if (ASR::is_a(*t)) { @@ -4527,13 +4520,6 @@ class BodyVisitor : public CommonVisitor { } current_scope = old_scope; tmp = nullptr; - - for( auto itr: goto_name2id ) { - if( !std::get<1>(itr.second) ) { - throw SemanticError("Label '" + itr.first + "' is not defined in '" - + std::string(x.m_name) + "'", std::get<2>(itr.second)); - } - } } void visit_Import(const AST::Import_t &x) { @@ -5523,33 +5509,6 @@ class BodyVisitor : public CommonVisitor { void visit_Attribute(const AST::Attribute_t &x) { if (AST::is_a(*x.m_value)) { std::string value = AST::down_cast(x.m_value)->m_id; - if( value == "label" ) { - std::string labelname = x.m_attr; - if( goto_name2id.find(labelname) == goto_name2id.end() ) { - goto_name2id[labelname] = std::make_tuple(gotoids, true, x.base.base.loc); - gotoids += 1; - } else if( !std::get<1>(goto_name2id[labelname]) ) { - goto_name2id[labelname] = std::make_tuple( - std::get<0>(goto_name2id[labelname]), - true, - std::get<2>(goto_name2id[labelname]) - ); - } - int id = std::get<0>(goto_name2id[labelname]); - tmp = ASR::make_GoToTarget_t(al, x.base.base.loc, id, x.m_attr); - return ; - } - - if (value == "goto"){ - std::string labelname = std::string(x.m_attr); - if( goto_name2id.find(labelname) == goto_name2id.end() ) { - goto_name2id[labelname] = std::make_tuple(gotoids, false, x.base.base.loc); - gotoids += 1; - } - int id = std::get<0>(goto_name2id[labelname]); - tmp = ASR::make_GoTo_t(al, x.base.base.loc, id, x.m_attr); - return ; - } ASR::symbol_t *org_sym = current_scope->resolve_symbol(value); if (!org_sym) { diff --git a/src/runtime/lpython/goto.py b/src/runtime/lpython/goto.py deleted file mode 100644 index 55c10759b0..0000000000 --- a/src/runtime/lpython/goto.py +++ /dev/null @@ -1,241 +0,0 @@ -""" -The source code of this file is coming from -https://github.com/snoack/python-goto/blob/acbe736221d2238df3d09beab457d0bb19d05812/goto.py. -The license of the python-goto project at the time of inclusion in LPython is available at -https://github.com/snoack/python-goto/blob/acbe736221d2238df3d09beab457d0bb19d05812/LICENSE. -""" -import dis -import struct -import array -import types -import functools - - -try: - _array_to_bytes = array.array.tobytes -except AttributeError: - _array_to_bytes = array.array.tostring - - -class _Bytecode: - def __init__(self): - code = (lambda: x if x else y).__code__.co_code - opcode, oparg = struct.unpack_from('BB', code, 2) - - # Starting with Python 3.6, the bytecode format has changed, using - # 16-bit words (8-bit opcode + 8-bit argument) for each instruction, - # as opposed to previously 24 bit (8-bit opcode + 16-bit argument) - # for instructions that expect an argument and otherwise 8 bit. - # https://bugs.python.org/issue26647 - if dis.opname[opcode] == 'POP_JUMP_IF_FALSE': - self.argument = struct.Struct('B') - self.have_argument = 0 - # As of Python 3.6, jump targets are still addressed by their - # byte unit. This is matter to change, so that jump targets, - # in the future might refer to code units (address in bytes / 2). - # https://bugs.python.org/issue26647 - self.jump_unit = 8 // oparg - else: - self.argument = struct.Struct('= _BYTECODE.have_argument: - oparg = extended_arg | _BYTECODE.argument.unpack_from(code, pos)[0] - pos += _BYTECODE.argument.size - - if opcode == dis.EXTENDED_ARG: - extended_arg = oparg << _BYTECODE.argument_bits - extended_arg_offset = offset - continue - - extended_arg = 0 - extended_arg_offset = None - yield (dis.opname[opcode], oparg, offset) - - -def _get_instruction_size(opname, oparg=0): - size = 1 - - extended_arg = oparg >> _BYTECODE.argument_bits - if extended_arg != 0: - size += _get_instruction_size('EXTENDED_ARG', extended_arg) - oparg &= (1 << _BYTECODE.argument_bits) - 1 - - opcode = dis.opmap[opname] - if opcode >= _BYTECODE.have_argument: - size += _BYTECODE.argument.size - - return size - - -def _get_instructions_size(ops): - size = 0 - for op in ops: - if isinstance(op, str): - size += _get_instruction_size(op) - else: - size += _get_instruction_size(*op) - return size - - -def _write_instruction(buf, pos, opname, oparg=0): - extended_arg = oparg >> _BYTECODE.argument_bits - if extended_arg != 0: - pos = _write_instruction(buf, pos, 'EXTENDED_ARG', extended_arg) - oparg &= (1 << _BYTECODE.argument_bits) - 1 - - opcode = dis.opmap[opname] - buf[pos] = opcode - pos += 1 - - if opcode >= _BYTECODE.have_argument: - _BYTECODE.argument.pack_into(buf, pos, oparg) - pos += _BYTECODE.argument.size - - return pos - - -def _write_instructions(buf, pos, ops): - for op in ops: - if isinstance(op, str): - pos = _write_instruction(buf, pos, op) - else: - pos = _write_instruction(buf, pos, *op) - return pos - - -def _find_labels_and_gotos(code): - labels = {} - gotos = [] - - block_stack = [] - block_counter = 0 - - opname1 = oparg1 = offset1 = None - opname2 = oparg2 = offset2 = None - opname3 = oparg3 = offset3 = None - - for opname4, oparg4, offset4 in _parse_instructions(code.co_code): - if opname1 in ('LOAD_GLOBAL', 'LOAD_NAME'): - if opname2 == 'LOAD_ATTR' and opname3 == 'POP_TOP': - name = code.co_names[oparg1] - if name == 'label': - if oparg2 in labels: - raise SyntaxError('Ambiguous label {0!r}'.format( - code.co_names[oparg2] - )) - labels[oparg2] = (offset1, - offset4, - tuple(block_stack)) - elif name == 'goto': - gotos.append((offset1, - offset4, - oparg2, - tuple(block_stack))) - elif opname1 in ('SETUP_LOOP', - 'SETUP_EXCEPT', 'SETUP_FINALLY', - 'SETUP_WITH', 'SETUP_ASYNC_WITH'): - block_counter += 1 - block_stack.append(block_counter) - elif opname1 == 'POP_BLOCK' and block_stack: - block_stack.pop() - - opname1, oparg1, offset1 = opname2, oparg2, offset2 - opname2, oparg2, offset2 = opname3, oparg3, offset3 - opname3, oparg3, offset3 = opname4, oparg4, offset4 - - return labels, gotos - - -def _inject_nop_sled(buf, pos, end): - while pos < end: - pos = _write_instruction(buf, pos, 'NOP') - - -def _patch_code(code): - labels, gotos = _find_labels_and_gotos(code) - buf = array.array('B', code.co_code) - - for pos, end, _ in labels.values(): - _inject_nop_sled(buf, pos, end) - - for pos, end, label, origin_stack in gotos: - try: - _, target, target_stack = labels[label] - except KeyError: - raise SyntaxError('Unknown label {0!r}'.format( - code.co_names[label] - )) - - target_depth = len(target_stack) - if origin_stack[:target_depth] != target_stack: - raise SyntaxError('Jump into different block') - - ops = [] - for i in range(len(origin_stack) - target_depth): - ops.append('POP_BLOCK') - ops.append(('JUMP_ABSOLUTE', target // _BYTECODE.jump_unit)) - - if pos + _get_instructions_size(ops) > end: - # not enough space, add code at buffer end and jump there - buf_end = len(buf) - - go_to_end_ops = [('JUMP_ABSOLUTE', buf_end // _BYTECODE.jump_unit)] - - if pos + _get_instructions_size(go_to_end_ops) > end: - # not sure if reachable - raise SyntaxError('Goto in an incredibly huge function') - - pos = _write_instructions(buf, pos, go_to_end_ops) - _inject_nop_sled(buf, pos, end) - - buf.extend([0] * _get_instructions_size(ops)) - _write_instructions(buf, buf_end, ops) - else: - pos = _write_instructions(buf, pos, ops) - _inject_nop_sled(buf, pos, end) - - return _make_code(code, _array_to_bytes(buf)) - - -def with_goto(func_or_code): - if isinstance(func_or_code, types.CodeType): - return _patch_code(func_or_code) - - return functools.update_wrapper( - types.FunctionType( - _patch_code(func_or_code.__code__), - func_or_code.__globals__, - func_or_code.__name__, - func_or_code.__defaults__, - func_or_code.__closure__, - ), - func_or_code - ) diff --git a/src/runtime/lpython/lpython.py b/src/runtime/lpython/lpython.py index c14b45738f..62c70bbb8e 100644 --- a/src/runtime/lpython/lpython.py +++ b/src/runtime/lpython/lpython.py @@ -3,12 +3,11 @@ import ctypes import platform from dataclasses import dataclass as py_dataclass, is_dataclass as py_is_dataclass -from goto import with_goto # TODO: this does not seem to restrict other imports __slots__ = ["i8", "i16", "i32", "i64", "u8", "u16", "u32", "u64", "f32", "f64", "c32", "c64", "CPtr", "overload", "ccall", "TypeVar", "pointer", "c_p_pointer", "Pointer", - "p_c_pointer", "vectorize", "inline", "Union", "static", "with_goto", + "p_c_pointer", "vectorize", "inline", "Union", "static", "packed", "Const", "sizeof", "ccallable", "ccallback", "Callable", "Allocatable"] diff --git a/tests/errors/test_goto.py b/tests/errors/test_goto.py deleted file mode 100644 index 649d659751..0000000000 --- a/tests/errors/test_goto.py +++ /dev/null @@ -1,12 +0,0 @@ -from lpython import with_goto, goto, label, i32 - -@with_goto -def f(): - i:i32 - for i in range(10): - if i == 5: - goto .end - - assert i == 5 - -f() diff --git a/tests/reference/asr-test_goto-ba9fd22.json b/tests/reference/asr-test_goto-ba9fd22.json deleted file mode 100644 index afa1b0f060..0000000000 --- a/tests/reference/asr-test_goto-ba9fd22.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "basename": "asr-test_goto-ba9fd22", - "cmd": "lpython --show-asr --no-color {infile} -o {outfile}", - "infile": "tests/errors/test_goto.py", - "infile_hash": "02cc918eba32d981a943d61cc908d9ccbdcebaa71f61b16f49ef28ba", - "outfile": null, - "outfile_hash": null, - "stdout": null, - "stdout_hash": null, - "stderr": "asr-test_goto-ba9fd22.stderr", - "stderr_hash": "a1e26c1edcd8784938199af965004496663f071968ff7d58a33be725", - "returncode": 2 -} \ No newline at end of file diff --git a/tests/reference/asr-test_goto-ba9fd22.stderr b/tests/reference/asr-test_goto-ba9fd22.stderr deleted file mode 100644 index 019db15d63..0000000000 --- a/tests/reference/asr-test_goto-ba9fd22.stderr +++ /dev/null @@ -1,5 +0,0 @@ -semantic error: Label 'end' is not defined in 'f' - --> tests/errors/test_goto.py:8:13 - | -8 | goto .end - | ^^^^^^^^^ diff --git a/tests/tests.toml b/tests/tests.toml index 5eb4f90f01..be62d907b1 100644 --- a/tests/tests.toml +++ b/tests/tests.toml @@ -1062,10 +1062,6 @@ asr = true filename = "errors/loop_03.py" asr = true -[[test]] -filename = "errors/test_goto.py" -asr = true - [[test]] filename = "errors/bindc_01.py" asr = true