Skip to content

Commit

Permalink
[core refactor] Use syntax_asdl::loc_t type everywhere
Browse files Browse the repository at this point in the history
  • Loading branch information
Andy C committed Jan 25, 2023
1 parent b09d017 commit 03228de
Show file tree
Hide file tree
Showing 12 changed files with 102 additions and 197 deletions.
14 changes: 10 additions & 4 deletions core/alloc.py
@@ -1,8 +1,8 @@
"""
alloc.py - Sketch of memory management.
alloc.py - FAILED attempt at memory management.
This is roughly what you might do in C++, but it's probably overly complicated
for Python.
TODO: Just use a straightforward graph and rely on the garbage collector.
There's NO ARENA.
The idea is to save the LST for functions, but discard it for commands that
have already executed. Each statement/function can be parsed into a separate
Expand All @@ -11,9 +11,10 @@
Also, we don't want to save comment lines.
"""

from _devbuild.gen.syntax_asdl import line_span, source_t
from _devbuild.gen.syntax_asdl import line_span, source_t, loc_t
from asdl import runtime
from core.pyerror import log
from frontend import location

from typing import List, Dict, Any

Expand Down Expand Up @@ -160,6 +161,11 @@ def GetLineSpan(self, span_id):
'Span ID out of range: %d is greater than %d' % (span_id, len(self.spans))
return self.spans[span_id]

def LineSpanFromLocation(self, loc_):
# type: (loc_t) -> line_span
span_id = location.GetSpanId(loc_)
return self.GetLineSpan(span_id)

def LastSpanId(self):
# type: () -> int
"""Return one past the last span ID."""
Expand Down
10 changes: 5 additions & 5 deletions core/dev.py
Expand Up @@ -16,9 +16,10 @@
from core import optview
from core import state
from core import ui
from qsn_ import qsn
from core.pyerror import log
from frontend import location
from osh import word_
from qsn_ import qsn
from pylib import os_path
from mycpp import mylib
from mycpp.mylib import tagswitch, iteritems
Expand All @@ -37,7 +38,7 @@
from frontend.parse_lib import ParseContext
from core.state import MutableOpts, Mem
from osh.word_eval import NormalWordEvaluator
#from osh.cmd_eval import CommandEvaluator
from osh.cmd_eval import CommandEvaluator


class CrashDumper(object):
Expand Down Expand Up @@ -82,8 +83,7 @@ def __init__(self, crash_dump_dir):
self.error = None # type: Dict[str, Any]

def MaybeRecord(self, cmd_ev, err):
# type: (Any, _ErrorWithLocation) -> None
# TODO: Any -> CommandEvaluator
# type: (CommandEvaluator, _ErrorWithLocation) -> None
"""
Collect data for a crash dump.
Expand All @@ -96,7 +96,7 @@ def MaybeRecord(self, cmd_ev, err):

if mylib.PYTHON: # can't translate yet due to dynamic typing
self.var_stack, self.argv_stack, self.debug_stack = cmd_ev.mem.Dump()
span_id = word_.SpanIdFromError(err)
span_id = location.GetSpanId(err.location)

self.error = {
'msg': err.UserErrorString(),
Expand Down
102 changes: 18 additions & 84 deletions core/error.py
Expand Up @@ -3,14 +3,8 @@
"""
from __future__ import print_function

from _devbuild.gen.syntax_asdl import (
Token, loc_e, loc_t, loc__Span, loc__WordPart, loc__Word)
from _devbuild.gen.syntax_asdl import loc_e, loc_t
from mycpp import mylib
from mycpp.mylib import tagswitch

from typing import Dict, Any, Optional, cast, TYPE_CHECKING
if TYPE_CHECKING: # avoid circular build deps
from _devbuild.gen.syntax_asdl import word_part_t, word_t

# Break circular dependency.
#from asdl import runtime
Expand All @@ -19,42 +13,6 @@

if mylib.PYTHON:

def LocationShim(location):
# type: (Optional[loc_t]) -> Dict[str, Any]
""" TODO: Remove this and cleanup _ErrorWithLocation constructor. """

kwargs = {} # type: Dict[str, Any]

if location is None:
kwargs['span_id'] = NO_SPID
else:
UP_location = location
with tagswitch(location) as case:
if case(loc_e.Missing):
kwargs['span_id'] = NO_SPID

elif case(loc_e.Token):
tok = cast(Token, UP_location)
kwargs['token'] = tok

elif case(loc_e.Span):
location = cast(loc__Span, UP_location)
kwargs['span_id'] = location.span_id

elif case(loc_e.WordPart):
location = cast(loc__WordPart, UP_location)
kwargs['part'] = location.p

elif case(loc_e.Word):
location = cast(loc__Word, UP_location)
kwargs['word'] = location.w

else:
# TODO: fill in other cases
raise AssertionError()

return kwargs

class Usage(Exception):
"""For flag parsing errors in builtins and main()
Expand All @@ -72,41 +30,23 @@ class _ErrorWithLocation(Exception):
Formatting is in ui.PrintError.
"""
def __init__(self, msg, *args, **kwargs):
# type: (str, *Any, **Any) -> None
def __init__(self, msg, location):
# type: (str, loc_t) -> None
Exception.__init__(self)
self.msg = msg
self.args = args
# NOTE: We use a kwargs dict because Python 2 doesn't have keyword-only
# args.
# TODO: Remove these and create a location type. I think
# word_.SpanIdFromError() or LocationFromeError can be called when
# CREATING this exception, not in core/ui.py.
self.span_id = kwargs.pop('span_id', NO_SPID) # type: int
self.token = kwargs.pop('token', None) # type: Token
self.part = kwargs.pop('part', None) # type: word_part_t
self.word = kwargs.pop('word', None) # type: word_t

if kwargs:
raise AssertionError('Invalid keyword args %s' % kwargs)
self.location = location

def HasLocation(self):
# type: () -> bool
return bool(self.span_id != NO_SPID or
self.token or self.part or self.word)
return self.location.tag_() != loc_e.Missing

def UserErrorString(self):
# type: () -> str

if self.args:
# TODO: this case is obsolete
return self.msg % self.args
else:
return self.msg
return self.msg

def __repr__(self):
# type: () -> str
return '<%s %r %r>' % (self.msg, self.token, self.word)
return '<%s %r>' % (self.msg, self.location)

def __str__(self):
# type: () -> str
Expand Down Expand Up @@ -135,8 +75,7 @@ class Parse(_ErrorWithLocation):
"""Used in the parsers."""
def __init__(self, msg, location):
# type: (str, loc_t) -> None
kwargs = LocationShim(location)
_ErrorWithLocation.__init__(self, msg, **kwargs)
_ErrorWithLocation.__init__(self, msg, location)


class FailGlob(_ErrorWithLocation):
Expand All @@ -147,8 +86,7 @@ class FailGlob(_ErrorWithLocation):

def __init__(self, msg, location):
# type: (str, loc_t) -> None
kwargs = LocationShim(location)
_ErrorWithLocation.__init__(self, msg, **kwargs)
_ErrorWithLocation.__init__(self, msg, location)


class RedirectEval(_ErrorWithLocation):
Expand All @@ -159,8 +97,7 @@ class RedirectEval(_ErrorWithLocation):
"""
def __init__(self, msg, location):
# type: (str, loc_t) -> None
kwargs = LocationShim(location)
_ErrorWithLocation.__init__(self, msg, **kwargs)
_ErrorWithLocation.__init__(self, msg, location)


class FatalRuntime(_ErrorWithLocation):
Expand All @@ -169,9 +106,9 @@ class FatalRuntime(_ErrorWithLocation):
Used in the evaluators, and also also used in test builtin for invalid
argument.
"""
def __init__(self, exit_status, msg, **kwargs):
# type: (int, str, Dict[str, Any]) -> None
_ErrorWithLocation.__init__(self, msg, **kwargs)
def __init__(self, exit_status, msg, location):
# type: (int, str, loc_t) -> None
_ErrorWithLocation.__init__(self, msg, location)
self.exit_status = exit_status

def ExitStatus(self):
Expand All @@ -198,8 +135,7 @@ class Strict(FatalRuntime):
"""
def __init__(self, msg, location):
# type: (str, loc_t) -> None
kwargs = LocationShim(location)
FatalRuntime.__init__(self, 1, msg, **kwargs)
FatalRuntime.__init__(self, 1, msg, location)


class ErrExit(FatalRuntime):
Expand All @@ -209,8 +145,7 @@ class ErrExit(FatalRuntime):
"""
def __init__(self, exit_status, msg, location, show_code=False):
# type: (int, str, loc_t, bool) -> None
kwargs = LocationShim(location)
FatalRuntime.__init__(self, exit_status, msg, **kwargs)
FatalRuntime.__init__(self, exit_status, msg, location)
self.show_code = show_code


Expand All @@ -219,11 +154,10 @@ class Expr(FatalRuntime):

def __init__(self, msg, location):
# type: (str, loc_t) -> None
kwargs = LocationShim(location)

# New status 3 for expression errors -- for both the caught and uncaught
# case.
# Unique status of 3 for expression errors -- for both the caught and
# uncaught case.
#
# Caught: try sets _status register to 3
# Uncaught: shell exits with status 3
FatalRuntime.__init__(self, 3, msg, **kwargs)
FatalRuntime.__init__(self, 3, msg, location)
6 changes: 2 additions & 4 deletions core/pyerror.py
Expand Up @@ -76,8 +76,7 @@ def e_die(msg, location=None):
Usually exits with status 1. See osh/cmd_eval.py.
"""
kwargs = error.LocationShim(location)
raise error.FatalRuntime(1, msg, **kwargs)
raise error.FatalRuntime(1, msg, location)


def e_die_status(status, msg, location=None):
Expand All @@ -88,5 +87,4 @@ def e_die_status(status, msg, location=None):
Note that it doesn't take positional args, so you should use % formatting.
"""
kwargs = error.LocationShim(location)
raise error.FatalRuntime(status, msg, **kwargs)
raise error.FatalRuntime(status, msg, location)
6 changes: 3 additions & 3 deletions core/ui.py
Expand Up @@ -19,7 +19,7 @@
from _devbuild.gen.runtime_asdl import value_str, value_t
from asdl import runtime
from asdl import format as fmt
from osh import word_
from frontend import location
from mycpp import mylib
from mycpp.mylib import print_stderr, tagswitch, StrFromC
from qsn_ import qsn
Expand Down Expand Up @@ -328,7 +328,7 @@ def PrettyPrintError(self, err, prefix=''):
level, in CommandEvaluator.
"""
msg = err.UserErrorString()
span_id = word_.SpanIdFromError(err)
span_id = location.GetSpanId(err.location)

# TODO: Should there be a special span_id of 0 for EOF? runtime.NO_SPID
# means there is no location info, but 0 could mean that the location is EOF.
Expand All @@ -351,7 +351,7 @@ def PrintErrExit(self, err, pid):
#self.PrettyPrintError(err, prefix=prefix)

msg = err.UserErrorString()
span_id = word_.SpanIdFromError(err)
span_id = location.GetSpanId(err.location)
_PrintWithSpanId(prefix, msg, span_id, self.arena, err.show_code)


Expand Down

0 comments on commit 03228de

Please sign in to comment.