Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Parse set() options correctly #157

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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 37 additions & 15 deletions src/cminx/aggregator.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,18 +24,19 @@ class listens to all relevent parser rules, generates
:Author: Branden Butler
:License: Apache 2.0
"""

import itertools
import logging
import re
from dataclasses import dataclass
from enum import Enum
from typing import List, Union

from antlr4 import ParserRuleContext

from .documentation_types import AttributeDocumentation, FunctionDocumentation, MacroDocumentation, \
VariableDocumentation, GenericCommandDocumentation, ClassDocumentation, TestDocumentation, SectionDocumentation, \
MethodDocumentation, VarType, CTestDocumentation, ModuleDocumentation, AbstractCommandDefinitionDocumentation, \
OptionDocumentation, DanglingDoccomment, DocumentationType
OptionDocumentation, DanglingDoccomment, DocumentationType, SetCommandKeywords, CacheVarType

from .exceptions import CMakeSyntaxException
from .parser.CMakeListener import CMakeListener
Expand All @@ -45,6 +46,8 @@ class listens to all relevent parser rules, generates
from cminx import Settings




@dataclass
class DefinitionCommand:
"""
Expand Down Expand Up @@ -283,7 +286,7 @@ def process_set(self, ctx: CMakeParser.Command_invocationContext, docstring: str

:param docstring: Cleaned docstring.
"""

params = [val.getText() for val in ctx.single_argument()]
if len(ctx.single_argument()) < 1:
pretty_text = docstring
pretty_text += f"\n{ctx.getText()}"
Expand All @@ -292,17 +295,31 @@ def process_set(self, ctx: CMakeParser.Command_invocationContext, docstring: str
f"set() called with incorrect parameters: {ctx.single_argument()}\n\n{pretty_text}")
return

varname = ctx.single_argument()[
0].getText()
# First argument is name of variable so ignore that
arg_len = len(ctx.single_argument()) - 1
varname = params[0]
# Used for comparing against the set() command's keywords
params_upper = [param.upper() for param in params[1:]]
values = list(
itertools.takewhile(
lambda param: param not in SetCommandKeywords.values(),
params[1:]
)
)

if arg_len > 1: # List
values = [val.getText()
for val in ctx.single_argument()[1:]]
keywords = {kw: kw.value in params_upper for kw in SetCommandKeywords}

if keywords[SetCommandKeywords.CACHE]:
cache_keyword_index = params.index(SetCommandKeywords.CACHE.value)
cache_var_type = CacheVarType.values()[params[cache_keyword_index + 1]]
cache_var_docstring = params[cache_keyword_index + 2]
else:
cache_var_type = None
cache_var_docstring = ""

if len(values) > 1: # List
self.documented.append(VariableDocumentation(
varname, docstring, VarType.LIST, " ".join(values)))
elif arg_len == 1: # String
varname, docstring, VarType.LIST, " ".join(values), keywords, cache_var_type, cache_var_docstring
))
elif len(values) == 1: # String
value = ctx.single_argument()[1].getText()

# If the value includes the quote marks,
Expand All @@ -312,10 +329,12 @@ def process_set(self, ctx: CMakeParser.Command_invocationContext, docstring: str
if value[-1] == '"':
value = value[:-1]
self.documented.append(VariableDocumentation(
varname, docstring, VarType.STRING, value))
varname, docstring, VarType.STRING, value, keywords, cache_var_type, cache_var_docstring
))
else: # Unset
self.documented.append(VariableDocumentation(
varname, docstring, VarType.UNSET, None))
varname, docstring, VarType.UNSET, None, keywords
))

def process_cpp_class(self, ctx: CMakeParser.Command_invocationContext, docstring: str) -> None:
"""
Expand Down Expand Up @@ -493,13 +512,16 @@ def process_option(self, ctx: CMakeParser.Command_invocationContext, docstring:
pretty_text += f"\n{ctx.getText()}"

self.logger.error(
f"ct_add_section() called with incorrect parameters: {params}\n\n{pretty_text}")
f"option() called with incorrect parameters: {params}\n\n{pretty_text}")
return

option_doc = OptionDocumentation(
params[0],
docstring,
"bool",
params[2] if len(params) == 3 else None,
{},
None,
params[1]
)
self.documented.append(option_doc)
Expand Down
52 changes: 45 additions & 7 deletions src/cminx/documentation_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,37 @@
from abc import ABC, abstractmethod
from dataclasses import dataclass, field
from enum import Enum
from typing import Union, List
from typing import Union, List, Dict

from .rstwriter import RSTWriter, Directive, interpreted_text


class SetCommandKeywords(Enum):
CACHE = "CACHE"
PARENT_SCOPE = "PARENT_SCOPE"
BOOL = "BOOL"
PATH = "PATH"
STRING = "STRING"
INTERNAL = "INTERNAL"
FORCE = "FORCE"

@classmethod
def values(cls) -> List[str]:
return [param.value for param in cls]


class CacheVarType(Enum):
BOOL = "BOOL"
FILEPATH = "FILEPATH"
PATH = "PATH"
STRING = "STRING"
INTERNAL = "INTERNAL"

@classmethod
def values(cls) -> Dict[str, 'CacheVarType']:
return {param.value: param for param in cls}


class VarType(Enum):
"""The types of variables accepted by the CMake :code:`set()` command"""

Expand Down Expand Up @@ -145,9 +171,23 @@ class VariableDocumentation(DocumentationType):
value: Union[str, None]
"""A default value that the variable has"""

keywords: Dict[SetCommandKeywords, bool]
"""
A dictionary between the set() command keywords and whether
they were present / active in the documented call.
"""

cache_var_type: Union[CacheVarType, None] = None

cache_var_docstring: str = ""

def process(self, writer: RSTWriter) -> None:
d = writer.directive("data", f"{self.name}")
d.text(self.doc)
if self.cache_var_type is not None:
d.text("Cache help text:")
d.text(self.cache_var_docstring)
d.field("FORCE", str(self.keywords[SetCommandKeywords.FORCE]))
d.field("Default value", self.value)
if self.type == VarType.STRING:
var_type = "str"
Expand All @@ -157,7 +197,7 @@ def process(self, writer: RSTWriter) -> None:
var_type = "UNSET"
else:
raise ValueError(f"Unknown variable type: {self.type}")
d.field("type", var_type)
d.field("type", var_type if self.cache_var_type is None else self.cache_var_type.value)


@dataclass
Expand All @@ -167,12 +207,10 @@ class OptionDocumentation(VariableDocumentation):
representing a user-configurable option that can
be selected via the cache. The RST form of this documentation
also uses the :code:`data` directive, but includes a note
specifying the variable is an option.
specifying the variable is an option. The help text is
the cache_var_docstring field.
"""

help_text: str
"""The help text that the option has."""

def process(self, writer: RSTWriter) -> None:
d = writer.directive("data", f"{self.name}")
note = d.directive("note")
Expand All @@ -183,7 +221,7 @@ def process(self, writer: RSTWriter) -> None:
edited on the command line by the :code:`-D` flag.
"""))
d.text(self.doc)
d.field("Help text", self.help_text)
d.field("Help text", self.cache_var_docstring)
d.field("Default value", self.value if self.value is not None else "OFF")
d.field("type", self.type)

Expand Down
6 changes: 6 additions & 0 deletions tests/examples/example.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,12 @@ set(MyList "Value" "Value 2")
#]]
set(MyString "String")

#[[[
# This is an example of a cache variable.
# This variable is a string variable.
#]]
set(MyStringCache "String" CACHE STRING "Some string a user can set in cache.")

#[[
# This is an undocumented variable.
# Unlike most other elements, it will
Expand Down
15 changes: 15 additions & 0 deletions tests/examples/sphinx/source/example.rst
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,21 @@ examples.example
:type: str


.. data:: MyStringCache

This is an example of a cache variable.
This variable is a string variable.

Cache help text:
"Some string a user can set in cache."

:FORCE: False

:Default value: String

:type: STRING


.. function:: message("hello")


Expand Down
15 changes: 15 additions & 0 deletions tests/examples/sphinx/source/example_no_undocumented.rst
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,21 @@ examples.example
:type: str


.. data:: MyStringCache

This is an example of a cache variable.
This variable is a string variable.

Cache help text:
"Some string a user can set in cache."

:FORCE: False

:Default value: String

:type: STRING


.. function:: message("hello")


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,21 @@ examples.example.cmake
:type: str


.. data:: MyStringCache

This is an example of a cache variable.
This variable is a string variable.

Cache help text:
"Some string a user can set in cache."

:FORCE: False

:Default value: String

:type: STRING


.. function:: message("hello")


Expand Down
15 changes: 15 additions & 0 deletions tests/examples/sphinx/source/example_prefix.rst
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,21 @@ prefix.example
:type: str


.. data:: MyStringCache

This is an example of a cache variable.
This variable is a string variable.

Cache help text:
"Some string a user can set in cache."

:FORCE: False

:Default value: String

:type: STRING


.. function:: message("hello")


Expand Down
2 changes: 1 addition & 1 deletion tests/unit_tests/test_documenter.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ def test_process(self):
self.fail(f"Unknown documentation type: {doc}")

def test_incorrect_variable_type(self):
var_doc = VariableDocumentation("name", "Not a valid variable type", "0", "This should fail")
var_doc = VariableDocumentation("name", "Not a valid variable type", "0", "This should fail", {})
self.assertRaises(ValueError, var_doc.process,
RSTWriter("test_writer"))

Expand Down
Loading