Skip to content

Commit

Permalink
Fix kernel parsing
Browse files Browse the repository at this point in the history
  • Loading branch information
evhub committed Nov 28, 2023
1 parent 88f571c commit a920e7f
Show file tree
Hide file tree
Showing 6 changed files with 77 additions and 7 deletions.
3 changes: 2 additions & 1 deletion coconut/compiler/compiler.py
Original file line number Diff line number Diff line change
Expand Up @@ -485,6 +485,7 @@ class Compiler(Grammar, pickleable_obj):
def __init__(self, *args, **kwargs):
"""Creates a new compiler with the given parsing parameters."""
self.setup(*args, **kwargs)
self.reset()

# changes here should be reflected in __reduce__, get_cli_args, and in the stub for coconut.api.setup
def setup(self, target=None, strict=False, minify=False, line_numbers=True, keep_lines=False, no_tco=False, no_wrap=False):
Expand Down Expand Up @@ -998,7 +999,7 @@ def remove_strs(self, inputstring, inner_environment=True, **kwargs):
try:
with (self.inner_environment() if inner_environment else noop_ctx()):
return self.str_proc(inputstring, **kwargs)
except Exception:
except CoconutSyntaxError:
logger.log_exc()
return None

Expand Down
2 changes: 1 addition & 1 deletion coconut/compiler/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -1806,7 +1806,7 @@ def collapse_indents(indentation):
def is_blank(line):
"""Determine whether a line is blank."""
line, _ = rem_and_count_indents(rem_comment(line))
return line.strip() == ""
return not line or line.isspace()


def final_indentation_level(code):
Expand Down
3 changes: 3 additions & 0 deletions coconut/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -1276,6 +1276,9 @@ def get_path_env_var(env_var, default):

enabled_xonsh_modes = ("single",)

# 1 is safe, 2 seems to work okay, and 3 breaks stuff like '"""\n(\n)\n"""'
num_assemble_logical_lines_tries = 1

# -----------------------------------------------------------------------------------------------------------------------
# DOCUMENTATION CONSTANTS:
# -----------------------------------------------------------------------------------------------------------------------
Expand Down
62 changes: 59 additions & 3 deletions coconut/icoconut/root.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,15 +43,17 @@
conda_build_env_var,
coconut_kernel_kwargs,
default_whitespace_chars,
num_assemble_logical_lines_tries,
)
from coconut.terminal import logger
from coconut.util import override, memoize_with_exceptions, replace_all
from coconut.compiler import Compiler
from coconut.compiler.util import should_indent
from coconut.compiler.util import should_indent, paren_change
from coconut.command.util import Runner

try:
from IPython.core.inputsplitter import IPythonInputSplitter
from IPython.core.inputtransformer import CoroutineInputTransformer
from IPython.core.interactiveshell import InteractiveShellABC
from IPython.core.compilerop import CachingCompiler
from IPython.terminal.embed import InteractiveShellEmbed
Expand Down Expand Up @@ -154,8 +156,8 @@ class CoconutSplitter(IPythonInputSplitter, object):
def __init__(self, *args, **kwargs):
"""Version of __init__ that sets up Coconut code compilation."""
super(CoconutSplitter, self).__init__(*args, **kwargs)
self._original_compile = self._compile
self._compile = self._coconut_compile
self._original_compile, self._compile = self._compile, self._coconut_compile
self.assemble_logical_lines = self._coconut_assemble_logical_lines()

def _coconut_compile(self, source, *args, **kwargs):
"""Version of _compile that checks Coconut code.
Expand All @@ -170,6 +172,60 @@ def _coconut_compile(self, source, *args, **kwargs):
else:
return True

@staticmethod
@CoroutineInputTransformer.wrap
def _coconut_assemble_logical_lines():
"""Version of assemble_logical_lines() that respects strings/parentheses/brackets/braces."""
line = ""
while True:
line = (yield line)
if not line or line.isspace():
continue

parts = []
level = 0
while line is not None:

# get no_strs_line
no_strs_line = None
while no_strs_line is None:
no_strs_line = line.strip()
if no_strs_line:
no_strs_line = COMPILER.remove_strs(no_strs_line)
if no_strs_line is None:
# if we're in the middle of a string, fetch a new line
for _ in range(num_assemble_logical_lines_tries):
new_line = (yield None)
if new_line is not None:
break
if new_line is None:
# if we're not able to build a no_strs_line, we should stop doing line joining
level = 0
no_strs_line = ""
break
else:
line += new_line

# update paren level
level += paren_change(no_strs_line)

# put line in parts and break if done
if level < 0:
parts.append(line)
elif no_strs_line.endswith("\\"):
parts.append(line[:-1])
else:
parts.append(line)
break

# if we're not done, fetch a new line
for _ in range(num_assemble_logical_lines_tries):
line = (yield None)
if line is not None:
break

line = ''.join(parts)

INTERACTIVE_SHELL_CODE = '''
input_splitter = CoconutSplitter(line_input_checker=True)
input_transformer_manager = CoconutSplitter(line_input_checker=False)
Expand Down
2 changes: 1 addition & 1 deletion coconut/root.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
VERSION = "3.0.4"
VERSION_NAME = None
# False for release, int >= 1 for develop
DEVELOP = 1
DEVELOP = 2
ALPHA = False # for pre releases rather than post releases

assert DEVELOP is False or DEVELOP >= 1, "DEVELOP must be False or an int >= 1"
Expand Down
12 changes: 11 additions & 1 deletion coconut/tests/src/extras.coco
Original file line number Diff line number Diff line change
Expand Up @@ -462,7 +462,7 @@ def test_kernel() -> bool:
captured_messages: list[tuple] = []
else:
captured_messages: list = []
def send(self, stream, msg_or_type, content, *args, **kwargs):
def send(self, stream, msg_or_type, content=None, *args, **kwargs):
self.captured_messages.append((msg_or_type, content))

if PY35:
Expand Down Expand Up @@ -515,6 +515,16 @@ def test_kernel() -> bool:
assert keyword_complete_result["cursor_start"] == 0
assert keyword_complete_result["cursor_end"] == 1

assert k.do_execute("ident$(\n?,\n)(99)", False, True, {}, True) |> unwrap_future$(loop) |> .["status"] == "ok"
captured_msg_type, captured_msg_content = fake_session.captured_messages[-1]
assert captured_msg_content is None
assert captured_msg_type["content"]["data"]["text/plain"] == "99"

assert k.do_execute('"""\n(\n)\n"""', False, True, {}, True) |> unwrap_future$(loop) |> .["status"] == "ok"
captured_msg_type, captured_msg_content = fake_session.captured_messages[-1]
assert captured_msg_content is None
assert captured_msg_type["content"]["data"]["text/plain"] == "'()'"

return True


Expand Down

0 comments on commit a920e7f

Please sign in to comment.