Skip to content

Commit

Permalink
[translation] ctx_Alias
Browse files Browse the repository at this point in the history
Hm this doesn't fix the infinite loop in case #3 of spec/alias?  Still
need to work on that.

mylib: add comments and test cases
  • Loading branch information
Andy Chu committed Jul 15, 2020
1 parent 35066bf commit c503d2d
Show file tree
Hide file tree
Showing 4 changed files with 55 additions and 43 deletions.
59 changes: 33 additions & 26 deletions frontend/parse_lib.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ def __init__(self):
self.tokens = [] # type: List[Token]

self.alias_words = [] # type: List[compound_word] # words INSIDE an alias expansion
self.expanding_alias = False
self._expanding_alias = False

def Clear(self):
# type: () -> None
Expand Down Expand Up @@ -120,6 +120,36 @@ class _NullTrail(_BaseTrail):
pass


class ctx_Alias(object):
"""Used by CommandParser so we know to be ready for FIRST alias word.
For example, for
alias ll='ls -l'
Then we want to capture 'ls' as the first word.
We do NOT want SetLatestWords or AppendToken to be active, because we don't
need other tokens from 'ls -l'.
It would also probably cause bugs in history expansion, e.g. echo !1 should
be the first word the user typed, not the first word after alias expansion.
"""

def __init__(self, trail):
# type: (_BaseTrail) -> None
trail._expanding_alias = True
self.trail = trail

def __enter__(self):
# type: () -> None
pass

def __exit__(self, type, value, traceback):
# type: (Any, Any, Any) -> None
self.trail._expanding_alias = False


class Trail(_BaseTrail):
"""Info left by the parser to help us complete shell syntax and commands.
Expand All @@ -135,41 +165,18 @@ def Clear(self):

def SetLatestWords(self, words, redirects):
# type: (List[compound_word], List[redir]) -> None
if self.expanding_alias:
if self._expanding_alias:
self.alias_words = words # Save these separately
return
self.words = words
self.redirects = redirects

def AppendToken(self, token):
# type: (Token) -> None
if self.expanding_alias: # We don't want tokens inside aliases
if self._expanding_alias: # We don't want tokens inside aliases
return
self.tokens.append(token)

def BeginAliasExpansion(self):
# type: () -> None
"""Called by CommandParser so we know to be ready for FIRST alias word.
For example, for
alias ll='ls -l'
Then we want to capture 'ls' as the first word.
We do NOT want SetLatestWords or AppendToken to be active, because we don't
need other tokens from 'ls -l'.
It would also probably cause bugs in history expansion, e.g. echo !1 should
be the first word the user typed, not the first word after alias expansion.
"""
self.expanding_alias = True

def EndAliasExpansion(self):
# type: () -> None
"""Go back to the normal trail collection mode."""
self.expanding_alias = False


if TYPE_CHECKING:
AliasesInFlight = List[Tuple[str, int]]
Expand Down
8 changes: 4 additions & 4 deletions mycpp/mylib.h
Original file line number Diff line number Diff line change
Expand Up @@ -894,10 +894,10 @@ inline int ord(Str* s) {
}

// https://stackoverflow.com/questions/3919995/determining-sprintf-buffer-size-whats-the-standard/11092994#11092994
// Note: Python 2.7's intobject.c has an erroneous +6

// This is 13, but
// len('-2147483648') is 11, which means we only need 12?
// Notes:
// - Python 2.7's intobject.c has an erroneous +6
// - This is 13, but len('-2147483648') is 11, which means we only need 12?
// - This formula is valid for octal(), because 2^(3 bits) = 8
const int kIntBufSize = CHAR_BIT * sizeof(int) / 3 + 3;

inline Str* str(int i) {
Expand Down
7 changes: 6 additions & 1 deletion mycpp/mylib_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -143,17 +143,22 @@ TEST test_str_funcs() {

int_str = str(-(1 << 31) + 1);
log("i = %s", int_str->data_);
int_str = str(-(1 << 31));

int int_min = -(1 << 31);
int_str = str(int_min);
log("i = %s", int_str->data_);

int_str = mylib::hex_lower(15);
ASSERT(str_equals0("f", int_str));
print(mylib::hex_lower(int_min)); // ASAN implicitly checks this

int_str = mylib::hex_upper(15);
ASSERT(str_equals0("F", int_str));
print(mylib::hex_upper(int_min)); // ASAN

int_str = mylib::octal(15);
ASSERT(str_equals0("17", int_str));
print(mylib::octal(int_min)); // ASAN

Str* s1 = new Str("abc\0bcd", 7);
ASSERT_EQ(7, len(s1));
Expand Down
24 changes: 12 additions & 12 deletions osh/cmd_parse.py
Original file line number Diff line number Diff line change
Expand Up @@ -728,22 +728,22 @@ def _MaybeExpandAliases(self, words):
cp = self.parse_ctx.MakeOshParser(line_reader)
cp.Init_AliasesInFlight(aliases_in_flight)

# break circular dep
from frontend import parse_lib

# The interaction between COMPLETION and ALIASES requires special care.
# See docstring of BeginAliasExpansion() in parse_lib.py.
src = source.Alias(first_word_str, argv0_spid)
with alloc.ctx_Location(self.arena, src):
trail = self.parse_ctx.trail
trail.BeginAliasExpansion()
try:
# _ParseCommandTerm() handles multiline commands, compound commands, etc.
# as opposed to ParseLogicalLine()
node = cp._ParseCommandTerm()
except error.Parse as e:
# Failure to parse alias expansion is a fatal error
# We don't need more handling here/
raise
finally:
trail.EndAliasExpansion()
with parse_lib.ctx_Alias(self.parse_ctx.trail):
try:
# _ParseCommandTerm() handles multiline commands, compound commands, etc.
# as opposed to ParseLogicalLine()
node = cp._ParseCommandTerm()
except error.Parse as e:
# Failure to parse alias expansion is a fatal error
# We don't need more handling here/
raise

if 0:
log('AFTER expansion:')
Expand Down

0 comments on commit c503d2d

Please sign in to comment.