Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] Sh: [EXPERIMENTAL] extract variables in variable assignments #3544

Draft
wants to merge 3 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion Tmain/ptag-in-optlib-parser.d/stdout-expected.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,9 @@
!_TAG_FILE_SORTED 1 /0=unsorted, 1=sorted, 2=foldcase/
!_TAG_KIND_DESCRIPTION!Sh a,alias /aliases/
!_TAG_KIND_DESCRIPTION!Sh f,function /functions/
!_TAG_KIND_DESCRIPTION!Sh h,heredoc /label for here document/
!_TAG_KIND_DESCRIPTION!Sh h,heredoc /labels for here document/
!_TAG_KIND_DESCRIPTION!Sh s,script /script files/
!_TAG_KIND_DESCRIPTION!Sh v,variable /variables assigment (experimental)/
!_TAG_OUTPUT_EXCMD mixed /number, pattern, mixed, or combineV2/
!_TAG_OUTPUT_FILESEP slash /slash or backslash/
!_TAG_OUTPUT_MODE u-ctags /u-ctags or e-ctags/
Expand Down
4 changes: 4 additions & 0 deletions Units/parser-sh.r/sh-comments.d/expected.tags
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,7 @@ afterpound1 input.sh /^foo="#"; afterpound1() {}$/;" f
afterpound2 input.sh /^foo="#\\""; afterpound2() {}$/;" f
afterpound3 input.sh /^foo='#'; afterpound3() {}$/;" f
afterpound4 input.sh /^foo='#'''; afterpound4() {}$/;" f
foo input.sh /^foo="#"; afterpound1() {}$/;" v
foo input.sh /^foo="#\\""; afterpound2() {}$/;" v
foo input.sh /^foo='#'''; afterpound4() {}$/;" v
foo input.sh /^foo='#'; afterpound3() {}$/;" v
5 changes: 5 additions & 0 deletions Units/parser-sh.r/sh-quotes.d/expected.tags
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,8 @@ afterpound1 input.sh /^foo="#"; afterpound1() {}$/;" f
afterpound2 input.sh /^foo="#\\""; afterpound2() {}$/;" f
afterpound3 input.sh /^foo='#'; afterpound3() {}$/;" f
afterpound4 input.sh /^foo='#'''; afterpound4() {}$/;" f
foo input.sh /^foo="#"; afterpound1() {}$/;" v
foo input.sh /^foo="#\\""; afterpound2() {}$/;" v
foo input.sh /^foo="nofunction()"$/;" v
foo input.sh /^foo='#'''; afterpound4() {}$/;" v
foo input.sh /^foo='#'; afterpound3() {}$/;" v
71 changes: 67 additions & 4 deletions parsers/sh.c
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ typedef enum {
K_FUNCTION,
K_SCRIPT,
K_HEREDOCLABEL,
K_VARIABLE,
} shKind;

typedef enum {
Expand Down Expand Up @@ -86,8 +87,10 @@ static roleDefinition ZshFunctionRoles [] = {
.referenceOnly = false, FUNCTION_ROLES_SPEC }, \
{ true, 's', "script", "script files", \
.referenceOnly = true, ATTACH_ROLES (SCRIPT_ROLES) }, \
{ true, 'h', "heredoc", "label for here document", \
.referenceOnly = false, ATTACH_ROLES (HEREDOC_ROLES) }
{ true, 'h', "heredoc", "labels for here document", \
.referenceOnly = false, ATTACH_ROLES (HEREDOC_ROLES) }, \
{ true, 'v', "variable", "variables assigment (experimental)" }


static kindDefinition ShKinds [] = {
SH_KINDS_COMMON(ShScriptRoles, ShHeredocRoles,),
Expand Down Expand Up @@ -456,6 +459,53 @@ static size_t handleZshKeyword (int keyword,
return vStringLength(token);
}

static bool doesLineCotinue(const unsigned char *start, const unsigned char *cp)
{
cp--;
if (start >= cp)
return false;

if (*cp != '\\')
return false;

while (start < cp)
{
if (*cp == ';' || *cp == '|' || *cp == '&')
return false;
else if (isspace(*cp))
cp--;
else
return true;
}
return false;
}

static bool handleVariableAssignment (vString *input)
{
const char *base = vStringValue (input);
const char *cp = base;

while (*cp != '\0')
{
if (*cp == '=')
{
size_t len = cp - base;
if (len > 0)
{
vStringTruncate (input, len);
return true;
}
break;
}
else if ( ((cp == base)?
isIdentChar0: isIdentChar) ((unsigned char)*cp) )
cp++;
else
break;
}
return false;
}

typedef bool (* checkCharFunc) (int);
static void findShTagsCommon (size_t (* keyword_handler) (int,
vString *,
Expand All @@ -474,6 +524,7 @@ static void findShTagsCommon (size_t (* keyword_handler) (int,
struct hereDocParsingState hstate;
hdocStateInit (&hstate);

bool cont_line = false;
while ((line = readLineFromInputFile ()) != NULL)
{
const unsigned char* cp = line;
Expand All @@ -499,10 +550,12 @@ static void findShTagsCommon (size_t (* keyword_handler) (int,
vStringDelete (hereDocDelimiter);
hereDocDelimiter = NULL;
}
cont_line = false;
continue;
}

hdocStateClear (&hstate);
bool beginning_of_line = !cont_line;
while (*cp != '\0')
{
subparser *sub = NULL;
Expand Down Expand Up @@ -640,6 +693,7 @@ static void findShTagsCommon (size_t (* keyword_handler) (int,
cp += d;
else if (*cp != '\0')
++cp;
beginning_of_line = false;
continue;
}

Expand All @@ -653,8 +707,9 @@ static void findShTagsCommon (size_t (* keyword_handler) (int,
while (isspace ((int) *cp))
++cp;

if ((found_kind != K_SCRIPT)
&& *cp == '(')
if (found_kind == K_SCRIPT)
; /* Do NOTHING */
else if (*cp == '(')
{
++cp;
while (isspace ((int) *cp))
Expand All @@ -680,6 +735,10 @@ static void findShTagsCommon (size_t (* keyword_handler) (int,
++cp;
}
}
else if (beginning_of_line
&& found_kind == K_NOTHING
&& handleVariableAssignment (name))
found_kind = K_VARIABLE;

if (found_kind != K_NOTHING)
{
Expand All @@ -696,7 +755,11 @@ static void findShTagsCommon (size_t (* keyword_handler) (int,
else if (!hereDocDelimiter)
hdocStateUpdateArgs (&hstate, name);
vStringClear (name);
beginning_of_line = false;
}
if (*cp == '#')
cont_line = false;
cont_line = doesLineCotinue (line, cp);
}
hdocStateFini (&hstate);
vStringDelete (name);
Expand Down