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

main: introduce --_paramdef-<LANG>=<NAME>,<DESCRIPTION> option #3613

Merged
merged 12 commits into from
Dec 29, 2022
Merged
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
4 changes: 4 additions & 0 deletions Tmain/list-params.d/run.sh
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,7 @@ echo
echo '# CPP MACHINABLE NOHEADER'
${C} --with-list-header=no --machinable --list-params=CPreProcessor
echo

echo '# CPP MACHINABLE NOHEADER + PARAM DEFINE WITH CMDLINE'
${C} --_paramdef-CPreProcessor='pragma,handle program' --with-list-header=no --machinable --list-params=CPreProcessor
echo
7 changes: 7 additions & 0 deletions Tmain/list-params.d/stdout-expected.txt
Original file line number Diff line number Diff line change
Expand Up @@ -59,3 +59,10 @@ define define replacement for an identifier (name(params,...)=definition)
if0 examine code within "#if 0" branch (true or [false])
ignore a token to be specially handled

# CPP MACHINABLE NOHEADER + PARAM DEFINE WITH CMDLINE
_expand expand macros if their definitions are in the current C/C++/CUDA input file (true or [false])
define define replacement for an identifier (name(params,...)=definition)
if0 examine code within "#if 0" branch (true or [false])
ignore a token to be specially handled
pragma handle program

11 changes: 11 additions & 0 deletions Units/paramdef.r/no-set.d/args.ctags
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
--langdef=Foo
--map-Foo=.foo
--kinddef-Foo=v,xval,externally defined values
--_paramdef-Foo=VAR,desc
--regex-Foo=/(x)//{{
/VAR _param {
/xval _tag _commit pop
} {
\1 /xval _tag _commit pop
} ifelse
}}
1 change: 1 addition & 0 deletions Units/paramdef.r/no-set.d/expected.tags
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
x input.foo /^x$/;" v
1 change: 1 addition & 0 deletions Units/paramdef.r/no-set.d/input.foo
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
x
10 changes: 10 additions & 0 deletions Units/paramdef.r/simple.d/args.ctags
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
--langdef=Foo
--map-Foo=.foo
--kinddef-Foo=v,xval,externally defined values
--_paramdef-Foo=VAR,desc
--regex-Foo=/(x)//{{
/VAR _param {
/xval _tag _commit pop
} if
}}
--param-Foo.VAR=y
1 change: 1 addition & 0 deletions Units/paramdef.r/simple.d/expected.tags
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
y input.foo /^x$/;" v
1 change: 1 addition & 0 deletions Units/paramdef.r/simple.d/input.foo
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
x
50 changes: 48 additions & 2 deletions docs/optscript.rst
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,8 @@ Related options

--list-fields

--_paramdef-<LANG>=<NAME>,<DESCRIPTION>

You can run optscript code fragments when pattern specified with
options matches successfully. The options are ``--regex-<LANG>``,
``--mline-regex-<LANG>``, and ``--_mtable-regex-<LANG>`` as you
Expand Down Expand Up @@ -269,12 +271,18 @@ represents the field has an operator for reading
(``:fieldname``). ``w`` represents the field has an operator for
writing (``fieldname:``).

``--_paramdef-<LANG>=<NAME>,<DESCRIPTION>`` defines a language specific
parameter named ``<NAME>``. ``--param-<LANG>.<NAME>=<VALUE>`` assigns
a value ``<VALUE>`` to the parameter. You can access the value from
Optscript code with ``_param`` operator. Don't use ``{`` character
in the description. The character is reserved for future extension.

Operators
............................

**.** -> ``-`` **.** ``corkIndex:int``

Push the cork index for the tag
Push the cork index for the tag.

**\\n** -> ``-`` **\\n** ``matchedString:string``

Expand Down Expand Up @@ -324,7 +332,45 @@ Data types
Recipes
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

TBW
Parameters
...........................................
With ``--_paramdef-<LANG>=<param>,<description>`` option, you can
define a parser-specific parameter to your optlib parser.

In the following example, we define a parser, ``Foo`` with a
parser-specific parameter ``VAR``. If the parser sees "x" in the
current input stream, a code fragment attached to the pattern "/(x)/"
runs. The code fragment does (1) check whether a value for ``VAR`` is
given, (2) emit a tag with the value given to parameter ``VAR`` as
name and with ``xval`` kind, and (3) remove the cork index from the
operand stack.

foo.ctags:
.. code-block::

--langdef=Foo
--map-Foo=.foo
--kinddef-Foo=v,xval,externally defined values
--_paramdef-Foo=VAR,desc
--regex-Foo=/(x)//{{
/VAR _param { % if VAR is defined ....
/xval _tag _commit pop
} if
% if VAR is not defined, we do nothing.
}}

input.foo:
.. code-block::

x

When running the parser, we can give a value ("hereiam" in the following example)
for the parameter ``VAR`` from the command line:

.. code-block:: console

$ ./ctags --options=args.ctags --param-Foo.VAR=hereiam -o - input.foo
hereiam input.foo /^x$/;" v

Difference between Optscript and PostScript
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Expand Down
46 changes: 46 additions & 0 deletions main/lregex.c
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,7 @@ struct lregexControlBlock {
struct guestRequest *guest_req;

EsObject *local_dict;
hashTable*param_dict;

ptrArray *hook[SCRIPT_HOOK_MAX];
ptrArray *hook_code[SCRIPT_HOOK_MAX];
Expand Down Expand Up @@ -341,6 +342,8 @@ extern struct lregexControlBlock* allocLregexControlBlock (parserDefinition *par
lcb->tstack = ptrArrayNew(NULL);
lcb->guest_req = guestRequestNew ();
lcb->local_dict = es_nil;
lcb->param_dict = hashTableNew (3, hashCstrhash, hashCstreq,
eFree, eFree);

for (int i = 0; i< SCRIPT_HOOK_MAX; i++)
{
Expand Down Expand Up @@ -373,6 +376,9 @@ extern void freeLregexControlBlock (struct lregexControlBlock* lcb)
es_object_unref (lcb->local_dict);
lcb->local_dict = es_nil;

hashTableDelete (lcb->param_dict);
lcb->param_dict = NULL;

for (int i = 0; i < SCRIPT_HOOK_MAX; i++)
{
ptrArrayDelete (lcb->hook[i]);
Expand Down Expand Up @@ -3157,6 +3163,13 @@ extern void addOptscriptToHook (struct lregexControlBlock *lcb, enum scriptHook
ptrArrayAdd (lcb->hook[hook], eStrdup (code));
}

extern void propagateParamToOptscript (struct lregexControlBlock *lcb, const char *param, const char *value)
{
Assert (param);
Assert (value);
hashTablePutItem (lcb->param_dict, eStrdup (param), eStrdup (value));
}

/* Return true if available. */
extern bool checkRegex (void)
{
Expand Down Expand Up @@ -4000,6 +4013,32 @@ static EsObject *lrop_makepromise (OptVM *vm, EsObject *name)
return es_false;
}

static EsObject *lrop_param (OptVM *vm, EsObject *name)
{
struct lregexControlBlock *lcb = opt_vm_get_app_data (vm);
EsObject *key = opt_vm_ostack_top (vm);
if (es_object_get_type (key) != OPT_TYPE_NAME)
return OPT_ERR_TYPECHECK;
EsObject *key_sym = es_pointer_get (key);
const char *keyc = es_symbol_get (key_sym);
const char *valuec = hashTableGetItem (lcb->param_dict, keyc);

if (valuec)
{
opt_vm_ostack_pop (vm);
EsObject *value = opt_string_new_from_cstr (valuec);
opt_vm_ostack_push (vm, value);
es_object_unref (value);
opt_vm_ostack_push (vm, es_true);
}
else
{
opt_vm_ostack_pop (vm);
opt_vm_ostack_push (vm, es_false);
}
return false;
}

static struct optscriptOperatorRegistration lropOperators [] = {
{
.name = "_matchstr",
Expand Down Expand Up @@ -4165,6 +4204,13 @@ static struct optscriptOperatorRegistration lropOperators [] = {
.help_str = "lang:string start:matchloc end:matchloc _MAKEPROMISE promise:int true%"
"lang:string start:matchloc end:matchloc _MAKEPROMISE false",
},
{
.name = "_param",
.fn = lrop_param,
.arity = 1,
.help_str = "param:name _PARAM value:string true%"
"param:name _PARAM false",
},
};

extern void initRegexOptscript (void)
Expand Down
1 change: 1 addition & 0 deletions main/lregex_p.h
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ extern void initRegexOptscript (void);
extern void listRegexOpscriptOperators (FILE *fp);

extern void addOptscriptToHook (struct lregexControlBlock *lcb, enum scriptHook hook, const char *code);
extern void propagateParamToOptscript (struct lregexControlBlock *lcb, const char *param, const char *value);

extern void printMultitableStatistics (struct lregexControlBlock *lcb);

Expand Down
4 changes: 4 additions & 0 deletions main/mini-geany.c
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,10 @@ static unsigned int ctagsGetLangCount(void)
void addIgnoreSymbol(const char *value)
{
langType lang = getNamedLanguage ("CPreProcessor", 0);
/*
* In the future, we will rename applyParameter to
* applyLanguageParam.
*/
applyParameter (lang, "ignore", value);
}

Expand Down
51 changes: 15 additions & 36 deletions main/options.c
Original file line number Diff line number Diff line change
Expand Up @@ -381,6 +381,8 @@ static optionDescription LongOptionDescription [] = {
{1,1," Copy patterns of a regex table to another regex table."},
{1,1," --_mtable-regex-<LANG>=<table>/<line_pattern>/<name_pattern>/[<flags>]"},
{1,1," Define multitable regular expression for locating tags in specific language."},
{1,1," --_paramdef-<LANG>=<name>,<description>"},
{1,1," Define new param for <LANG>."},
{1,1," --_prelude-<LANG>={{ optscript-code }}"},
{1,1," Specify code run before parsing with <LANG> parser."},
{1,1," --_pretend-<NEWLANG>=<OLDLANG>"},
Expand Down Expand Up @@ -1709,7 +1711,7 @@ static void processIf0Option (const char *const option,
langType lang = getNamedLanguage ("CPreProcessor", 0);
const char *arg = if0? "true": "false";

applyParameter (lang, "if0", arg);
applyLanguageParam (lang, "if0", arg);
}

static void processLanguageForceOption (
Expand Down Expand Up @@ -2018,31 +2020,6 @@ extern bool processMapOption (
return true;
}

extern bool processParamOption (
const char *const option, const char *const value)
{
langType language;
const char* name;
const char* sep;

language = getLanguageComponentInOption (option, "param-");
if (language == LANG_IGNORE)
return false;

sep = option + strlen ("param-") + strlen (getLanguageName (language));
/* `:' is only for keeping self compatibility */
if (! (*sep == '.' || *sep == ':' ))
error (FATAL, "no separator(.) is given for %s=%s", option, value);
name = sep + 1;

if (value == NULL || value [0] == '\0')
error (FATAL, "no value is given for %s", option);

applyParameter (language, name, value);

return true;
}

static void processLicenseOption (
const char *const option CTAGS_ATTR_UNUSED,
const char *const parameter CTAGS_ATTR_UNUSED)
Expand Down Expand Up @@ -2129,18 +2106,18 @@ static void processListParametersOption (const char *const option,
const char *const parameter)
{
if (parameter [0] == '\0' || strcasecmp (parameter, RSV_LANG_ALL) == 0)
printLanguageParameters (LANG_AUTO,
localOption.withListHeader, localOption.machinable,
stdout);
printLanguageParams (LANG_AUTO,
localOption.withListHeader, localOption.machinable,
stdout);
else
{
langType language = getNamedLanguage (parameter, 0);
if (language == LANG_IGNORE)
error (FATAL, "Unknown language \"%s\" in \"%s\" option", parameter, option);
else
printLanguageParameters (language,
localOption.withListHeader, localOption.machinable,
stdout);
printLanguageParams (language,
localOption.withListHeader, localOption.machinable,
stdout);
}
exit (0);
}
Expand Down Expand Up @@ -2595,7 +2572,7 @@ static void readIgnoreList (const char *const list)

while (token != NULL)
{
applyParameter (lang, "ignore", token);
applyLanguageParam (lang, "ignore", token);
token = strtok (NULL, IGNORE_SEPARATORS);
}
eFree (newList);
Expand All @@ -2615,7 +2592,7 @@ static void addIgnoreListFromFile (const char *const fileName)
for(i=0;i<c;i++)
{
vString * s = stringListItem(tokens,i);
applyParameter (lang, "ignore", vStringValue(s));
applyLanguageParam (lang, "ignore", vStringValue(s));
}

stringListDelete(tokens);
Expand All @@ -2626,7 +2603,7 @@ static void processIgnoreOption (const char *const list, int IgnoreOrDefine)
langType lang = getNamedLanguage ("CPreProcessor", 0);

if (IgnoreOrDefine == 'D')
applyParameter (lang, "define", list);
applyLanguageParam (lang, "define", list);
else if (strchr ("@./\\", list [0]) != NULL)
{
const char* fileName = (*list == '@') ? list + 1 : list;
Expand All @@ -2637,7 +2614,7 @@ static void processIgnoreOption (const char *const list, int IgnoreOrDefine)
addIgnoreListFromFile (list);
#endif
else if (strcmp (list, "-") == 0)
applyParameter (lang, "ignore", NULL);
applyLanguageParam (lang, "ignore", NULL);
else
readIgnoreList (list);
}
Expand Down Expand Up @@ -3352,6 +3329,8 @@ static void processLongOption (
;
else if (processMapOption (option, parameter))
;
else if (processParamdefOption (option, parameter))
;
else if (processParamOption (option, parameter))
;
else if (processTabledefOption (option, parameter))
Expand Down
1 change: 1 addition & 0 deletions main/options_p.h
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,7 @@ extern langType getLanguageComponentInOptionFull (const char *const option,

extern void processLanguageDefineOption (const char *const option, const char *const parameter);
extern bool processMapOption (const char *const option, const char *const parameter);
extern bool processParamdefOption (const char *const option, const char *const value);
extern bool processParamOption (const char *const option, const char *const value);
extern bool processKinddefOption (const char *const option, const char *const parameter);
extern bool processKindsOption (const char *const option, const char *const parameter);
Expand Down
Loading