From 2dd698bc69d8e9c2adc53435aa8988612cadce82 Mon Sep 17 00:00:00 2001 From: Masatake YAMATO Date: Sun, 11 May 2025 15:32:52 +0900 Subject: [PATCH 1/9] dsl: fix a typo in the help message for "=" Signed-off-by: Masatake YAMATO --- dsl/optscript.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dsl/optscript.c b/dsl/optscript.c index 2a8833d171..c684f6a3c4 100644 --- a/dsl/optscript.c +++ b/dsl/optscript.c @@ -472,7 +472,7 @@ opt_init (void) defOP (opt_system_dict, op__print_objdict_rec,"====", 1, "any === -"); defOP (opt_system_dict, op__print_objdict, "===", 1, "any === -"); defOP (opt_system_dict, op__print_object, "==", 1, "any == -"); - defOP (opt_system_dict, op__print, "=", 1, "any == -"); + defOP (opt_system_dict, op__print, "=", 1, "any = -"); defOP (opt_system_dict, op_mark, "<<", 0, "- << mark"); defOP (opt_system_dict, op_mark, "[", 0, "- [ mark"); From 721f4c44c2a6a46e094bce38ae0cfbc321ebaf3a Mon Sep 17 00:00:00 2001 From: Masatake YAMATO Date: Sun, 11 May 2025 15:38:02 +0900 Subject: [PATCH 2/9] dsl: add new operators for debugging =+ does the same as = but doesn't print newline at the end of output. ==+ does the same as == but doesn't print newline at the end of output. Signed-off-by: Masatake YAMATO --- .../error-undefined-if-if.expected | 2 +- Tmain/optscript.d/error-undefined-if.expected | 2 +- dsl/optscript.c | 19 +++++++++++++------ 3 files changed, 15 insertions(+), 8 deletions(-) diff --git a/Tmain/optscript.d/error-undefined-if-if.expected b/Tmain/optscript.d/error-undefined-if-if.expected index bd92d0202e..ab131c6bc9 100644 --- a/Tmain/optscript.d/error-undefined-if-if.expected +++ b/Tmain/optscript.d/error-undefined-if-if.expected @@ -4,4 +4,4 @@ top| |bottom Execution stack: top| a {a} --if-- {true {a} if} --if-- |bottom Dictionary stack: -top| -dict:1- -dict:89- |bottom +top| -dict:1- -dict:91- |bottom diff --git a/Tmain/optscript.d/error-undefined-if.expected b/Tmain/optscript.d/error-undefined-if.expected index daed401f05..39d74f529e 100644 --- a/Tmain/optscript.d/error-undefined-if.expected +++ b/Tmain/optscript.d/error-undefined-if.expected @@ -4,4 +4,4 @@ top| |bottom Execution stack: top| a {a} --if-- |bottom Dictionary stack: -top| -dict:1- -dict:89- |bottom +top| -dict:1- -dict:91- |bottom diff --git a/dsl/optscript.c b/dsl/optscript.c index c684f6a3c4..09113cd2e9 100644 --- a/dsl/optscript.c +++ b/dsl/optscript.c @@ -271,6 +271,8 @@ static EsObject* op__print_objdict_rec (OptVM *vm, EsObject *name); static EsObject* op__print_objdict (OptVM *vm, EsObject *name); static EsObject* op__print_object (OptVM *vm, EsObject *name); static EsObject* op__print (OptVM *vm, EsObject *name); +static EsObject* op__print_object_nonl (OptVM *vm, EsObject *name); +static EsObject* op__print_nonl (OptVM *vm, EsObject *name); static EsObject* op__make_array (OptVM *vm, EsObject *name); static EsObject* op__make_dict (OptVM *vm, EsObject *name); @@ -474,6 +476,9 @@ opt_init (void) defOP (opt_system_dict, op__print_object, "==", 1, "any == -"); defOP (opt_system_dict, op__print, "=", 1, "any = -"); + defOP (opt_system_dict, op__print_object_nonl,"==+", 1, "any ==+ -"); + defOP (opt_system_dict, op__print_nonl, "=+", 1, "any =+ -"); + defOP (opt_system_dict, op_mark, "<<", 0, "- << mark"); defOP (opt_system_dict, op_mark, "[", 0, "- [ mark"); defOP (opt_system_dict, op__make_array, "]", 0, "[ any1 ... anyn ] array"); @@ -2419,21 +2424,23 @@ mark_es_equal (const void *a, const void *b) /* * Operator implementations */ -#define GEN_PRINTER(NAME, BODY) \ +#define GEN_PRINTER(NAME, BODY,NL) \ static EsObject* \ NAME(OptVM *vm, EsObject *name) \ { \ EsObject * elt = ptrArrayRemoveLast (vm->ostack); \ BODY; \ - mio_putc (vm->out, '\n'); \ + if (NL) mio_putc (vm->out, '\n'); \ es_object_unref (elt); \ return es_false; \ } -GEN_PRINTER(op__print_objdict_rec, vm_print_full (vm, elt, false, 10)) -GEN_PRINTER(op__print_objdict, vm_print_full (vm, elt, false, 1)) -GEN_PRINTER(op__print_object, vm_print_full (vm, elt, false, 0)) -GEN_PRINTER(op__print, vm_print_full (vm, elt, true, 0)) +GEN_PRINTER(op__print_objdict_rec, vm_print_full (vm, elt, false, 10), true) +GEN_PRINTER(op__print_objdict, vm_print_full (vm, elt, false, 1), true) +GEN_PRINTER(op__print_object, vm_print_full (vm, elt, false, 0), true) +GEN_PRINTER(op__print, vm_print_full (vm, elt, true, 0), true) +GEN_PRINTER(op__print_object_nonl, vm_print_full (vm, elt, false, 0), false) +GEN_PRINTER(op__print_nonl, vm_print_full (vm, elt, true, 0), false) static EsObject* op__make_array (OptVM *vm, EsObject *name) From e8b8800f33195a7c2847f27816b8d852cfb03750 Mon Sep 17 00:00:00 2001 From: Masatake YAMATO Date: Sun, 11 May 2025 07:58:59 +0900 Subject: [PATCH 3/9] main/field,comment: revise the description of the value interpretation Signed-off-by: Masatake YAMATO --- main/field.h | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/main/field.h b/main/field.h index 6dc3021df9..a52027acc4 100644 --- a/main/field.h +++ b/main/field.h @@ -84,7 +84,7 @@ typedef enum eFieldDataType { * as a VALUE for the specified field. * * The VALUE is interpreted very differently depending on the output - * format: ctags, xref, and json. See field.h. + * format: ctags, xref, and json. * * For FIELDTYPE_STRING * -------------------- @@ -115,12 +115,11 @@ typedef enum eFieldDataType { * * For FIELDTYPE_STRING|FIELDTYPE_BOOL * ----------------------------------- - * If the value points "" (empty C string), the json writer prints it as - * false, and the xref writer prints it as -. - * THEREFORE, in the xref format, there is no way to distinguish the - * output for the value "" and "-". Both are printed as "-". - * If the value points a non-empty C string, Both json writer and xref - * writers print it as-is. + * If a field holds "" (empty C string), the json writer prints it as + * false, and the xref writer prints it as -. In the xref format, + * there is no way to distinguish the output for the value "" and + * "-". Both are printed as "-". If the value is a non-empty C + * string, Both json writer and xref writer print it as-is. * * Consider if you set "str" to the field "foo": * @@ -149,11 +148,11 @@ typedef enum eFieldDataType { * * For FIELDTYPE_BOOL * ------------------ - * Either VALUE points "" (empty C string) or a non-epmty C string, - * the json writer always prints true. In the same condition, the xref - * writer always prints the name of field. + * Whether a field holds "" (an empty C string) or a non-epmty C string, + * the json writer prints it as true. In the same condition, the xref + * writer prints the name of the field. * - * If a value is not set, the field is treated as holding false. + * If a value is not set, the field is treated as if it holds false. * The json writer prints nothing for the field holding false. * The xref writer prints - for the field holding false. @@ -184,9 +183,9 @@ typedef enum eFieldDataType { * * For FIELDTYPE_INTEGER * --------------------- - * If the value points "" (empty C string), the all writers print it as - * 0. If the value points a string which cannot be converted to an integer with - * strtol(3), the all writers print it as 1. + * If a field holds "" (an empty C string), the all writers print it as + * 0. If a field holds a string that strtol(3) cannot convert to an integer, + * all the writers print it as 1. * * Consider if you set "99" to the field "foo": * @@ -221,7 +220,7 @@ typedef enum eFieldDataType { * json | (nothing) * * - * The other data type and the combination of types are not implemented yet. + * The other data types and the combinations of types are not implemented yet. * */ From 1ccfb30ad846d41c60e31495e01bc3ed866e909c Mon Sep 17 00:00:00 2001 From: Masatake YAMATO Date: Tue, 16 May 2023 04:57:43 +0900 Subject: [PATCH 4/9] main/field: define operators accessing parser specific fields The name of operators has following form: setter => .: getter => :. The operators for a field are automatically defined only if the field has a setter and a getter in C language level; the operators require that the fieldDefinition for the field has getValueObject method setValueObject method. Currently, no parser has such methods. So, we cannot test the new code added with this commit yet. In later commits, I will implement the methods for fields defined with --_fielddef option. Signed-off-by: Masatake YAMATO --- main/field.c | 2 ++ main/lregex.c | 13 ++++++++++++ main/lregex_p.h | 3 +++ main/options.c | 1 + main/script.c | 56 ++++++++++++++++++++++++++++++++++++++++++------- main/script_p.h | 2 ++ 6 files changed, 70 insertions(+), 7 deletions(-) diff --git a/main/field.c b/main/field.c index 3d84ff5e1f..792d7a1816 100644 --- a/main/field.c +++ b/main/field.c @@ -1371,6 +1371,8 @@ extern int defineField (fieldDefinition *def, langType language) fobj->sibling = FIELD_UNKNOWN; updateSiblingField (def->ftype, def->name); + installOptscriptFieldAccessor (def->ftype); + return def->ftype; } diff --git a/main/lregex.c b/main/lregex.c index 2f5fd1b348..beea60db3c 100644 --- a/main/lregex.c +++ b/main/lregex.c @@ -4582,6 +4582,19 @@ static struct optscriptOperatorRegistration lropOperators [] = { }, }; +extern bool installOptscriptFieldAccessor (fieldType ftype) +{ + /* This function is called via defineField(). + defineField() is called via --fielddef option of built-in parsers + defining their specific fields. + built-in parsers are initialized lazily in the current implementation. + optvm is initialized earlier than parsers. */ + Assert (!es_null(lregex_dict)); + + optscriptInstallFieldAccessor (lregex_dict, ftype); + return true; +} + extern void initRegexOptscript (void) { if (!regexAvailable) diff --git a/main/lregex_p.h b/main/lregex_p.h index 15bd869c04..bfeb192a23 100644 --- a/main/lregex_p.h +++ b/main/lregex_p.h @@ -19,6 +19,7 @@ * INCLUDE FILES */ #include "general.h" +#include "field.h" #include "flags_p.h" #include "kind_p.h" #include "lregex.h" @@ -115,6 +116,8 @@ extern void extendRegexTable (struct lregexControlBlock *lcb, const char *src, c extern void initRegexOptscript (void); extern void listRegexOpscriptOperators (FILE *fp); +extern bool installOptscriptFieldAccessor (fieldType ftype); + extern void addOptscriptToHook (struct lregexControlBlock *lcb, enum scriptHook hook, const char *code); extern void propagateParamToOptscript (struct lregexControlBlock *lcb, const char *param, const char *value); diff --git a/main/options.c b/main/options.c index 1bfee7e287..5ba78faa9d 100644 --- a/main/options.c +++ b/main/options.c @@ -2322,6 +2322,7 @@ static void processListSubparsersOptions (const char *const option CTAGS_ATTR_UN static void processListOperators (const char *const option CTAGS_ATTR_UNUSED, const char *const parameter) { + initializeParser (LANG_AUTO); listRegexOpscriptOperators (stdout); exit (0); } diff --git a/main/script.c b/main/script.c index 5c81da8560..57d6d980fb 100644 --- a/main/script.c +++ b/main/script.c @@ -152,12 +152,22 @@ static EsObject* lrop_set_field_value (OptVM *vm, EsObject *name) return es_false; } -static void optscriptInstallFieldGetter (EsObject *dict, fieldType ftype, - vString *op_name, vString *op_desc) +static void optscriptInstallFieldGetterFast (EsObject *dict, fieldType ftype, + vString *op_name, vString *op_desc) { - const char *fname = getFieldName (ftype); vStringPut (op_name, ':'); + + langType lang = getFieldLanguage (ftype); + if (lang != LANG_IGNORE) + { + const char *lname = getLanguageName (lang); + vStringCatS (op_name, lname); + vStringPut (op_name, '.'); + } + + const char *fname = getFieldName (ftype); vStringCatS (op_name, fname); + EsObject *op_sym = es_symbol_intern (vStringValue (op_name)); es_symbol_set_data (op_sym, HT_INT_TO_PTR (ftype)); @@ -198,9 +208,17 @@ static void optscriptInstallFieldGetter (EsObject *dict, fieldType ftype, es_object_unref (op); } -static void optscriptInstallFieldSetter (EsObject *dict, fieldType ftype, - vString *op_name, vString *op_desc) +static void optscriptInstallFieldSetterFast (EsObject *dict, fieldType ftype, + vString *op_name, vString *op_desc) { + langType lang = getFieldLanguage (ftype); + if (lang != LANG_IGNORE) + { + const char *lname = getLanguageName (lang); + vStringCatS (op_name, lname); + vStringPut (op_name, '.'); + } + const char *fname = getFieldName (ftype); vStringCatS (op_name, fname); vStringPut (op_name, ':'); @@ -237,22 +255,46 @@ static void optscriptInstallFieldSetter (EsObject *dict, fieldType ftype, es_object_unref (op); } +extern void optscriptInstallFieldAccessor (EsObject *dict, fieldType ftype) +{ + vString *op_name = vStringNew (); + vString *op_desc = vStringNew (); + + if (hasFieldGetter (ftype)) + { + optscriptInstallFieldGetterFast (dict, ftype, op_name, op_desc); + vStringClear (op_name); + vStringClear (op_desc); + } + + if (hasFieldSetter (ftype)) + optscriptInstallFieldSetterFast (dict, ftype, op_name, op_desc); + + vStringDelete (op_name); + vStringDelete (op_desc); +} + static void optscriptInstallFieldAccessors (EsObject *dict) { vString *op_name = vStringNew (); vString *op_desc = vStringNew (); + /* In the current implementation, the upper boundary of the loop + can be "<= FIELD_BUILTIN_LAST" because the parser specific fields + are registered via defineField. However, when we change the order + and the way to initialize parsers, we may have to use "< countFields()" + instead. */ for (fieldType ftype = 0; ftype <= FIELD_BUILTIN_LAST; ftype++) { if (hasFieldGetter (ftype)) { - optscriptInstallFieldGetter (dict, ftype, op_name, op_desc); + optscriptInstallFieldGetterFast (dict, ftype, op_name, op_desc); vStringClear (op_name); vStringClear (op_desc); } if (hasFieldSetter (ftype)) { - optscriptInstallFieldSetter (dict, ftype, op_name, op_desc); + optscriptInstallFieldSetterFast (dict, ftype, op_name, op_desc); vStringClear (op_name); vStringClear (op_desc); } diff --git a/main/script_p.h b/main/script_p.h index 7e8852da53..7f144afe5f 100644 --- a/main/script_p.h +++ b/main/script_p.h @@ -13,6 +13,7 @@ #include "general.h" /* must always come first */ +#include "field.h" #include "optscript.h" #include "mio.h" @@ -32,6 +33,7 @@ extern EsObject *OPTSCRIPT_ERR_UNKNOWNEXTRA; extern OptVM *optscriptInit (void); extern void optscriptInstallProcs (EsObject *dict, OptOperatorFn matchResultAccessor); +extern void optscriptInstallFieldAccessor (EsObject *dict, fieldType ftype); extern void optscriptSetup (OptVM *vm, EsObject *dict, int corkIndex); extern void optscriptTeardown (OptVM *vm, EsObject *dict); From 09fee7657acf898e6b6fe2413f63069f0df7e4b2 Mon Sep 17 00:00:00 2001 From: Masatake YAMATO Date: Thu, 18 May 2023 10:17:51 +0900 Subject: [PATCH 5/9] main/field: implement the setter and getter for parser specific fields defined in an optlib parser Signed-off-by: Masatake YAMATO --- .../stdout-expected.txt | 8 +- .../list-fielddef-flags.d/stdout-expected.txt | 2 +- .../stdout-expected.txt | 6 +- Tmain/list-fields.d/stdout-expected.txt | 6 +- main/field.c | 81 ++++++++++- main/field.h | 133 +++++++++++++++--- main/lregex.c | 1 + main/parse.c | 25 ++-- main/script.c | 15 +- main/script_p.h | 1 + misc/optlib2c | 4 +- optlib/inko.c | 4 +- optlib/passwd.c | 8 +- 13 files changed, 245 insertions(+), 49 deletions(-) diff --git a/Tmain/flags-fielddef-datatype.d/stdout-expected.txt b/Tmain/flags-fielddef-datatype.d/stdout-expected.txt index 9bbd7f209c..c62077a2ad 100644 --- a/Tmain/flags-fielddef-datatype.d/stdout-expected.txt +++ b/Tmain/flags-fielddef-datatype.d/stdout-expected.txt @@ -1,6 +1,6 @@ #LETTER NAME ENABLED LANGUAGE JSTYPE FIXED OP DESCRIPTION -- boolfield no FIELDTEST --b no -- a field having boolean value +- boolfield no FIELDTEST --b no rw a field having boolean value - deffield no FIELDTEST s-- no -- a field that type is not specified -- intfield no FIELDTEST -i- no -- a field having integer value -- strboolfield no FIELDTEST s-b no -- a field having string value or false -- strfield no FIELDTEST s-- no -- a field having string value +- intfield no FIELDTEST -i- no rw a field having integer value +- strboolfield no FIELDTEST s-b no rw a field having string value or false +- strfield no FIELDTEST s-- no rw a field having string value diff --git a/Tmain/list-fielddef-flags.d/stdout-expected.txt b/Tmain/list-fielddef-flags.d/stdout-expected.txt index 64d73e8ccc..3049b06970 100644 --- a/Tmain/list-fielddef-flags.d/stdout-expected.txt +++ b/Tmain/list-fielddef-flags.d/stdout-expected.txt @@ -1,2 +1,2 @@ #LETTER NAME DESCRIPTION -- datatype=TYPE acceaptable datatype of the field ([str]|bool|int|str+bool) +- datatype=TYPE acceaptable datatype of the field (str|bool|int|str+bool) diff --git a/Tmain/list-fields-with-prefix.d/stdout-expected.txt b/Tmain/list-fields-with-prefix.d/stdout-expected.txt index 838c1d1be8..3ab59db55a 100644 --- a/Tmain/list-fields-with-prefix.d/stdout-expected.txt +++ b/Tmain/list-fields-with-prefix.d/stdout-expected.txt @@ -31,7 +31,7 @@ x UCTAGSxpath no NONE s-- no -- xpath for - UCTAGShowImported no Go s-- no -- how the package is imported ("inline" for `.' or "init" for `_') - UCTAGSpackage yes Go s-- no -- the real package specified by the package name - UCTAGSpackageName yes Go s-- no -- the name for referring the package -- UCTAGSimplements yes Inko s-- no -- Trait being implemented +- UCTAGSimplements yes Inko s-- no rw Trait being implemented - UCTAGSassignment yes LdScript s-- no -- how a value is assigned to the symbol - UCTAGSdefiner yes Lisp s-- no -- the name of the function or macro that defines the unknown/Y-kind object - UCTAGSsectionMarker no Markdown s-- no -- character used for declaring section(#, ##, =, or -) @@ -39,8 +39,8 @@ x UCTAGSxpath no NONE s-- no -- xpath for - UCTAGSlangid yes NSIS s-- no -- language identifier specified in (License)LangString commands - UCTAGScategory yes ObjectiveC s-- no -- category attached to the class - UCTAGSprotocols yes ObjectiveC s-- no -- protocols that the class (or category) confirms to -- UCTAGShome yes Passwd s-- no -- home directory -- UCTAGSshell yes Passwd s-- no -- login shell +- UCTAGShome yes Passwd s-- no rw home directory +- UCTAGSshell yes Passwd s-- no rw login shell - UCTAGSdecorators no Python s-- no -- decorators on functions and classes - UCTAGSnameref yes Python s-- no -- the original name for the tag - UCTAGSassignmentop no R s-- no -- operator for assignment diff --git a/Tmain/list-fields.d/stdout-expected.txt b/Tmain/list-fields.d/stdout-expected.txt index fb4587a956..38ff743e27 100644 --- a/Tmain/list-fields.d/stdout-expected.txt +++ b/Tmain/list-fields.d/stdout-expected.txt @@ -49,7 +49,7 @@ z kind no NONE s-- no r- [tags output] prepend "kind:" to k/ (or K/) field outpu - howImported no Go s-- no -- how the package is imported ("inline" for `.' or "init" for `_') - package yes Go s-- no -- the real package specified by the package name - packageName yes Go s-- no -- the name for referring the package -- implements yes Inko s-- no -- Trait being implemented +- implements yes Inko s-- no rw Trait being implemented - assignment yes LdScript s-- no -- how a value is assigned to the symbol - definer yes Lisp s-- no -- the name of the function or macro that defines the unknown/Y-kind object - sectionMarker no Markdown s-- no -- character used for declaring section(#, ##, =, or -) @@ -57,8 +57,8 @@ z kind no NONE s-- no r- [tags output] prepend "kind:" to k/ (or K/) field outpu - langid yes NSIS s-- no -- language identifier specified in (License)LangString commands - category yes ObjectiveC s-- no -- category attached to the class - protocols yes ObjectiveC s-- no -- protocols that the class (or category) confirms to -- home yes Passwd s-- no -- home directory -- shell yes Passwd s-- no -- login shell +- home yes Passwd s-- no rw home directory +- shell yes Passwd s-- no rw login shell - decorators no Python s-- no -- decorators on functions and classes - nameref yes Python s-- no -- the original name for the tag - assignmentop no R s-- no -- operator for assignment diff --git a/main/field.c b/main/field.c index 792d7a1816..10dac4802e 100644 --- a/main/field.c +++ b/main/field.c @@ -1316,7 +1316,7 @@ static const char* defaultRenderer (const tagEntryInfo *const tag CTAGS_ATTR_UNU return renderEscapedString (value, tag, buffer); } -static bool isValueAvailableGeneric (const tagEntryInfo *const e, const fieldDefinition *fdef) +extern bool isValueAvailableGeneric (const tagEntryInfo *const e, const fieldDefinition *fdef) { return getParserFieldValueForType(e, fdef->ftype)? true: false; } @@ -1925,3 +1925,82 @@ static EsObject* setFieldValueForInherits (tagEntryInfo *tag, const fieldDefinit return es_false; } + +extern EsObject* getFieldValueGeneric (const tagEntryInfo *tag, const fieldDefinition *fdef) +{ + const char *value = getParserFieldValueForType(tag, fdef->ftype); + unsigned int dt = fdef->dataType; + + if (dt & FIELDTYPE_STRING) + { + if (value == NULL) + return es_nil; + return (dt & FIELDTYPE_BOOL && value[0] == '\0') + ? es_false + : opt_string_new_from_cstr (value); + } + else if (dt & FIELDTYPE_INTEGER) + { + long tmp; + + if (value == NULL) + return es_nil; + else if (value[0] == '\0') + tmp = 0; + else if (!strToLong (value, 10, &tmp)) + tmp = 1; + + return es_integer_new ((int)tmp); + } + else if (dt & FIELDTYPE_BOOL) + return value? es_true: es_nil; + else + { + AssertNotReached (); + return es_nil; + } +} + +extern EsObject* setFieldValueGeneric (tagEntryInfo *tag, const fieldDefinition *fdef, const EsObject *obj) +{ + unsigned int dt = fdef->dataType; + const char * val; + char buf[1 /* [+-] */ + 20 + 1 /* for \0 */]; + + if (dt & FIELDTYPE_STRING) + { + if (es_object_get_type (obj) == OPT_TYPE_STRING) + val = opt_string_get_cstr (obj); + else if ((dt & FIELDTYPE_BOOL) && es_object_equal (es_false, obj)) + val = ""; + else + return OPT_ERR_TYPECHECK; + } + else if (dt & FIELDTYPE_INTEGER) + { + int tmp = es_integer_get (obj); + /* 2^64 => "18446744073709551616" */ + snprintf(buf, sizeof(buf), "%d", tmp); + val = buf; + } + else if (dt & FIELDTYPE_BOOL) + { + if (es_boolean_get (obj)) + val = ""; + else + { + if (doesFieldHaveValue(fdef->ftype, tag)) + return OPTSCRIPT_ERR_FIELDRESET; + val = NULL; + } + } + else + { + val = ""; + AssertNotReached (); + } + + if (val) + attachParserField (tag, fdef->ftype, val); + return es_false; +} diff --git a/main/field.h b/main/field.h index a52027acc4..d6cbcf5790 100644 --- a/main/field.h +++ b/main/field.h @@ -77,6 +77,17 @@ typedef enum eFieldDataType { /* used in --list-fields */ FIELDTYPE_END_MARKER = 1 << 3, + + /* If you want to allow a field to be accessed from code + * written in optscript, append FIELDTYPE_SCRIPTABLE to + * dataType member of the field's fieldDefinition. + * + * For the field defined in optlib, set {datatype=TYPE} flag to + * --_fielddef-=... option. Just specifying a type is + * enough; FIELDTYPE_SCRIPTABLE is automatically append to the + * filed definition. If you don't set the flag explicitly, + * FIELDTYPE_SCRIPTABLE is not appended. */ + FIELDTYPE_SCRIPTABLE = FIELDTYPE_END_MARKER, } fieldDataType; /* Interpretation of VALUE of field * @@ -87,34 +98,57 @@ typedef enum eFieldDataType { * format: ctags, xref, and json. * * For FIELDTYPE_STRING - * -------------------- + * ===================================================================== + * + * output and getter + * --------------------------------------------------------------------- + * * Consider if you set "str" to the field "foo": * * WRITER | OUTPUT - * -------+----------- + * -------+------------- * ctags | foo:str * xref | str * json | "foo": "str" + * -------+------------- + * :foo | (foo) => (foo) true * * Consider if you set "" to the field "foo": * * WRITER | OUTPUT - * -------+----------- + * -------+------------- * ctags | foo: * xref | (nothing) * json | "foo": "" + * -------+------------- + * :foo | () => () true * * Consider if you don't set the field "foo": * * WRITER | OUTPUT - * -------+----------- + * -------+------------- * ctags | (nothing) * xref | (nothing) * json | (nothing) + * -------+------------- + * :foo | null => false + * + * setter + * --------------------------------------------------------------------- + * + * stack | C sting stored to the field + * ----------+---------------------------- + * . (str) | "str" + * . () | "" + * . object | ERROR:typecheck * * * For FIELDTYPE_STRING|FIELDTYPE_BOOL - * ----------------------------------- + * ===================================================================== + * + * output and getter + * --------------------------------------------------------------------- + * * If a field holds "" (empty C string), the json writer prints it as * false, and the xref writer prints it as -. In the xref format, * there is no way to distinguish the output for the value "" and @@ -124,30 +158,51 @@ typedef enum eFieldDataType { * Consider if you set "str" to the field "foo": * * WRITER | OUTPUT - * -------+----------- + * -------+------------- * ctags | foo:str * xref | str * json | "foo": "str" + * -------+------------- + * :foo | (str) => (str) true * * Consider if you set "" to the field "foo": * * WRITER | OUTPUT - * -------+----------- + * -------+------------- * ctags | foo: * xref | - (as specified as FIELD_NULL_LETTER_CHAR/FIELD_NULL_LETTER_STRING) * json | "foo": false + * -------+------------- + * :foo | false => false true * * Consider if you don't set the field "foo": * * WRITER | OUTPUT - * -------+----------- + * -------+------------- * ctags | (nothing) * xref | (nothing) * json | (nothing) + * -------+------------- + * :foo | null => false + * + * setter + * --------------------------------------------------------------------- + * + * stack | C sting stored to the field + * ----------+---------------------------- + * . (str) | "str" + * . () | "" + * . false | "" + * . true | ERROR:typecheck + * . object | ERROR:typecheck * * * For FIELDTYPE_BOOL - * ------------------ + * ===================================================================== + * + * output and getter + * --------------------------------------------------------------------- + * * Whether a field holds "" (an empty C string) or a non-epmty C string, * the json writer prints it as true. In the same condition, the xref * writer prints the name of the field. @@ -159,30 +214,51 @@ typedef enum eFieldDataType { * Consider if you set "str" to the field "foo": * * WRITER | OUTPUT - * -------+----------- + * -------+------------- * ctags | foo: * xref | foo * json | "foo": true + * -------+------------- + * :foo | true => true true * * Consider if you set "" to the field "foo": * * WRITER | OUTPUT - * -------+----------- + * -------+------------- * ctags | foo: * xref | foo * json | "foo": true + * -------+------------- + * :foo | true => true true * * Consider if you don't set the field "foo": * * WRITER | OUTPUT - * -------+----------- + * -------+------------- * ctags | (nothing) * xref | - (as specified as FIELD_NULL_LETTER_CHAR/FIELD_NULL_LETTER_STRING) * json | (nothing) + * -------+------------- + * :foo | null => false + * + * setter + * --------------------------------------------------------------------- + * + * stack | C sting stored to the field + * ----------+---------------------------- + * . false | do nothing if the field was not set. + * | ERROR:fieldreset if the field was already set. + * | This is a limit of current implementation. + * . true | "" + * . object | ERROR:typecheck * * * For FIELDTYPE_INTEGER - * --------------------- + * ===================================================================== + * + * output and getter + * --------------------------------------------------------------------- + * * If a field holds "" (an empty C string), the all writers print it as * 0. If a field holds a string that strtol(3) cannot convert to an integer, * all the writers print it as 1. @@ -190,26 +266,32 @@ typedef enum eFieldDataType { * Consider if you set "99" to the field "foo": * * WRITER | OUTPUT - * -------+----------- + * -------+------------- * ctags | foo:99 * xref | 99 * json | "foo": 99 - * + * -------+------------- + * :foo | 99 => 99 true + * Consider if you set "str" to the field "foo": * * WRITER | OUTPUT - * -------+----------- + * -------+------------- * ctags | foo:1 * xref | 1 * json | "foo": 1 - * + * -------+------------- + * :foo | 1 => 1 true + * Consider if you set "" to the field "foo": * * WRITER | OUTPUT - * -------+----------- + * -------+------------- * ctags | foo:0 * xref | 0 * json | "foo": 0 + * -------+------------- + * :foo | 0 => 0 true * * Consider if you don't set the field "foo": * @@ -218,6 +300,17 @@ typedef enum eFieldDataType { * ctags | (nothing) * xref | (nothing) * json | (nothing) + * -------+------------- + * :foo | null => false + * + * setter + * --------------------------------------------------------------------- + * + * stack | C sting stored to the field + * ----------+---------------------------- + * . int | int + * . 1 | "1" (as an example) + * . object | ERROR:typecheck * * * The other data types and the combinations of types are not implemented yet. @@ -264,4 +357,8 @@ struct sFieldDefinition { extern bool isFieldEnabled (fieldType type); +extern bool isValueAvailableGeneric (const tagEntryInfo *const tag, const fieldDefinition *fdef); +extern struct _EsObject* getFieldValueGeneric (const tagEntryInfo *tag, const fieldDefinition *fdef); +extern struct _EsObject* setFieldValueGeneric (tagEntryInfo *tag, const fieldDefinition *fdef, const struct _EsObject *obj); + #endif /* CTAGS_MAIN_FIELD_H */ diff --git a/main/lregex.c b/main/lregex.c index beea60db3c..46109163cf 100644 --- a/main/lregex.c +++ b/main/lregex.c @@ -4614,6 +4614,7 @@ extern void initRegexOptscript (void) OPTSCRIPT_ERR_UNKNOWNLANGUAGE = es_error_intern ("unknownlanguage"); OPTSCRIPT_ERR_UNKNOWNKIND = es_error_intern ("unknownkind"); OPTSCRIPT_ERR_UNKNOWNROLE = es_error_intern ("unknownrole"); + OPTSCRIPT_ERR_FIELDRESET = es_error_intern ("fieldreset"); optscriptInstallProcs (lregex_dict, lrop_get_match_string_named_group); diff --git a/main/parse.c b/main/parse.c index 014850efed..2df2a84c39 100644 --- a/main/parse.c +++ b/main/parse.c @@ -4032,7 +4032,7 @@ static void field_def_flag_datatype_long (const char *const optflag CTAGS_ATTR_U if (*param == '\0') error (FATAL, "no datatype given for field: \"%s\"", fdef->name); - fdef->dataType = 0; + fdef->dataType = FIELDTYPE_SCRIPTABLE; if (strcmp (param, "int") == 0) fdef->dataType |= FIELDTYPE_INTEGER; else if (strcmp (param, "str") == 0) @@ -4047,7 +4047,7 @@ static void field_def_flag_datatype_long (const char *const optflag CTAGS_ATTR_U static flagDefinition FieldDefFlagDef [] = { { '\0', "datatype", NULL, field_def_flag_datatype_long, - "TYPE", "acceaptable datatype of the field ([str]|bool|int|str+bool)" }, + "TYPE", "acceaptable datatype of the field (str|bool|int|str+bool)" }, }; static bool processLangDefineField (const langType language, @@ -4090,17 +4090,26 @@ static bool processLangDefineField (const langType language, fdef->letter = NUL_FIELD_LETTER; fdef->name = eStrndup(parameter, name_end - parameter); fdef->description = desc; - fdef->isValueAvailable = NULL; - fdef->getValueObject = NULL; - fdef->getterValueType = NULL; - fdef->setValueObject = NULL; - fdef->setterValueType = NULL; - fdef->checkValueForSetter = NULL; + fdef->dataType = 0; if (flags) flagsEval (flags, FieldDefFlagDef, ARRAY_SIZE (FieldDefFlagDef), fdef); if (!fdef->dataType) fdef->dataType = FIELDTYPE_STRING; + + fdef->isValueAvailable = (fdef->dataType & FIELDTYPE_SCRIPTABLE) + ? isValueAvailableGeneric + : NULL; + fdef->getValueObject = (fdef->dataType & FIELDTYPE_SCRIPTABLE) + ? getFieldValueGeneric + : NULL; + fdef->getterValueType = NULL; + fdef->setValueObject = (fdef->dataType & FIELDTYPE_SCRIPTABLE) + ? setFieldValueGeneric + : NULL; + fdef->setterValueType = NULL; + + fdef->checkValueForSetter = NULL; fdef->ftype = FIELD_UNKNOWN; DEFAULT_TRASH_BOX(fdef, fieldDefinitionDestroy); diff --git a/main/script.c b/main/script.c index 57d6d980fb..c0f5afe130 100644 --- a/main/script.c +++ b/main/script.c @@ -25,6 +25,7 @@ EsObject *OPTSCRIPT_ERR_NOTAGENTRY; EsObject *OPTSCRIPT_ERR_UNKNOWNLANGUAGE; +EsObject *OPTSCRIPT_ERR_FIELDRESET; int OPT_TYPE_MATCHLOC; static int locEqual (const void *a, const void *b); @@ -134,13 +135,13 @@ static EsObject* lrop_set_field_value (OptVM *vm, EsObject *name) if (!es_object_equal (e, es_false)) return e; } - else - { - if (! (((fdata_type & FIELDTYPE_STRING) && (valtype == OPT_TYPE_STRING)) - || ((fdata_type & FIELDTYPE_BOOL) && (valtype == ES_TYPE_BOOLEAN)) - || ((fdata_type & FIELDTYPE_INTEGER) && (valtype == ES_TYPE_INTEGER)))) - return OPT_ERR_TYPECHECK; - } + else if ((fdata_type & FIELDTYPE_STRING) && (fdata_type & FIELDTYPE_BOOL) + && ((valtype == OPT_TYPE_STRING) || (valtype == ES_TYPE_BOOLEAN))) + ; /* Accept; do nothing */ + else if (! (((fdata_type & FIELDTYPE_STRING) && (valtype == OPT_TYPE_STRING)) + || ((fdata_type & FIELDTYPE_BOOL) && (valtype == ES_TYPE_BOOLEAN)) + || ((fdata_type & FIELDTYPE_INTEGER) && (valtype == ES_TYPE_INTEGER)))) + return OPT_ERR_TYPECHECK; EsObject *r = setFieldValue (ftype, e, valobj); if (es_error_p (r)) diff --git a/main/script_p.h b/main/script_p.h index 7f144afe5f..08899af49f 100644 --- a/main/script_p.h +++ b/main/script_p.h @@ -29,6 +29,7 @@ extern void optscriptRegisterOperators(EsObject * dict, extern EsObject *OPTSCRIPT_ERR_NOTAGENTRY; extern EsObject *OPTSCRIPT_ERR_UNKNOWNLANGUAGE; extern EsObject *OPTSCRIPT_ERR_UNKNOWNEXTRA; +extern EsObject *OPTSCRIPT_ERR_FIELDRESET; extern OptVM *optscriptInit (void); diff --git a/misc/optlib2c b/misc/optlib2c index 42179edf3d..71a09d0843 100755 --- a/misc/optlib2c +++ b/misc/optlib2c @@ -61,7 +61,7 @@ my $langdef_flags = my $fielddef_flags = [ [ qr/\{datatype=([^\}]+)\}/, sub { - my $datatype = ""; + my $datatype = "FIELDTYPE_SCRIPTABLE|"; if ($1 eq 'str') { @@ -1104,6 +1104,8 @@ EOF if (defined $_->{'datatype'}) { print <{'datatype'}, + .getValueObject = getFieldValueGeneric, + .setValueObject = setFieldValueGeneric, EOF } print < Date: Fri, 24 Jan 2025 05:45:34 +0900 Subject: [PATCH 6/9] optlib2c: set .isValueAvailable explicitly Signed-off-by: Masatake YAMATO --- misc/optlib2c | 1 + optlib/inko.c | 1 + optlib/passwd.c | 2 ++ 3 files changed, 4 insertions(+) diff --git a/misc/optlib2c b/misc/optlib2c index 71a09d0843..0e19fd244c 100755 --- a/misc/optlib2c +++ b/misc/optlib2c @@ -1104,6 +1104,7 @@ EOF if (defined $_->{'datatype'}) { print <{'datatype'}, + .isValueAvailable = isValueAvailableGeneric, .getValueObject = getFieldValueGeneric, .setValueObject = setFieldValueGeneric, EOF diff --git a/optlib/inko.c b/optlib/inko.c index c505c2731e..f05373678f 100644 --- a/optlib/inko.c +++ b/optlib/inko.c @@ -179,6 +179,7 @@ extern parserDefinition* InkoParser (void) .name = "implements", .description = "Trait being implemented", .dataType = FIELDTYPE_SCRIPTABLE|FIELDTYPE_STRING, + .isValueAvailable = isValueAvailableGeneric, .getValueObject = getFieldValueGeneric, .setValueObject = setFieldValueGeneric, }, diff --git a/optlib/passwd.c b/optlib/passwd.c index 1bdfcce34e..53a9f0975c 100644 --- a/optlib/passwd.c +++ b/optlib/passwd.c @@ -38,6 +38,7 @@ extern parserDefinition* PasswdParser (void) .name = "home", .description = "home directory", .dataType = FIELDTYPE_SCRIPTABLE|FIELDTYPE_STRING, + .isValueAvailable = isValueAvailableGeneric, .getValueObject = getFieldValueGeneric, .setValueObject = setFieldValueGeneric, }, @@ -46,6 +47,7 @@ extern parserDefinition* PasswdParser (void) .name = "shell", .description = "login shell", .dataType = FIELDTYPE_SCRIPTABLE|FIELDTYPE_STRING, + .isValueAvailable = isValueAvailableGeneric, .getValueObject = getFieldValueGeneric, .setValueObject = setFieldValueGeneric, }, From fa84ccca2b40a23e3c3d476f77871631884b8e0b Mon Sep 17 00:00:00 2001 From: Masatake YAMATO Date: Sun, 11 May 2025 09:38:02 +0900 Subject: [PATCH 7/9] main/field,comment: add descripions to the members of sFieldDefinition Signed-off-by: Masatake YAMATO --- main/field.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/main/field.h b/main/field.h index d6cbcf5790..bcf523a4e2 100644 --- a/main/field.h +++ b/main/field.h @@ -336,16 +336,16 @@ struct sFieldDefinition { bool (* isValueAvailable) (const tagEntryInfo *const, const fieldDefinition *); - const char * getterValueType; + const char * getterValueType; /* used in --_list-operators */ struct _EsObject * (* getValueObject) (const tagEntryInfo *, const fieldDefinition *); - const char * setterValueType; + const char * setterValueType; /* used in --_list-operators */ /* Return es_false if passed value is acceptable. Return an error object is unacceptable. */ struct _EsObject * (* checkValueForSetter) (const fieldDefinition *, const struct _EsObject *); struct _EsObject * (* setValueObject) (tagEntryInfo *, const fieldDefinition *, const struct _EsObject *); - fieldDataType dataType; /* used in json output */ + fieldDataType dataType; /* used in json output. See OP column in --list-fields. */ unsigned int ftype; /* Given from the main part */ }; From 20d81684c8565133af78d73c13501a422f5b8c06 Mon Sep 17 00:00:00 2001 From: Masatake YAMATO Date: Fri, 3 Jan 2025 00:31:11 +0900 Subject: [PATCH 8/9] Tmain: add cases for testing parser specific fields with data types defined in optlib Signed-off-by: Masatake YAMATO --- .../input.unknownx | 10 + .../knownz.ctags | 12 ++ .../run.sh | 19 ++ .../stderr-expected.txt | 1 + .../stdout-expected.txt | 12 ++ .../unknownx.ctags | 41 ++++ .../input.unknownx | 13 +- .../knownz.ctags | 13 +- .../run.sh | 11 +- .../stderr-expected.txt | 19 ++ .../stdout-expected.txt | 33 +++- .../unknownx.ctags | 66 ++++++- .../exit-expected.txt | 1 + .../input.testlang | 31 ++++ .../run.sh | 28 +++ .../stderr-expected.txt | 28 +++ .../stdout-expected.txt | 118 ++++++++++++ .../testlang.ctags | 175 ++++++++++++++++++ 18 files changed, 625 insertions(+), 6 deletions(-) create mode 100644 Tmain/parser-specific-fields-for-foreign-lang-in-json.d/input.unknownx create mode 100644 Tmain/parser-specific-fields-for-foreign-lang-in-json.d/knownz.ctags create mode 100644 Tmain/parser-specific-fields-for-foreign-lang-in-json.d/run.sh create mode 100644 Tmain/parser-specific-fields-for-foreign-lang-in-json.d/stderr-expected.txt create mode 100644 Tmain/parser-specific-fields-for-foreign-lang-in-json.d/stdout-expected.txt create mode 100644 Tmain/parser-specific-fields-for-foreign-lang-in-json.d/unknownx.ctags create mode 100644 Tmain/parser-specific-fields-with-scripts.d/exit-expected.txt create mode 100644 Tmain/parser-specific-fields-with-scripts.d/input.testlang create mode 100755 Tmain/parser-specific-fields-with-scripts.d/run.sh create mode 100644 Tmain/parser-specific-fields-with-scripts.d/stderr-expected.txt create mode 100644 Tmain/parser-specific-fields-with-scripts.d/stdout-expected.txt create mode 100644 Tmain/parser-specific-fields-with-scripts.d/testlang.ctags diff --git a/Tmain/parser-specific-fields-for-foreign-lang-in-json.d/input.unknownx b/Tmain/parser-specific-fields-for-foreign-lang-in-json.d/input.unknownx new file mode 100644 index 0000000000..f6510db7d6 --- /dev/null +++ b/Tmain/parser-specific-fields-for-foreign-lang-in-json.d/input.unknownx @@ -0,0 +1,10 @@ +public func foo(n, m); +protected func bar(n); +private func baz(n,...); +STR:strset@iamowner +STR:setsetempty@ +STR:notset +Y:iamowner2=tagme2 +Z:tagme-z@iamowner-z +eset:a +enoset:b diff --git a/Tmain/parser-specific-fields-for-foreign-lang-in-json.d/knownz.ctags b/Tmain/parser-specific-fields-for-foreign-lang-in-json.d/knownz.ctags new file mode 100644 index 0000000000..92799bce41 --- /dev/null +++ b/Tmain/parser-specific-fields-for-foreign-lang-in-json.d/knownz.ctags @@ -0,0 +1,12 @@ +--langdef=knownz +--kinddef-knownz=m,mark,makers + +--_fielddef-knownz=owner,the owner of the markers{datatype=str} + +--_fielddef-knownz=len,the length of owner string{datatype=int} +--fields-knownz=+{len} +--_fielddef-knownz=lenplus,the length of owner string + 1{datatype=int} +--fields-knownz=+{lenplus} + +--_fielddef-knownz=exported,whether the marker is exported or not{datatype=bool} +--fields-knownz=+{exported} diff --git a/Tmain/parser-specific-fields-for-foreign-lang-in-json.d/run.sh b/Tmain/parser-specific-fields-for-foreign-lang-in-json.d/run.sh new file mode 100644 index 0000000000..72756253fb --- /dev/null +++ b/Tmain/parser-specific-fields-for-foreign-lang-in-json.d/run.sh @@ -0,0 +1,19 @@ +# Copyright: 2025 Masatake YAMATO +# License: GPL-2 + +. ../utils.sh + +CTAGS=$1 + +V= +# V=valgrind + +is_feature_available "${CTAGS}" json + +echo "# output: json" +${V} ${CTAGS} --options=NONE --options=./knownz.ctags --sort=no --options=./unknownx.ctags \ + --fields=+l \ + --fields-unknownx=+'{protection}{signature}' \ + --fields-knownz=+'{owner}' \ + --output-format=json \ + -o - input.unknownx diff --git a/Tmain/parser-specific-fields-for-foreign-lang-in-json.d/stderr-expected.txt b/Tmain/parser-specific-fields-for-foreign-lang-in-json.d/stderr-expected.txt new file mode 100644 index 0000000000..fd87c9c6da --- /dev/null +++ b/Tmain/parser-specific-fields-for-foreign-lang-in-json.d/stderr-expected.txt @@ -0,0 +1 @@ +ctags: Notice: No options will be read from files or environment diff --git a/Tmain/parser-specific-fields-for-foreign-lang-in-json.d/stdout-expected.txt b/Tmain/parser-specific-fields-for-foreign-lang-in-json.d/stdout-expected.txt new file mode 100644 index 0000000000..5046b29aaa --- /dev/null +++ b/Tmain/parser-specific-fields-for-foreign-lang-in-json.d/stdout-expected.txt @@ -0,0 +1,12 @@ +# output: json +{"_type": "tag", "name": "foo", "path": "input.unknownx", "pattern": "/^public func foo(n, m);$/", "language": "unknownx", "kind": "func", "protection": "public ", "signature": "(n, m)"} +{"_type": "tag", "name": "bar", "path": "input.unknownx", "pattern": "/^protected func bar(n);$/", "language": "unknownx", "kind": "func", "protection": "protected ", "signature": "(n)"} +{"_type": "tag", "name": "baz", "path": "input.unknownx", "pattern": "/^private func baz(n,...);$/", "language": "unknownx", "kind": "func", "protection": "private ", "signature": "(n,...)"} +{"_type": "tag", "name": "strset", "path": "input.unknownx", "pattern": "/^STR:strset@iamowner$/", "language": "knownz", "kind": "mark", "owner": "iamowner"} +{"_type": "tag", "name": "setsetempty", "path": "input.unknownx", "pattern": "/^STR:setsetempty@$/", "language": "knownz", "kind": "mark", "owner": ""} +{"_type": "tag", "name": "notset", "path": "input.unknownx", "pattern": "/^STR:notset$/", "language": "knownz", "kind": "mark"} +{"_type": "tag", "name": "tagme2", "path": "input.unknownx", "pattern": "/^Y:iamowner2=tagme2$/", "language": "knownz", "kind": "mark", "owner": "iamowner2"} +{"_type": "tag", "name": "tagme-z", "path": "input.unknownx", "pattern": "/^Z:tagme-z@iamowner-z$/", "language": "knownz", "kind": "mark", "owner": "iamowner-z", "len": 10, "lenplus": 11} +{"_type": "tag", "name": "a", "path": "input.unknownx", "pattern": "/^eset:a$/", "language": "knownz", "kind": "mark", "exported": true} +{"_type": "tag", "name": "b", "path": "input.unknownx", "pattern": "/^enoset:b$/", "language": "knownz", "kind": "mark"} +{"_type": "tag", "name": "9_exported", "path": "input.unknownx", "pattern": "/^enoset:b$/", "language": "knownz", "kind": "mark"} diff --git a/Tmain/parser-specific-fields-for-foreign-lang-in-json.d/unknownx.ctags b/Tmain/parser-specific-fields-for-foreign-lang-in-json.d/unknownx.ctags new file mode 100644 index 0000000000..dcc647137a --- /dev/null +++ b/Tmain/parser-specific-fields-for-foreign-lang-in-json.d/unknownx.ctags @@ -0,0 +1,41 @@ +--langdef=unknownx{_foreignLanguage=knownz} +--kinddef-unknownx=f,func,functions +--map-unknownx=+.unknownx + +--_fielddef-unknownx=protection,protections +--_fielddef-unknownx=signature,signatures + +--_prelude-unknownx={{ + /exported false def +}} + +--regex-unknownx=/^((public|protected|private) +)?func ([^\(]+)\((.*)\)/\3/f/{_field=protection:\1}{_field=signature:(\4)} +--regex-unknownx=/^STR:([a-z]+)@([a-z]+)/\1/m/{_language=knownz}{_field=owner:\2} +--regex-unknownx=/^STR:([a-z]+)@$/\1/m/{_language=knownz}{_field=owner:} +--regex-unknownx=/^STR:([a-z]+)$/\1/m/{_language=knownz} +--regex-unknownx=/^Y:([a-z0-9]+)=([a-z0-9]+)/\2/m/{_field=owner:\1}{_language=knownz} +--regex-unknownx=/^Z:([-a-z]+)@([-a-z]+)/\1/m/{_language=knownz}{{ + . \2 knownz.owner: + . :knownz.owner { + . exch length knownz.len: + } if + . :knownz.len { + 1 add + . exch knownz.lenplus: + } if +}} + +--regex-unknownx=/^eset:([-a-z]+)/\1/m/{_language=knownz}{{ + /exported . def + . true knownz.exported: +}} + +--regex-unknownx=/^enoset:([-a-z]+)/\1/m/{_language=knownz}{{ + . false knownz.exported: + exported :knownz.exported and { + mark exported 0 string cvs (_exported) _buildstring + /knownz + /mark + 1@ _foreigntag _commit pop + } if +}} diff --git a/Tmain/parser-specific-fields-for-foreign-lang.d/input.unknownx b/Tmain/parser-specific-fields-for-foreign-lang.d/input.unknownx index 8ce5984bbc..a84cd763af 100644 --- a/Tmain/parser-specific-fields-for-foreign-lang.d/input.unknownx +++ b/Tmain/parser-specific-fields-for-foreign-lang.d/input.unknownx @@ -1,5 +1,16 @@ public func foo(n, m); protected func bar(n); private func baz(n,...); -X:tagme@iamowner +STR:strset@iamowner +STR:setsetempty@ +STR:notset Y:iamowner2=tagme2 +Z:tagme-z@iamowner-z +eset:a +enoset:b + +stb:o +stb:p- +stb:q.something string +x0:O +x1:P diff --git a/Tmain/parser-specific-fields-for-foreign-lang.d/knownz.ctags b/Tmain/parser-specific-fields-for-foreign-lang.d/knownz.ctags index bf91c87100..cc23b60b87 100644 --- a/Tmain/parser-specific-fields-for-foreign-lang.d/knownz.ctags +++ b/Tmain/parser-specific-fields-for-foreign-lang.d/knownz.ctags @@ -1,4 +1,15 @@ --langdef=knownz --kinddef-knownz=m,mark,makers ---_fielddef-knownz=owner,the owner of the markers +--_fielddef-knownz=owner,the owner of the markers{datatype=str} + +--_fielddef-knownz=len,the length of owner string{datatype=int} +--fields-knownz=+{len} +--_fielddef-knownz=lenplus,the length of owner string + 1{datatype=int} +--fields-knownz=+{lenplus} + +--_fielddef-knownz=exported,whether the marker is exported or not{datatype=bool} +--fields-knownz=+{exported} + +--_fielddef-knownz=stb,string or false{datatype=str+bool} +--fields-knownz=+{stb} diff --git a/Tmain/parser-specific-fields-for-foreign-lang.d/run.sh b/Tmain/parser-specific-fields-for-foreign-lang.d/run.sh index 9abae09deb..765464235d 100644 --- a/Tmain/parser-specific-fields-for-foreign-lang.d/run.sh +++ b/Tmain/parser-specific-fields-for-foreign-lang.d/run.sh @@ -8,8 +8,17 @@ CTAGS=$1 V= # V=valgrind -${V} ${CTAGS} --options=NONE --options=./knownz.ctags --options=./unknownx.ctags \ +echo "# output: tags" +${V} ${CTAGS} --options=NONE --options=./knownz.ctags --sort=no --options=./unknownx.ctags \ --fields=+l \ --fields-unknownx=+'{protection}{signature}' \ --fields-knownz=+'{owner}' \ -o - input.unknownx + +echo "# output: xref" +${V} ${CTAGS} --options=NONE --options=./knownz.ctags --sort=no --options=./unknownx.ctags \ + --fields=+l \ + --fields-unknownx=+'{protection}{signature}' \ + --fields-knownz=+'{owner}' \ + -x --_xformat="%N %l / owner:%{knownz.owner},len:%{knownz.len},lenplus:%{knownz.lenplus},exported:%{knownz.exported},stb:%{knownz.stb} / %{unknownx.protection}%{unknownx.signature}" \ + -o - input.unknownx diff --git a/Tmain/parser-specific-fields-for-foreign-lang.d/stderr-expected.txt b/Tmain/parser-specific-fields-for-foreign-lang.d/stderr-expected.txt index fd87c9c6da..2bcdb8cd4d 100644 --- a/Tmain/parser-specific-fields-for-foreign-lang.d/stderr-expected.txt +++ b/Tmain/parser-specific-fields-for-foreign-lang.d/stderr-expected.txt @@ -1 +1,20 @@ ctags: Notice: No options will be read from files or environment +/not-set +false +(something string) +# Setting a string to a bool field +true +true +# Setting a string to a int field +true +1 +ctags: Notice: No options will be read from files or environment +/not-set +false +(something string) +# Setting a string to a bool field +true +true +# Setting a string to a int field +true +1 diff --git a/Tmain/parser-specific-fields-for-foreign-lang.d/stdout-expected.txt b/Tmain/parser-specific-fields-for-foreign-lang.d/stdout-expected.txt index 690da2ad7a..98999bcb6e 100644 --- a/Tmain/parser-specific-fields-for-foreign-lang.d/stdout-expected.txt +++ b/Tmain/parser-specific-fields-for-foreign-lang.d/stdout-expected.txt @@ -1,5 +1,34 @@ +# output: tags +foo input.unknownx /^public func foo(n, m);$/;" f language:unknownx protection:public signature:(n, m) bar input.unknownx /^protected func bar(n);$/;" f language:unknownx protection:protected signature:(n) baz input.unknownx /^private func baz(n,...);$/;" f language:unknownx protection:private signature:(n,...) -foo input.unknownx /^public func foo(n, m);$/;" f language:unknownx protection:public signature:(n, m) -tagme input.unknownx /^X:tagme@iamowner$/;" m language:knownz owner:iamowner +strset input.unknownx /^STR:strset@iamowner$/;" m language:knownz owner:iamowner +setsetempty input.unknownx /^STR:setsetempty@$/;" m language:knownz owner: +notset input.unknownx /^STR:notset$/;" m language:knownz tagme2 input.unknownx /^Y:iamowner2=tagme2$/;" m language:knownz owner:iamowner2 +tagme-z input.unknownx /^Z:tagme-z@iamowner-z$/;" m language:knownz owner:iamowner-z len:10 lenplus:11 +a input.unknownx /^eset:a$/;" m language:knownz exported: +b input.unknownx /^enoset:b$/;" m language:knownz +9_exported input.unknownx /^enoset:b$/;" m language:knownz +o input.unknownx /^stb:o$/;" m language:knownz +p input.unknownx /^stb:p-$/;" m language:knownz stb: +q input.unknownx /^stb:q.something string$/;" m language:knownz stb:something string +O input.unknownx /^x0:O$/;" m language:knownz exported: +P input.unknownx /^x1:P$/;" m language:knownz len:1 +# output: xref +foo unknownx / owner:,len:,lenplus:,exported:-,stb: / public (n, m) +bar unknownx / owner:,len:,lenplus:,exported:-,stb: / protected (n) +baz unknownx / owner:,len:,lenplus:,exported:-,stb: / private (n,...) +strset knownz / owner:iamowner,len:,lenplus:,exported:-,stb: / +setsetempty knownz / owner:,len:,lenplus:,exported:-,stb: / +notset knownz / owner:,len:,lenplus:,exported:-,stb: / +tagme2 knownz / owner:iamowner2,len:,lenplus:,exported:-,stb: / +tagme-z knownz / owner:iamowner-z,len:10,lenplus:11,exported:-,stb: / +a knownz / owner:,len:,lenplus:,exported:exported,stb: / +b knownz / owner:,len:,lenplus:,exported:-,stb: / +9_exported knownz / owner:,len:,lenplus:,exported:-,stb: / +o knownz / owner:,len:,lenplus:,exported:-,stb: / +p knownz / owner:,len:,lenplus:,exported:-,stb:- / +q knownz / owner:,len:,lenplus:,exported:-,stb:something string / +O knownz / owner:,len:,lenplus:,exported:exported,stb: / +P knownz / owner:,len:1,lenplus:,exported:-,stb: / diff --git a/Tmain/parser-specific-fields-for-foreign-lang.d/unknownx.ctags b/Tmain/parser-specific-fields-for-foreign-lang.d/unknownx.ctags index 523a670b34..367fae6fc3 100644 --- a/Tmain/parser-specific-fields-for-foreign-lang.d/unknownx.ctags +++ b/Tmain/parser-specific-fields-for-foreign-lang.d/unknownx.ctags @@ -5,6 +5,70 @@ --_fielddef-unknownx=protection,protections --_fielddef-unknownx=signature,signatures +--_prelude-unknownx={{ + /exported false def +}} + --regex-unknownx=/^((public|protected|private) +)?func ([^\(]+)\((.*)\)/\3/f/{_field=protection:\1}{_field=signature:(\4)} ---regex-unknownx=/^X:([a-z]+)@([a-z]+)/\1/m/{_language=knownz}{_field=owner:\2} +--regex-unknownx=/^STR:([a-z]+)@([a-z]+)/\1/m/{_language=knownz}{_field=owner:\2} +--regex-unknownx=/^STR:([a-z]+)@$/\1/m/{_language=knownz}{_field=owner:} +--regex-unknownx=/^STR:([a-z]+)$/\1/m/{_language=knownz} --regex-unknownx=/^Y:([a-z0-9]+)=([a-z0-9]+)/\2/m/{_field=owner:\1}{_language=knownz} +--regex-unknownx=/^Z:([-a-z]+)@([-a-z]+)/\1/m/{_language=knownz}{{ + . \2 knownz.owner: + . :knownz.owner { + . exch length knownz.len: + } if + . :knownz.len { + 1 add + . exch knownz.lenplus: + } if +}} + +--regex-unknownx=/^eset:([-a-z]+)/\1/m/{_language=knownz}{{ + /exported . def + . true knownz.exported: +}} + +--regex-unknownx=/^enoset:([-a-z]+)/\1/m/{_language=knownz}{{ + . false knownz.exported: + exported :knownz.exported and { + mark exported 0 string cvs (_exported) _buildstring + /knownz + /mark + 1@ _foreigntag _commit pop + } if +}} + +--regex-unknownx=/^stb:([a-z])$/\1/m/{_language=knownz}{{ + . :knownz.stb { + == + } { + /not-set == + } ifelse +}} +--regex-unknownx=/^stb:([a-z])-$/\1/m/{_language=knownz}{_field=stb:}{{ + . :knownz.stb { + == + } { + /not-set == + } ifelse +}} +--regex-unknownx=/^stb:([a-z])\.(.*)$/\1/m/{_language=knownz}{_field=stb:\2}{{ + . :knownz.stb { + == + } { + /not-set == + } ifelse +}} + +--regex-unknownx=/^x0:([a-zA-Z])$/\1/m/{_language=knownz}{_field=exported:alpha}{{ + (# Setting a string to a bool field) = + . :knownz.exported pstack clear +}} + +# Setting string to a int field +--regex-unknownx=/^x1:([a-zA-Z])$/\1/m/{_language=knownz}{_field=len:alpha}{{ + (# Setting a string to a int field) = + . :knownz.len pstack clear +}} diff --git a/Tmain/parser-specific-fields-with-scripts.d/exit-expected.txt b/Tmain/parser-specific-fields-with-scripts.d/exit-expected.txt new file mode 100644 index 0000000000..573541ac97 --- /dev/null +++ b/Tmain/parser-specific-fields-with-scripts.d/exit-expected.txt @@ -0,0 +1 @@ +0 diff --git a/Tmain/parser-specific-fields-with-scripts.d/input.testlang b/Tmain/parser-specific-fields-with-scripts.d/input.testlang new file mode 100644 index 0000000000..8e40f000e3 --- /dev/null +++ b/Tmain/parser-specific-fields-with-scripts.d/input.testlang @@ -0,0 +1,31 @@ +string => string +string => integer +string => bool +string => strbool +int => string +int => integer +int => bool +int => strbool +true => string +true => integer +true => bool +true => strbool +false => string +false => integer +false => bool +false => strbool +array => string +array => integer +array => bool +array => strbool + +empty string => string +empty string => integer +empty string => bool +empty string => strbool + +int => +bool => +strbool => + +true => bool, false => true diff --git a/Tmain/parser-specific-fields-with-scripts.d/run.sh b/Tmain/parser-specific-fields-with-scripts.d/run.sh new file mode 100755 index 0000000000..d7e1df369c --- /dev/null +++ b/Tmain/parser-specific-fields-with-scripts.d/run.sh @@ -0,0 +1,28 @@ +# Copyright: 2025 Masatake YAMATO +# License: GPL-2 + +CTAGS="$1" +CMDLINE="$CTAGS --quiet --options=NONE --options=./testlang.ctags" + +. ../utils.sh + +is_feature_available "$1" json + +echo '### ctags' && +${CMDLINE} \ + --param-Testlang.dp=true \ + -o - input.testlang && + +echo '### xref' && +${CMDLINE} \ + --_xformat="%-16N :: str:%{Testlang.str} int:%{Testlang.int} bool:%{Testlang.bool} strbool:%{Testlang.strbool}" \ + -x input.testlang && + +echo '### json' && +${CMDLINE} \ + --output-format=json -o - input.testlang && + +echo '### etags' && +${CMDLINE} \ + --output-format=etags -o - input.testlang && +: diff --git a/Tmain/parser-specific-fields-with-scripts.d/stderr-expected.txt b/Tmain/parser-specific-fields-with-scripts.d/stderr-expected.txt new file mode 100644 index 0000000000..a11b07828a --- /dev/null +++ b/Tmain/parser-specific-fields-with-scripts.d/stderr-expected.txt @@ -0,0 +1,28 @@ +string => string...OK stringtype/(str) +string => integer...XERR typecheck +string => bool...XERR typecheck +string => strbool...OK stringtype/(str) +int => string...XERR typecheck +int => integer...OK integertype/17 +int => bool...XERR typecheck +int => strbool...XERR typecheck +true => string...XERR typecheck +true => integer...XERR typecheck +true => bool...OK booleantype/true +true => strbool...XERR typecheck +false => string...XERR typecheck +false => integer...XERR typecheck +false => bool...OK /noval +false => strbool...OK booleantype/false +array => string...XERR typecheck +array => integer...XERR typecheck +array => bool...XERR typecheck +array => strbool...XERR typecheck +empty string => string...OK stringtype/() +empty string => integer...XERR typecheck +empty string => bool...XERR typecheck +empty string => strbool...OK booleantype/false +int =>...OK /noval +bool =>...OK /noval +strbool =>...OK /noval +true => bool, false => true...XERR fieldreset diff --git a/Tmain/parser-specific-fields-with-scripts.d/stdout-expected.txt b/Tmain/parser-specific-fields-with-scripts.d/stdout-expected.txt new file mode 100644 index 0000000000..be86b3f1d5 --- /dev/null +++ b/Tmain/parser-specific-fields-with-scripts.d/stdout-expected.txt @@ -0,0 +1,118 @@ +### ctags +string => string input.testlang /^string => string$/;" o str:str +string => integer input.testlang /^string => integer$/;" o +string => bool input.testlang /^string => bool$/;" o +string => strbool input.testlang /^string => strbool$/;" o strbool:str +int => string input.testlang /^int => string$/;" o +int => integer input.testlang /^int => integer$/;" o int:17 +int => bool input.testlang /^int => bool$/;" o +int => strbool input.testlang /^int => strbool$/;" o +true => string input.testlang /^true => string$/;" o +true => integer input.testlang /^true => integer$/;" o +true => bool input.testlang /^true => bool$/;" o bool: +true => strbool input.testlang /^true => strbool$/;" o +false => string input.testlang /^false => string$/;" o +false => integer input.testlang /^false => integer$/;" o +false => bool input.testlang /^false => bool$/;" o +false => strbool input.testlang /^false => strbool$/;" o strbool: +array => string input.testlang /^array => string$/;" o +array => integer input.testlang /^array => integer$/;" o +array => bool input.testlang /^array => bool$/;" o +array => strbool input.testlang /^array => strbool$/;" o +empty string => string input.testlang /^empty string => string$/;" o str: +empty string => integer input.testlang /^empty string => integer$/;" o +empty string => bool input.testlang /^empty string => bool$/;" o +empty string => strbool input.testlang /^empty string => strbool$/;" o strbool: +int => input.testlang /^int =>$/;" o +bool => input.testlang /^bool =>$/;" o +strbool => input.testlang /^strbool =>$/;" o +true => bool, false => true input.testlang /^true => bool, false => true$/;" o bool: +### xref +string => string :: str:str int: bool:- strbool: +string => integer :: str: int: bool:- strbool: +string => bool :: str: int: bool:- strbool: +string => strbool :: str: int: bool:- strbool:str +int => string :: str: int: bool:- strbool: +int => integer :: str: int:17 bool:- strbool: +int => bool :: str: int: bool:- strbool: +int => strbool :: str: int: bool:- strbool: +true => string :: str: int: bool:- strbool: +true => integer :: str: int: bool:- strbool: +true => bool :: str: int: bool:bool strbool: +true => strbool :: str: int: bool:- strbool: +false => string :: str: int: bool:- strbool: +false => integer :: str: int: bool:- strbool: +false => bool :: str: int: bool:- strbool: +false => strbool :: str: int: bool:- strbool:- +array => string :: str: int: bool:- strbool: +array => integer :: str: int: bool:- strbool: +array => bool :: str: int: bool:- strbool: +array => strbool :: str: int: bool:- strbool: +empty string => string :: str: int: bool:- strbool: +empty string => integer :: str: int: bool:- strbool: +empty string => bool :: str: int: bool:- strbool: +empty string => strbool :: str: int: bool:- strbool:- +int => :: str: int: bool:- strbool: +bool => :: str: int: bool:- strbool: +strbool => :: str: int: bool:- strbool: +true => bool, false => true :: str: int: bool:bool strbool: +### json +{"_type": "tag", "name": "string => string", "path": "input.testlang", "pattern": "/^string => string$/", "kind": "object", "str": "str"} +{"_type": "tag", "name": "string => integer", "path": "input.testlang", "pattern": "/^string => integer$/", "kind": "object"} +{"_type": "tag", "name": "string => bool", "path": "input.testlang", "pattern": "/^string => bool$/", "kind": "object"} +{"_type": "tag", "name": "string => strbool", "path": "input.testlang", "pattern": "/^string => strbool$/", "kind": "object", "strbool": "str"} +{"_type": "tag", "name": "int => string", "path": "input.testlang", "pattern": "/^int => string$/", "kind": "object"} +{"_type": "tag", "name": "int => integer", "path": "input.testlang", "pattern": "/^int => integer$/", "kind": "object", "int": 17} +{"_type": "tag", "name": "int => bool", "path": "input.testlang", "pattern": "/^int => bool$/", "kind": "object"} +{"_type": "tag", "name": "int => strbool", "path": "input.testlang", "pattern": "/^int => strbool$/", "kind": "object"} +{"_type": "tag", "name": "true => string", "path": "input.testlang", "pattern": "/^true => string$/", "kind": "object"} +{"_type": "tag", "name": "true => integer", "path": "input.testlang", "pattern": "/^true => integer$/", "kind": "object"} +{"_type": "tag", "name": "true => bool", "path": "input.testlang", "pattern": "/^true => bool$/", "kind": "object", "bool": true} +{"_type": "tag", "name": "true => strbool", "path": "input.testlang", "pattern": "/^true => strbool$/", "kind": "object"} +{"_type": "tag", "name": "false => string", "path": "input.testlang", "pattern": "/^false => string$/", "kind": "object"} +{"_type": "tag", "name": "false => integer", "path": "input.testlang", "pattern": "/^false => integer$/", "kind": "object"} +{"_type": "tag", "name": "false => bool", "path": "input.testlang", "pattern": "/^false => bool$/", "kind": "object"} +{"_type": "tag", "name": "false => strbool", "path": "input.testlang", "pattern": "/^false => strbool$/", "kind": "object", "strbool": false} +{"_type": "tag", "name": "array => string", "path": "input.testlang", "pattern": "/^array => string$/", "kind": "object"} +{"_type": "tag", "name": "array => integer", "path": "input.testlang", "pattern": "/^array => integer$/", "kind": "object"} +{"_type": "tag", "name": "array => bool", "path": "input.testlang", "pattern": "/^array => bool$/", "kind": "object"} +{"_type": "tag", "name": "array => strbool", "path": "input.testlang", "pattern": "/^array => strbool$/", "kind": "object"} +{"_type": "tag", "name": "empty string => string", "path": "input.testlang", "pattern": "/^empty string => string$/", "kind": "object", "str": ""} +{"_type": "tag", "name": "empty string => integer", "path": "input.testlang", "pattern": "/^empty string => integer$/", "kind": "object"} +{"_type": "tag", "name": "empty string => bool", "path": "input.testlang", "pattern": "/^empty string => bool$/", "kind": "object"} +{"_type": "tag", "name": "empty string => strbool", "path": "input.testlang", "pattern": "/^empty string => strbool$/", "kind": "object", "strbool": false} +{"_type": "tag", "name": "int =>", "path": "input.testlang", "pattern": "/^int =>$/", "kind": "object"} +{"_type": "tag", "name": "bool =>", "path": "input.testlang", "pattern": "/^bool =>$/", "kind": "object"} +{"_type": "tag", "name": "strbool =>", "path": "input.testlang", "pattern": "/^strbool =>$/", "kind": "object"} +{"_type": "tag", "name": "true => bool, false => true", "path": "input.testlang", "pattern": "/^true => bool, false => true$/", "kind": "object", "bool": true} +### etags + +input.testlang,1095 +string => stringstring => string1,0 +string => integerstring => integer2,17 +string => boolstring => bool3,35 +string => strboolstring => strbool4,50 +int => stringint => string5,68 +int => integerint => integer6,82 +int => boolint => bool7,97 +int => strboolint => strbool8,109 +true => stringtrue => string9,124 +true => integertrue => integer10,139 +true => booltrue => bool11,155 +true => strbooltrue => strbool12,168 +false => stringfalse => string13,184 +false => integerfalse => integer14,200 +false => boolfalse => bool15,217 +false => strboolfalse => strbool16,231 +array => stringarray => string17,248 +array => integerarray => integer18,264 +array => boolarray => bool19,281 +array => strboolarray => strbool20,295 +empty string => stringempty string => string22,313 +empty string => integerempty string => integer23,336 +empty string => boolempty string => bool24,360 +empty string => strboolempty string => strbool25,381 +int =>int =>27,406 +bool =>bool =>28,413 +strbool =>strbool =>29,421 +true => bool, false => truetrue => bool, false => true31,433 diff --git a/Tmain/parser-specific-fields-with-scripts.d/testlang.ctags b/Tmain/parser-specific-fields-with-scripts.d/testlang.ctags new file mode 100644 index 0000000000..3a11c7e641 --- /dev/null +++ b/Tmain/parser-specific-fields-with-scripts.d/testlang.ctags @@ -0,0 +1,175 @@ +--sort=no + +--langdef=Testlang +--map-Testlang=+.testlang + +--_paramdef-Testlang=dp,enable debug printing + +--kinddef-Testlang=o,object,objects + +--_fielddef-Testlang=str,String{datatype=str} +--fields-Testlang=+{str} +--_fielddef-Testlang=int,Integer{datatype=int} +--fields-Testlang=+{int} +--_fielddef-Testlang=bool,Boolean{datatype=bool} +--fields-Testlang=+{bool} +--_fielddef-Testlang=strbool,String or Boolean{datatype=str+bool} +--fields-Testlang=+{strbool} + +--_prelude-Testlang={{ + /dp _param { + pop + /q {=} def + /qq {==} def + /qa {=+} def + /qqa {==+} def + } { + /q {pop} def + /qq {pop} def + /qa {pop} def + /qqa {pop} def + } ifelse + + /T { mark \1 (...) _buildstring qa } def + /pval { + dup type qqa (/) qa qq + } def + /Tstr { T . exch { Testlang.str: } + stopped { clear (XERR ) qa _errorname q } + { (OK ) qa . :Testlang.str {pval} {/noval qq} ifelse} ifelse + } def + /Tint { T . exch { Testlang.int: } + stopped { clear (XERR ) qa _errorname q } + { (OK ) qa . :Testlang.int {pval} {/noval qq} ifelse } ifelse + } def + /Tbool { T . exch { Testlang.bool: } + stopped { clear (XERR ) qa _errorname q } + { (OK ) qa . :Testlang.bool {pval} {/noval qq} ifelse } ifelse + } def + /Tstrbool { T . exch { Testlang.strbool: } + stopped { clear (XERR ) qa _errorname q } + { (OK ) qa . :Testlang.strbool {pval} {/noval qq} ifelse } ifelse + } def + /verifygetter { + stopped { clear (XERR ) qa _errorname q } + { (OK ) qa {pval} {/noval qq} ifelse } ifelse + } def +}} + +--regex-Testlang=/^(string => string)$/\1/o/{{ + (str) Tstr +}} + +--regex-Testlang=/^(string => integer)$/\1/o/{{ + (str) Tint +}} + +--regex-Testlang=/^(string => bool)$/\1/o/{{ + (str) Tbool +}} + +--regex-Testlang=/^(string => strbool)$/\1/o/{{ + (str) Tstrbool +}} + +--regex-Testlang=/^(int => string)$/\1/o/{{ + 17 Tstr +}} + +--regex-Testlang=/^(int => integer)$/\1/o/{{ + 17 Tint +}} + +--regex-Testlang=/^(int => bool)$/\1/o/{{ + 17 Tbool +}} + +--regex-Testlang=/^(int => strbool)$/\1/o/{{ + 17 Tstrbool +}} + +--regex-Testlang=/^(true => string)$/\1/o/{{ + true Tstr +}} + +--regex-Testlang=/^(true => integer)$/\1/o/{{ + true Tint +}} + +--regex-Testlang=/^(true => bool)$/\1/o/{{ + true Tbool +}} + +--regex-Testlang=/^(true => strbool)$/\1/o/{{ + true Tstrbool +}} + +--regex-Testlang=/^(false => string)$/\1/o/{{ + false Tstr +}} + +--regex-Testlang=/^(false => integer)$/\1/o/{{ + false Tint +}} + +--regex-Testlang=/^(false => bool)$/\1/o/{{ + false Tbool +}} + +--regex-Testlang=/^(false => strbool)$/\1/o/{{ + false Tstrbool +}} + +--regex-Testlang=/^(array => string)$/\1/o/{{ + [ 1 2 3 ] Tstr +}} + +--regex-Testlang=/^(array => integer)$/\1/o/{{ + [ 1 2 3 ] Tint +}} + +--regex-Testlang=/^(array => bool)$/\1/o/{{ + [ 1 2 3 ] Tbool +}} + +--regex-Testlang=/^(array => strbool)$/\1/o/{{ + [ 1 2 3 ] Tstrbool +}} + +--regex-Testlang=/^(empty string => string)$/\1/o/{{ + () Tstr +}} + +--regex-Testlang=/^(empty string => integer)$/\1/o/{{ + () Tint +}} + +--regex-Testlang=/^(empty string => bool)$/\1/o/{{ + () Tbool +}} + +--regex-Testlang=/^(empty string => strbool)$/\1/o/{{ + () Tstrbool +}} + +--regex-Testlang=/^(string =>)$/\1/o/{{ + { T . :Testlang.str } verifygetter +}} + +--regex-Testlang=/^(int =>)$/\1/o/{{ + { T . :Testlang.int } verifygetter +}} + +--regex-Testlang=/^(bool =>)$/\1/o/{{ + { T . :Testlang.bool } verifygetter +}} + +--regex-Testlang=/^(strbool =>)$/\1/o/{{ + { T . :Testlang.strbool } verifygetter +}} + +--regex-Testlang=/^(true => bool, false => true)$/\1/o/{{ + T + . true Testlang.bool: + { . false Testlang.bool: } stopped { clear (XERR ) qa _errorname q } if +}} \ No newline at end of file From d87078d2072e08714191d18e12bb0846a178a743 Mon Sep 17 00:00:00 2001 From: Masatake YAMATO Date: Fri, 3 Jan 2025 02:12:27 +0900 Subject: [PATCH 9/9] SCSS: add module parser-specific field Signed-off-by: Masatake YAMATO --- .../stdout-expected.txt | 1 + Tmain/list-fields.d/stdout-expected.txt | 1 + Units/parser-scss.r/use.d/expected.tags | 8 ++++---- docs/man/ctags-lang-scss.7.rst | 1 + man/ctags-lang-scss.7.rst.in | 1 + optlib/scss.c | 19 ++++++++++++++++--- optlib/scss.ctags | 9 ++++++--- 7 files changed, 30 insertions(+), 10 deletions(-) diff --git a/Tmain/list-fields-with-prefix.d/stdout-expected.txt b/Tmain/list-fields-with-prefix.d/stdout-expected.txt index 3ab59db55a..1d953ac929 100644 --- a/Tmain/list-fields-with-prefix.d/stdout-expected.txt +++ b/Tmain/list-fields-with-prefix.d/stdout-expected.txt @@ -48,6 +48,7 @@ x UCTAGSxpath no NONE s-- no -- xpath for - UCTAGSoverline no ReStructuredText --b no -- whether using overline & underline for declaring section - UCTAGSsectionMarker no ReStructuredText s-- no -- character used for declaring section - UCTAGSmixin yes Ruby s-- no -- how the class or module is mixed in (mixin:HOW:MODULE) +- UCTAGSmodule yes SCSS s-- no rw the name of module behind the namespace - UCTAGSdefiner yes Scheme s-- no -- the name of the function or macro that defines the unknown/Y-kind object - UCTAGSparameter no SystemVerilog --b no -- parameter whose value can be overridden. - UCTAGStarget yes Thrift s-- no -- the target language specified at "namespace" diff --git a/Tmain/list-fields.d/stdout-expected.txt b/Tmain/list-fields.d/stdout-expected.txt index 38ff743e27..04d1c45cf6 100644 --- a/Tmain/list-fields.d/stdout-expected.txt +++ b/Tmain/list-fields.d/stdout-expected.txt @@ -66,6 +66,7 @@ z kind no NONE s-- no r- [tags output] prepend "kind:" to k/ (or K/) field outpu - overline no ReStructuredText --b no -- whether using overline & underline for declaring section - sectionMarker no ReStructuredText s-- no -- character used for declaring section - mixin yes Ruby s-- no -- how the class or module is mixed in (mixin:HOW:MODULE) +- module yes SCSS s-- no rw the name of module behind the namespace - definer yes Scheme s-- no -- the name of the function or macro that defines the unknown/Y-kind object - parameter no SystemVerilog --b no -- parameter whose value can be overridden. - target yes Thrift s-- no -- the target language specified at "namespace" diff --git a/Units/parser-scss.r/use.d/expected.tags b/Units/parser-scss.r/use.d/expected.tags index 4c1167c5ea..67d61746c6 100644 --- a/Units/parser-scss.r/use.d/expected.tags +++ b/Units/parser-scss.r/use.d/expected.tags @@ -1,10 +1,10 @@ X/y input.scss /^@use "X\/y";$/;" M roles:used -y input.scss /^@use "X\/y";$/;" n roles:def +y input.scss /^@use "X\/y";$/;" n roles:def module:X/y Z input.scss /^@use "Z";$/;" M roles:used -Z input.scss /^@use "Z";$/;" n roles:def +Z input.scss /^@use "Z";$/;" n roles:def module:Z A input.scss /^@use "A" as NS;$/;" M roles:used -NS input.scss /^@use "A" as NS;$/;" n roles:def +NS input.scss /^@use "A" as NS;$/;" n roles:def module:A B/ input.scss /^@use "B\/";$/;" M roles:used C/d/e input.scss /^@use 'C\/d\/e';$/;" M roles:used -e input.scss /^@use 'C\/d\/e';$/;" n roles:def +e input.scss /^@use 'C\/d\/e';$/;" n roles:def module:C/d/e P/q input.scss /^@use 'P\/q' as *;$/;" M roles:used diff --git a/docs/man/ctags-lang-scss.7.rst b/docs/man/ctags-lang-scss.7.rst index a415409764..9eb0940823 100644 --- a/docs/man/ctags-lang-scss.7.rst +++ b/docs/man/ctags-lang-scss.7.rst @@ -28,6 +28,7 @@ Change since "0.0" * New kind ``module`` and new role ``used`` of the ``module`` kind * New kind ``namespace`` +* New field ``module`` SEE ALSO -------- diff --git a/man/ctags-lang-scss.7.rst.in b/man/ctags-lang-scss.7.rst.in index 7c446ef9b9..62232bd12f 100644 --- a/man/ctags-lang-scss.7.rst.in +++ b/man/ctags-lang-scss.7.rst.in @@ -28,6 +28,7 @@ Change since "0.0" * New kind ``module`` and new role ``used`` of the ``module`` kind * New kind ``namespace`` +* New field ``module`` SEE ALSO -------- diff --git a/optlib/scss.c b/optlib/scss.c index 113d3a79e8..75f2b32ea3 100644 --- a/optlib/scss.c +++ b/optlib/scss.c @@ -63,18 +63,18 @@ static void initializeSCSSParser (const langType language) " % module-name offset' count namespace-string\n" " _copyinterval\n" " dup length 0 gt {\n" - " /namespace @1 _tag _commit pop\n" + " /namespace @1 _tag _commit \\1 SCSS.module:\n" " } {\n" " clear\n" " } ifelse\n" " } {\n" " % Extract the module name as a namespace.\n" - " \\1 /namespace @1 _tag _commit pop\n" + " \\1 /namespace @1 _tag _commit \\1 SCSS.module:\n" " } ifelse\n" " } {\n" " % \"as *\" doesn't make a namespace.\n" " \\3 (*) ne {\n" - " \\3 /namespace @3 _tag _commit pop\n" + " \\3 /namespace @3 _tag _commit \\1 SCSS.module:\n" " } if\n" " } ifelse\n" "}}", NULL); @@ -233,6 +233,17 @@ extern parserDefinition* SCSSParser (void) ATTACH_ROLES(SCSSModuleRoleTable), }, }; + static fieldDefinition SCSSFieldTable [] = { + { + .enabled = true, + .name = "module", + .description = "the name of module behind the namespace", + .dataType = FIELDTYPE_SCRIPTABLE|FIELDTYPE_STRING, + .isValueAvailable = isValueAvailableGeneric, + .getValueObject = getFieldValueGeneric, + .setValueObject = setFieldValueGeneric, + }, + }; parserDefinition* const def = parserNew ("SCSS"); @@ -246,6 +257,8 @@ extern parserDefinition* SCSSParser (void) def->useCork = CORK_QUEUE; def->kindTable = SCSSKindTable; def->kindCount = ARRAY_SIZE(SCSSKindTable); + def->fieldTable = SCSSFieldTable; + def->fieldCount = ARRAY_SIZE(SCSSFieldTable); def->initialize = initializeSCSSParser; return def; diff --git a/optlib/scss.ctags b/optlib/scss.ctags index 80bbd32314..c615ff8f3c 100644 --- a/optlib/scss.ctags +++ b/optlib/scss.ctags @@ -40,6 +40,9 @@ --kinddef-SCSS=M,module,modules --_roledef-SCSS.{module}=used,used +--_fielddef-SCSS=module,the name of module behind the namespace{datatype=str} +--fields-SCSS=+{module} + --_tabledef-SCSS=toplevel --_tabledef-SCSS=comment --_tabledef-SCSS=interp @@ -69,18 +72,18 @@ % module-name offset' count namespace-string _copyinterval dup length 0 gt { - /namespace @1 _tag _commit pop + /namespace @1 _tag _commit \1 SCSS.module: } { clear } ifelse } { % Extract the module name as a namespace. - \1 /namespace @1 _tag _commit pop + \1 /namespace @1 _tag _commit \1 SCSS.module: } ifelse } { % "as *" doesn't make a namespace. \3 (*) ne { - \3 /namespace @3 _tag _commit pop + \3 /namespace @3 _tag _commit \1 SCSS.module: } if } ifelse }}