Skip to content
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
84 changes: 80 additions & 4 deletions parsers/sh.c
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
K_FUNCTION,
K_SCRIPT,
K_HEREDOCLABEL,
K_VARIABLE,
} shKind;

typedef enum {
Expand Down Expand Up @@ -86,8 +87,10 @@
.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 All @@ -103,6 +106,7 @@
KEYWORD_alias,
KEYWORD_source,
KEYWORD_autoload,
KEYWORD_declare, /* declare, typeset, local, export, readonly, float(zsh), integer */
};

const char *dialectMap [] = {
Expand All @@ -114,6 +118,13 @@
{ "alias", KEYWORD_alias, { 1, 1 } },
{ "source", KEYWORD_source, { 1, 1 } },
{ "autoload", KEYWORD_autoload, { 0, 1 } },
{ "declare", KEYWORD_declare, { 1, 1 } },
{ "typset", KEYWORD_declare, { 1, 1 } },
{ "local", KEYWORD_declare, { 1, 1 } },
{ "export", KEYWORD_declare, { 1, 1 } },
{ "readonly", KEYWORD_declare, { 1, 1 } },
{ "float", KEYWORD_declare, { 0, 1 } },
{ "integer", KEYWORD_declare, { 0, 1 } },
};

/*
Expand Down Expand Up @@ -352,6 +363,10 @@
*role = R_SCRIPT_LOADED;
*check_char = isFileChar;
break;
case KEYWORD_declare:
*kind = K_VARIABLE;
*check_char = isIdentChar;
break;

Check warning on line 369 in parsers/sh.c

View check run for this annotation

Codecov / codecov/patch

parsers/sh.c#L366-L369

Added lines #L366 - L369 were not covered by tests
default:
AssertNotReached();
break;
Expand Down Expand Up @@ -509,6 +524,54 @@
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)

Check warning on line 536 in parsers/sh.c

View check run for this annotation

Codecov / codecov/patch

parsers/sh.c#L536

Added line #L536 was not covered by tests
{
if (*cp == ';' || *cp == '|' || *cp == '&'
|| *cp == '(' || *cp == '{')

Check warning on line 539 in parsers/sh.c

View check run for this annotation

Codecov / codecov/patch

parsers/sh.c#L538-L539

Added lines #L538 - L539 were not covered by tests
return false;
else if (isspace(*cp))
cp--;

Check warning on line 542 in parsers/sh.c

View check run for this annotation

Codecov / codecov/patch

parsers/sh.c#L541-L542

Added lines #L541 - L542 were not covered by tests
else
return true;
}
return false;
}

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

while (*cp != '\0')
{
if (*cp == '=' || (*cp == '+' && *(cp + 1) == '='))
{
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 @@ -527,6 +590,7 @@
struct hereDocParsingState hstate;
hdocStateInit (&hstate);

bool cont_line = false;
while ((line = readLineFromInputFile ()) != NULL)
{
const unsigned char* cp = line;
Expand All @@ -552,10 +616,12 @@
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 @@ -693,6 +759,7 @@
cp += d;
else if (*cp != '\0')
++cp;
beginning_of_line = false;
continue;
}

Expand All @@ -706,8 +773,9 @@
while (isspace (*cp))
++cp;

if ((found_kind != K_SCRIPT)
&& *cp == '(')
if (found_kind == K_SCRIPT)
; /* Do NOTHING */
else if (*cp == '(')
{
++cp;
while (isspace (*cp))
Expand All @@ -733,6 +801,10 @@
++cp;
}
}
else if (beginning_of_line
&& found_kind == K_NOTHING
&& handleVariableAssignment (name))
found_kind = K_VARIABLE;

if (found_kind != K_NOTHING)
{
Expand All @@ -749,7 +821,11 @@
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
Loading