From dfdadb185f4a8060a21b755f695186a236f7b72e Mon Sep 17 00:00:00 2001 From: Masatake YAMATO Date: Mon, 25 Jul 2022 02:51:27 +0900 Subject: [PATCH] KernelDoc: new parser This one is disabled by default. Give --languages=+KernelDoc for enabling. Signed-off-by: Masatake YAMATO --- .../list-subparsers-all.d/stdout-expected.txt | 61 ++-- .../dots-in-members.d/args.ctags | 7 + .../dots-in-members.d/expected.tags | 12 + .../dots-in-members.d/input.c | 38 +++ Units/parser-kerneldoc.r/inline.d/args.ctags | 7 + .../parser-kerneldoc.r/inline.d/expected.tags | 7 + Units/parser-kerneldoc.r/inline.d/input.c | 29 ++ Units/parser-kerneldoc.r/simple.d/args.ctags | 7 + .../parser-kerneldoc.r/simple.d/expected.tags | 20 ++ Units/parser-kerneldoc.r/simple.d/input.c | 81 ++++++ .../typedef-with-prototype.d/args.ctags | 7 + .../typedef-with-prototype.d/expected.tags | 3 + .../typedef-with-prototype.d/input.c | 12 + docs/news.rst | 1 + main/parsers_p.h | 1 + parsers/kerneldoc.c | 275 ++++++++++++++++++ source.mak | 1 + 17 files changed, 539 insertions(+), 30 deletions(-) create mode 100644 Units/parser-kerneldoc.r/dots-in-members.d/args.ctags create mode 100644 Units/parser-kerneldoc.r/dots-in-members.d/expected.tags create mode 100644 Units/parser-kerneldoc.r/dots-in-members.d/input.c create mode 100644 Units/parser-kerneldoc.r/inline.d/args.ctags create mode 100644 Units/parser-kerneldoc.r/inline.d/expected.tags create mode 100644 Units/parser-kerneldoc.r/inline.d/input.c create mode 100644 Units/parser-kerneldoc.r/simple.d/args.ctags create mode 100644 Units/parser-kerneldoc.r/simple.d/expected.tags create mode 100644 Units/parser-kerneldoc.r/simple.d/input.c create mode 100644 Units/parser-kerneldoc.r/typedef-with-prototype.d/args.ctags create mode 100644 Units/parser-kerneldoc.r/typedef-with-prototype.d/expected.tags create mode 100644 Units/parser-kerneldoc.r/typedef-with-prototype.d/input.c create mode 100644 parsers/kerneldoc.c diff --git a/Tmain/list-subparsers-all.d/stdout-expected.txt b/Tmain/list-subparsers-all.d/stdout-expected.txt index 95905bfff5..df2e74a39f 100644 --- a/Tmain/list-subparsers-all.d/stdout-expected.txt +++ b/Tmain/list-subparsers-all.d/stdout-expected.txt @@ -1,30 +1,31 @@ -#NAME BASEPARSER DIRECTIONS -AnsiblePlaybook Yaml base <> sub {bidirectional} -Ant XML base <> sub {bidirectional} -Autoconf M4 base <> sub {bidirectional} -Automake Make base <= sub {dedicated} -Bats Sh base <= sub {dedicated} -DBusIntrospect XML base <> sub {bidirectional} -FunctionParameters Perl base <> sub {bidirectional} -GemSpec Ruby base <= sub {dedicated} -Glade XML base <> sub {bidirectional} -IPythonCell Python base => sub {shared} -ITcl Tcl base <> sub {bidirectional} -Maven2 XML base <> sub {bidirectional} -Moose Perl base <> sub {bidirectional} -OpenAPI Yaml base <> sub {bidirectional} -PlistXML XML base <> sub {bidirectional} -PythonLoggingConfig Iniconf base <> sub {bidirectional} -QtMoc C++ base <> sub {bidirectional} -R6Class R base <> sub {bidirectional} -RMarkdown Markdown base <= sub {dedicated} -RSpec Ruby base => sub {shared} -Rake Ruby base <= sub {dedicated} -RelaxNG XML base <> sub {bidirectional} -S4Class R base <> sub {bidirectional} -SVG XML base <> sub {bidirectional} -SystemdUnit Iniconf base <= sub {dedicated} -TclOO Tcl base <> sub {bidirectional} -TeXBeamer Tex base <> sub {bidirectional} -XSLT XML base <> sub {bidirectional} -YumRepo Iniconf base <= sub {dedicated} +#NAME BASEPARSER DIRECTIONS +AnsiblePlaybook Yaml base <> sub {bidirectional} +Ant XML base <> sub {bidirectional} +Autoconf M4 base <> sub {bidirectional} +Automake Make base <= sub {dedicated} +Bats Sh base <= sub {dedicated} +DBusIntrospect XML base <> sub {bidirectional} +FunctionParameters Perl base <> sub {bidirectional} +GemSpec Ruby base <= sub {dedicated} +Glade XML base <> sub {bidirectional} +IPythonCell Python base => sub {shared} +ITcl Tcl base <> sub {bidirectional} +KernelDoc CPreProcessor base => sub {shared} +Maven2 XML base <> sub {bidirectional} +Moose Perl base <> sub {bidirectional} +OpenAPI Yaml base <> sub {bidirectional} +PlistXML XML base <> sub {bidirectional} +PythonLoggingConfig Iniconf base <> sub {bidirectional} +QtMoc C++ base <> sub {bidirectional} +R6Class R base <> sub {bidirectional} +RMarkdown Markdown base <= sub {dedicated} +RSpec Ruby base => sub {shared} +Rake Ruby base <= sub {dedicated} +RelaxNG XML base <> sub {bidirectional} +S4Class R base <> sub {bidirectional} +SVG XML base <> sub {bidirectional} +SystemdUnit Iniconf base <= sub {dedicated} +TclOO Tcl base <> sub {bidirectional} +TeXBeamer Tex base <> sub {bidirectional} +XSLT XML base <> sub {bidirectional} +YumRepo Iniconf base <= sub {dedicated} diff --git a/Units/parser-kerneldoc.r/dots-in-members.d/args.ctags b/Units/parser-kerneldoc.r/dots-in-members.d/args.ctags new file mode 100644 index 0000000000..7f2bb04f2b --- /dev/null +++ b/Units/parser-kerneldoc.r/dots-in-members.d/args.ctags @@ -0,0 +1,7 @@ +--sort=no +--languages=+KernelDoc +--fields=+Kl +--extras=+g +--kinds-KernelDoc=* +--kinds-C= +--kinds-CPreProcessor= diff --git a/Units/parser-kerneldoc.r/dots-in-members.d/expected.tags b/Units/parser-kerneldoc.r/dots-in-members.d/expected.tags new file mode 100644 index 0000000000..1b71314cbd --- /dev/null +++ b/Units/parser-kerneldoc.r/dots-in-members.d/expected.tags @@ -0,0 +1,12 @@ +nested_foobar input.c /^ * struct nested_foobar - a struct with nested unions and structs$/;" struct language:KernelDoc +memb1 input.c /^ * @memb1: first member of anonymous union\/anonymous struct$/;" member language:KernelDoc struct:nested_foobar +memb2 input.c /^ * @memb2: second member of anonymous union\/anonymous struct$/;" member language:KernelDoc struct:nested_foobar +memb3 input.c /^ * @memb3: third member of anonymous union\/anonymous struct$/;" member language:KernelDoc struct:nested_foobar +memb4 input.c /^ * @memb4: fourth member of anonymous union\/anonymous struct$/;" member language:KernelDoc struct:nested_foobar +bar input.c /^ * @bar: non-anonymous union$/;" member language:KernelDoc struct:nested_foobar +bar.st1 input.c /^ * @bar.st1: struct st1 inside @bar$/;" member language:KernelDoc struct:nested_foobar +bar.st2 input.c /^ * @bar.st2: struct st2 inside @bar$/;" member language:KernelDoc struct:nested_foobar +bar.st1.memb1 input.c /^ * @bar.st1.memb1: first member of struct st1 on union bar$/;" member language:KernelDoc struct:nested_foobar +bar.st1.memb2 input.c /^ * @bar.st1.memb2: second member of struct st1 on union bar$/;" member language:KernelDoc struct:nested_foobar +bar.st2.memb1 input.c /^ * @bar.st2.memb1: first member of struct st2 on union bar$/;" member language:KernelDoc struct:nested_foobar +bar.st2.memb2 input.c /^ * @bar.st2.memb2: second member of struct st2 on union bar$/;" member language:KernelDoc struct:nested_foobar diff --git a/Units/parser-kerneldoc.r/dots-in-members.d/input.c b/Units/parser-kerneldoc.r/dots-in-members.d/input.c new file mode 100644 index 0000000000..fd7cfdd4bb --- /dev/null +++ b/Units/parser-kerneldoc.r/dots-in-members.d/input.c @@ -0,0 +1,38 @@ +/* Taken from linux/Documentation/doc-guide/kernel-doc.rst */ +/** + * struct nested_foobar - a struct with nested unions and structs + * @memb1: first member of anonymous union/anonymous struct + * @memb2: second member of anonymous union/anonymous struct + * @memb3: third member of anonymous union/anonymous struct + * @memb4: fourth member of anonymous union/anonymous struct + * @bar: non-anonymous union + * @bar.st1: struct st1 inside @bar + * @bar.st2: struct st2 inside @bar + * @bar.st1.memb1: first member of struct st1 on union bar + * @bar.st1.memb2: second member of struct st1 on union bar + * @bar.st2.memb1: first member of struct st2 on union bar + * @bar.st2.memb2: second member of struct st2 on union bar + */ +struct nested_foobar { + /* Anonymous union/struct*/ + union { + struct { + int memb1; + int memb2; + }; + struct { + void *memb3; + int memb4; + }; + }; + union { + struct { + int memb1; + int memb2; + } st1; + struct { + void *memb1; + int memb2; + } st2; + } bar; +}; diff --git a/Units/parser-kerneldoc.r/inline.d/args.ctags b/Units/parser-kerneldoc.r/inline.d/args.ctags new file mode 100644 index 0000000000..7f2bb04f2b --- /dev/null +++ b/Units/parser-kerneldoc.r/inline.d/args.ctags @@ -0,0 +1,7 @@ +--sort=no +--languages=+KernelDoc +--fields=+Kl +--extras=+g +--kinds-KernelDoc=* +--kinds-C= +--kinds-CPreProcessor= diff --git a/Units/parser-kerneldoc.r/inline.d/expected.tags b/Units/parser-kerneldoc.r/inline.d/expected.tags new file mode 100644 index 0000000000..a158131c01 --- /dev/null +++ b/Units/parser-kerneldoc.r/inline.d/expected.tags @@ -0,0 +1,7 @@ +foo input.c /^ * struct foo - Brief description.$/;" struct language:KernelDoc +foo input.c /^ * @foo: The Foo member.$/;" member language:KernelDoc struct:foo +@bar input.c /^ * @bar: The Bar member.$/;" unknown language:GtkDoc +@baz input.c /^ * @baz: The Baz member.$/;" unknown language:GtkDoc +@foobar input.c /^ \/** @foobar: Single line description. *\/$/;" unknown language:GtkDoc +@bar2 input.c /^ \/** @bar2: Description for struct @bar2 inside @foo *\/$/;" unknown language:GtkDoc +@bar2.barbar input.c /^ * @bar2.barbar: Description for @barbar inside @foo.bar2$/;" unknown language:GtkDoc diff --git a/Units/parser-kerneldoc.r/inline.d/input.c b/Units/parser-kerneldoc.r/inline.d/input.c new file mode 100644 index 0000000000..b17a224b71 --- /dev/null +++ b/Units/parser-kerneldoc.r/inline.d/input.c @@ -0,0 +1,29 @@ +/* Taken from linux/Documentation/doc-guide/kernel-doc.rst */ +/** + * struct foo - Brief description. + * @foo: The Foo member. + */ +struct foo { + int foo; + /** + * @bar: The Bar member. + */ + int bar; + /** + * @baz: The Baz member. + * + * Here, the member description may contain several paragraphs. + */ + int baz; + union { + /** @foobar: Single line description. */ + int foobar; + }; + /** @bar2: Description for struct @bar2 inside @foo */ + struct { + /** + * @bar2.barbar: Description for @barbar inside @foo.bar2 + */ + int barbar; + } bar2; +}; diff --git a/Units/parser-kerneldoc.r/simple.d/args.ctags b/Units/parser-kerneldoc.r/simple.d/args.ctags new file mode 100644 index 0000000000..7f2bb04f2b --- /dev/null +++ b/Units/parser-kerneldoc.r/simple.d/args.ctags @@ -0,0 +1,7 @@ +--sort=no +--languages=+KernelDoc +--fields=+Kl +--extras=+g +--kinds-KernelDoc=* +--kinds-C= +--kinds-CPreProcessor= diff --git a/Units/parser-kerneldoc.r/simple.d/expected.tags b/Units/parser-kerneldoc.r/simple.d/expected.tags new file mode 100644 index 0000000000..30b0bd38f8 --- /dev/null +++ b/Units/parser-kerneldoc.r/simple.d/expected.tags @@ -0,0 +1,20 @@ +cpuhp_invoke_callback input.c /^ * cpuhp_invoke_callback - Invoke the callbacks for a given state$/;" unknown language:KernelDoc +cpu input.c /^ * @cpu: The cpu for which the callback should be invoked$/;" parameter language:KernelDoc unknown:cpuhp_invoke_callback +state input.c /^ * @state: The state to do callbacks for$/;" parameter language:KernelDoc unknown:cpuhp_invoke_callback +bringup input.c /^ * @bringup: True if the bringup callback should be invoked$/;" parameter language:KernelDoc unknown:cpuhp_invoke_callback +node input.c /^ * @node: For multi-instance, do a single entry callback for install\/remove$/;" parameter language:KernelDoc unknown:cpuhp_invoke_callback +lastp input.c /^ * @lastp: For multi-instance rollback, remember how far we got$/;" parameter language:KernelDoc unknown:cpuhp_invoke_callback +ACPI_DEVICE_CLASS input.c /^ * ACPI_DEVICE_CLASS - macro used to describe an ACPI device with$/;" unknown language:KernelDoc +_cls input.c /^ * @_cls : the class, subclass, prog-if triple for this device$/;" parameter language:KernelDoc unknown:ACPI_DEVICE_CLASS +_msk input.c /^ * @_msk : the class mask for this device$/;" parameter language:KernelDoc unknown:ACPI_DEVICE_CLASS +acpi_dma_spec input.c /^ * struct acpi_dma_spec - slave device DMA resources$/;" struct language:KernelDoc +chan_id input.c /^ * @chan_id: channel unique id$/;" member language:KernelDoc struct:acpi_dma_spec +slave_id input.c /^ * @slave_id: request line unique id$/;" member language:KernelDoc struct:acpi_dma_spec +dev input.c /^ * @dev: struct device of the DMA controller to be used in the filter$/;" member language:KernelDoc struct:acpi_dma_spec +dma_cookie_t input.c /^ * typedef dma_cookie_t - an opaque DMA cookie$/;" typedef language:KernelDoc +coresight_dev_subtype input.c /^ * union coresight_dev_subtype - further characterisation of a type$/;" union language:KernelDoc +sink_subtype input.c /^ * @sink_subtype: type of sink this component is, as defined$/;" member language:KernelDoc union:coresight_dev_subtype +link_subtype input.c /^ * @link_subtype: type of link this component is, as defined$/;" member language:KernelDoc union:coresight_dev_subtype +source_subtype input.c /^ * @source_subtype: type of source this component is, as defined$/;" member language:KernelDoc union:coresight_dev_subtype +helper_subtype input.c /^ * @helper_subtype: type of helper this component is, as defined$/;" member language:KernelDoc union:coresight_dev_subtype +ect_subtype input.c /^ * @ect_subtype: type of cross trigger this component is, as$/;" member language:KernelDoc union:coresight_dev_subtype diff --git a/Units/parser-kerneldoc.r/simple.d/input.c b/Units/parser-kerneldoc.r/simple.d/input.c new file mode 100644 index 0000000000..89f825a616 --- /dev/null +++ b/Units/parser-kerneldoc.r/simple.d/input.c @@ -0,0 +1,81 @@ +/* Taken from linux/kernel/cpu.c */ + +/** + * cpuhp_invoke_callback - Invoke the callbacks for a given state + * @cpu: The cpu for which the callback should be invoked + * @state: The state to do callbacks for + * @bringup: True if the bringup callback should be invoked + * @node: For multi-instance, do a single entry callback for install/remove + * @lastp: For multi-instance rollback, remember how far we got + * + * Called from cpu hotplug and from the state register machinery. + * + * Return: %0 on success or a negative errno code + */ +static int cpuhp_invoke_callback(unsigned int cpu, enum cpuhp_state state, + bool bringup, struct hlist_node *node, + struct hlist_node **lastp) +{ + return 0; +} + +/* Taken from linux/include/linux/acpi.h */ +/** + * ACPI_DEVICE_CLASS - macro used to describe an ACPI device with + * the PCI-defined class-code information + * + * @_cls : the class, subclass, prog-if triple for this device + * @_msk : the class mask for this device + * + * This macro is used to create a struct acpi_device_id that matches a + * specific PCI class. The .id and .driver_data fields will be left + * initialized with the default value. + */ +#define ACPI_DEVICE_CLASS(_cls, _msk) .cls = (_cls), .cls_msk = (_msk), + +/* Taken from linux/include/linux/acpi_dma.h */ +/** + * struct acpi_dma_spec - slave device DMA resources + * @chan_id: channel unique id + * @slave_id: request line unique id + * @dev: struct device of the DMA controller to be used in the filter + * function + */ +struct acpi_dma_spec { + int chan_id; + int slave_id; + struct device *dev; +}; + +/* Taken from linux/include/linux/dmaengine.h */ +/** + * typedef dma_cookie_t - an opaque DMA cookie + * + * if dma_cookie_t is >0 it's a DMA request cookie, <0 it's an error code + */ +typedef s32 dma_cookie_t; + +/* Taken from linux/include/linux/coresight.h */ +/** + * union coresight_dev_subtype - further characterisation of a type + * @sink_subtype: type of sink this component is, as defined + * by @coresight_dev_subtype_sink. + * @link_subtype: type of link this component is, as defined + * by @coresight_dev_subtype_link. + * @source_subtype: type of source this component is, as defined + * by @coresight_dev_subtype_source. + * @helper_subtype: type of helper this component is, as defined + * by @coresight_dev_subtype_helper. + * @ect_subtype: type of cross trigger this component is, as + * defined by @coresight_dev_subtype_ect + */ +union coresight_dev_subtype { + /* We have some devices which acts as LINK and SINK */ + struct { + enum coresight_dev_subtype_sink sink_subtype; + enum coresight_dev_subtype_link link_subtype; + }; + enum coresight_dev_subtype_source source_subtype; + enum coresight_dev_subtype_helper helper_subtype; + enum coresight_dev_subtype_ect ect_subtype; +}; diff --git a/Units/parser-kerneldoc.r/typedef-with-prototype.d/args.ctags b/Units/parser-kerneldoc.r/typedef-with-prototype.d/args.ctags new file mode 100644 index 0000000000..7f2bb04f2b --- /dev/null +++ b/Units/parser-kerneldoc.r/typedef-with-prototype.d/args.ctags @@ -0,0 +1,7 @@ +--sort=no +--languages=+KernelDoc +--fields=+Kl +--extras=+g +--kinds-KernelDoc=* +--kinds-C= +--kinds-CPreProcessor= diff --git a/Units/parser-kerneldoc.r/typedef-with-prototype.d/expected.tags b/Units/parser-kerneldoc.r/typedef-with-prototype.d/expected.tags new file mode 100644 index 0000000000..d4af5c349f --- /dev/null +++ b/Units/parser-kerneldoc.r/typedef-with-prototype.d/expected.tags @@ -0,0 +1,3 @@ +type_name input.c /^ * typedef type_name - Brief description.$/;" typedef language:KernelDoc +arg1 input.c /^ * @arg1: description of arg1$/;" parameter language:KernelDoc typedef:type_name +arg2 input.c /^ * @arg2: description of arg2$/;" parameter language:KernelDoc typedef:type_name diff --git a/Units/parser-kerneldoc.r/typedef-with-prototype.d/input.c b/Units/parser-kerneldoc.r/typedef-with-prototype.d/input.c new file mode 100644 index 0000000000..fd6601e8de --- /dev/null +++ b/Units/parser-kerneldoc.r/typedef-with-prototype.d/input.c @@ -0,0 +1,12 @@ +/* Taken from linux/Documentation/doc-guide/kernel-doc.rst */ +/** + * typedef type_name - Brief description. + * @arg1: description of arg1 + * @arg2: description of arg2 + * + * Description of the type. + * + * Context: Locking context. + * Return: Meaning of the return value. + */ + typedef void (*type_name)(struct v4l2_ctrl *arg1, void *arg2); diff --git a/docs/news.rst b/docs/news.rst index 464ed4b77c..1ee18793ef 100644 --- a/docs/news.rst +++ b/docs/news.rst @@ -429,6 +429,7 @@ The following parsers have been added: * JSON * Julia * Kconfig *optlib* +* KernelDoc *CPreProcessor based subparser" * Kotlin *peg/packcc* * GNU linker script(LdScript) * LEX *optlib* diff --git a/main/parsers_p.h b/main/parsers_p.h index faba51fb11..dcb7c4b9e1 100644 --- a/main/parsers_p.h +++ b/main/parsers_p.h @@ -115,6 +115,7 @@ JsonParser, \ JuliaParser, \ KconfigParser, \ + KernelDocParser, \ LdScriptParser, \ LEXParser, \ LispParser, \ diff --git a/parsers/kerneldoc.c b/parsers/kerneldoc.c new file mode 100644 index 0000000000..bb7af2ba11 --- /dev/null +++ b/parsers/kerneldoc.c @@ -0,0 +1,275 @@ +/* + * Copyright (c) 2023, Masatake YAMATO + * Copyright (c) 2023, Red Hat, Inc. + * + * This source code is released for free distribution under the terms of the + * GNU General Public License version 2 or (at your option) any later version. + * + * This module contains functions for generating tags for kerledoc used in + * linux kernel. + * + * References: + * - https://www.kernel.org/doc/html/v4.9/kernel-documentation.html#writing-kernel-doc-comments + * - https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/Documentation/doc-guide/kernel-doc.rst + * - https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/scripts/kernel-doc + */ + +// NOTE: +// This parser doesn't extract overviews like: + /** + * DOC: Theory of Operation + * + * The whizbang foobar is a dilly of a gizmo. It can do whatever you + * want it to do, at any time. It reads your mind. Here's how it works. + * + * foo bar splat + * + * The only drawback to this gizmo is that is can sometimes damage + * hardware, software, or its subject(s). + */ +// because this "DOC:" notation implies the comment is written in GtkDoc. +// We cannot find the way to distribution an overview of KernelDoc from +// GtkDoc comments. + + +#include "general.h" /* must always come first */ +#include "cpreprocessor.h" + +#include "entry.h" +#include "keyword.h" +#include "kind.h" +#include "parse.h" +#include "read.h" +#include "vstring.h" + +#include +#include + +static langType Lang_kerneldoc; + +typedef enum { + K_UNKNOWN, + K_STRUCT, + K_UNION, + K_ENUM, + K_TYPEDEF, + K_PARAM, + K_FUNCTION, + K_MEMBER, + K_ENUMERATOR, +} kernelDocKind; + +static kindDefinition KernelDocKinds [] = { + { true, 'Y', "unknown", "unknown items", }, + { true, 's', "struct", "struct names", }, + { true, 'u', "union", "union names", }, + { true, 'g', "enum", "enumeration names", }, + { true, 't', "typedef", "typedefs", }, + { true, 'z', "parameter", "parameters" }, + { true, 'f', "function", "functions and macros" }, + { true, 'm', "member", "struct, and union members" }, + { true, 'e', "enumerator" "enumerators (values inside an enumeration)" }, +}; + +struct sKernelDocSubparser { + cPreProcessorSubparser cpp; + int current; /* cork index */ +}; + +enum { + KEYWORD_struct, + KEYWORD_typedef, + KEYWORD_union, + KEYWORD_enum, +}; + +static const keywordTable KernelDocKeywordTable[] = { + { "struct", KEYWORD_struct }, + { "typedef", KEYWORD_typedef }, + { "union", KEYWORD_union }, + { "enum", KEYWORD_enum }, +}; + +static void findKernelDocTags (void) +{ + scheduleRunningBaseparser (0); +} + +static bool firstLineNotify (cPreProcessorSubparser *s, char firstchar, const char *line) +{ + int kind = K_UNKNOWN; + int r = CORK_NIL; + const char *c = line; + vString *obj = NULL; + + while (isspace((unsigned char)*c) || *c == '*') + c++; + + obj = vStringNew (); + while (*c) + { + if (isspace((unsigned char)*c)) + { + int k = lookupKeyword (vStringValue (obj), Lang_kerneldoc); + if (k == KEYWORD_struct) + { + vStringClear(obj); + kind = K_STRUCT; + c++; + continue; + } + else if (k == KEYWORD_union) + { + vStringClear(obj); + kind = K_UNION; + c++; + continue; + + } + else if (k == KEYWORD_enum) + { + vStringClear(obj); + kind = K_ENUMERATOR; + c++; + continue; + + } + else if (k == KEYWORD_typedef) + { + vStringClear(obj); + kind = K_TYPEDEF; + c++; + continue; + } + else + { + c++; + break; + } + } + vStringPut(obj, *c++); + } + + while (isspace((unsigned char)*c)) + c++; + + size_t len = vStringLength(obj); + if (len > 2 + && (vStringChar(obj, len - 1) == ')') && (vStringChar(obj, len - 2) == '(')) + { + kind = K_FUNCTION; + vStringTruncate (obj, len - 2); + len -= 2; + } + + if (*c == '-' && isspace((unsigned char)*(c + 1)) && len > 0) + { + r = makeSimpleTag(obj, kind); + ((struct sKernelDocSubparser *)s)->current = r; + } + + vStringDelete(obj); + + return r != CORK_NIL; +} + +static void restLineNotify (cPreProcessorSubparser *s, const char *line) +{ + const char *c = line; + + while (isspace((unsigned char)*c) || *c == '*') + c++; + + if (*c == '@') + { + vString *obj = vStringNew (); + c++; + while (*c && *c != ':') + vStringPut (obj, *c++); + if (*c == ':' && !vStringIsEmpty (obj)) + { + tagEntryInfo e; + int kindex = K_PARAM; + int current = ((struct sKernelDocSubparser *)s)->current; + tagEntryInfo *parent = getEntryInCorkQueue (current); + + if (parent) + { + switch (parent->kindIndex) + { + case K_TYPEDEF: + case K_FUNCTION: + break; + case K_UNION: + case K_STRUCT: + kindex = K_MEMBER; + break; + case K_ENUM: + kindex = K_ENUMERATOR; + break; + } + } + initTagEntry (&e, vStringValue (obj), kindex); + e.extensionFields.scopeIndex = current; + makeTagEntry(&e); + } + vStringDelete (obj); + } +} + +static void endOfCommentNotify(cPreProcessorSubparser *s) +{ + int r = ((struct sKernelDocSubparser *)s)->current; + tagEntryInfo *e = getEntryInCorkQueue (r); + + e->extensionFields.endLine = getInputLineNumber (); + ((struct sKernelDocSubparser *)s)->current = e->extensionFields.scopeIndex; +} + +static void initialize (const langType language) +{ + Lang_kerneldoc = language; +} + +static void inputStart (subparser *s) +{ + struct sKernelDocSubparser *kerneldoc = (struct sKernelDocSubparser*)s; + + kerneldoc->current = CORK_NIL; +} + +extern parserDefinition* KernelDocParser (void) +{ + static struct sKernelDocSubparser kernelDocSubparser = { + .cpp = { + .subparser = { + .direction = SUBPARSER_BASE_RUNS_SUB, + .inputStart = inputStart, + .inputEnd = NULL, + }, + .firstLineNotify = firstLineNotify, + .restLineNotify = restLineNotify, + .endOfCommentNotify = endOfCommentNotify, + }, + }; + static parserDependency dependencies [] = { + { DEPTYPE_SUBPARSER, "CPreProcessor", &kernelDocSubparser }, + }; + + parserDefinition* def = parserNew ("KernelDoc"); + def->enabled = false; + + def->kindTable = KernelDocKinds; + def->kindCount = ARRAY_SIZE (KernelDocKinds); + + def->parser = findKernelDocTags; + def->initialize = initialize; + + def->dependencies = dependencies; + def->dependencyCount = ARRAY_SIZE (dependencies); + + def->keywordTable = KernelDocKeywordTable; + def->keywordCount = ARRAY_SIZE (KernelDocKeywordTable); + + return def; +} diff --git a/source.mak b/source.mak index 9d54ca38fe..a83505f5b3 100644 --- a/source.mak +++ b/source.mak @@ -361,6 +361,7 @@ PARSER_SRCS = \ parsers/jscript.c \ parsers/json.c \ parsers/julia.c \ + parsers/kerneldoc.c \ parsers/ldscript.c \ parsers/lisp.c \ parsers/lua.c \