mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-26 10:11:46 +00:00
Support block comments in selector filter syntax (#5023)
The filter_elements selector grammar had no way to comment out part of a query, so users had to delete and retype text to temporarily toggle a facet. Add a /* ... */ block comment terminal that is ignored by the lexer, and tolerate a trailing "+" so that commenting out the final operand (e.g. "IfcWall + /* IfcSlab */") parses cleanly. Comments may span multiple lines; a /* sequence inside a quoted string is not treated as a comment. Only the filter grammar is affected, not get_element or format which use "/" for regex and division. Adds a regression test and documents the syntax. Generated with the assistance of an AI coding tool. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
committed by
Dion Moult
parent
0b7e25a3ef
commit
5c11946470
@@ -89,6 +89,11 @@ The filters are chained and apply from left to right.
|
|||||||
|
|
||||||
filter[, filter]*
|
filter[, filter]*
|
||||||
|
|
||||||
|
Any part of a query may be commented out using a ``/* ... */`` block comment.
|
||||||
|
This lets you temporarily disable part of a query without deleting the text, for
|
||||||
|
example ``IfcWall + /* IfcSlab, material=concrete */`` selects only walls while
|
||||||
|
keeping the slab criteria on hand. Block comments may span multiple lines.
|
||||||
|
|
||||||
Below is the table of filters to choose from. Most of these filters will filter
|
Below is the table of filters to choose from. Most of these filters will filter
|
||||||
previously added elements in your filter group based on their criteria.
|
previously added elements in your filter group based on their criteria.
|
||||||
|
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ import ifcopenshell.util.system
|
|||||||
import ifcopenshell.util.unit
|
import ifcopenshell.util.unit
|
||||||
|
|
||||||
filter_elements_grammar = lark.Lark("""start: filter_group
|
filter_elements_grammar = lark.Lark("""start: filter_group
|
||||||
filter_group: facet_list ("+" facet_list)*
|
filter_group: facet_list ("+" facet_list)* "+"?
|
||||||
facet_list: facet ("," facet)*
|
facet_list: facet ("," facet)*
|
||||||
|
|
||||||
facet: instance | entity | attribute | type | material | query | classification | location | property | group | parent
|
facet: instance | entity | attribute | type | material | query | classification | location | property | group | parent
|
||||||
@@ -108,8 +108,10 @@ filter_elements_grammar = lark.Lark("""start: filter_group
|
|||||||
CR : /\\r/
|
CR : /\\r/
|
||||||
LF : /\\n/
|
LF : /\\n/
|
||||||
NEWLINE: (CR? LF)+
|
NEWLINE: (CR? LF)+
|
||||||
|
COMMENT: "/*" /.*?/s "*/"
|
||||||
|
|
||||||
%ignore WS // Disregard spaces in text
|
%ignore WS // Disregard spaces in text
|
||||||
|
%ignore COMMENT // Allow /* ... */ block comments to toggle parts of a query
|
||||||
""")
|
""")
|
||||||
|
|
||||||
get_element_grammar = lark.Lark("""start: keys
|
get_element_grammar = lark.Lark("""start: keys
|
||||||
|
|||||||
@@ -351,6 +351,22 @@ class TestFilterElements(test.bootstrap.IFC4):
|
|||||||
assert subject.filter_elements(self.file, "IfcWall, Name=Foo + IfcSlab") == {element, element2}
|
assert subject.filter_elements(self.file, "IfcWall, Name=Foo + IfcSlab") == {element, element2}
|
||||||
assert subject.filter_elements(self.file, "IfcWall, Name=Foo + IfcSlab, Name=Bar") == {element, element2}
|
assert subject.filter_elements(self.file, "IfcWall, Name=Foo + IfcSlab, Name=Bar") == {element, element2}
|
||||||
|
|
||||||
|
def test_block_comments_are_ignored(self):
|
||||||
|
element = ifcopenshell.api.root.create_entity(self.file, ifc_class="IfcWall")
|
||||||
|
element.Name = "Foo"
|
||||||
|
element2 = ifcopenshell.api.root.create_entity(self.file, ifc_class="IfcSlab")
|
||||||
|
element2.Name = "Bar"
|
||||||
|
# A /* ... */ block comment lets a query be toggled off without deleting the text.
|
||||||
|
assert subject.filter_elements(self.file, "IfcWall /* + IfcSlab */") == {element}
|
||||||
|
assert subject.filter_elements(self.file, "IfcWall + /* IfcSlab */") == {element}
|
||||||
|
assert subject.filter_elements(self.file, "/* IfcWall + */ IfcSlab") == {element2}
|
||||||
|
assert subject.filter_elements(self.file, "IfcWall /* commented */ + IfcSlab") == {element, element2}
|
||||||
|
# Comments may span multiple lines.
|
||||||
|
assert subject.filter_elements(self.file, "IfcWall + /* multi\nline\ncomment */ IfcSlab") == {element, element2}
|
||||||
|
# A /* sequence inside a quoted string is not treated as a comment.
|
||||||
|
element.Name = "a/*b"
|
||||||
|
assert subject.filter_elements(self.file, 'IfcWall, Name="a/*b"') == {element}
|
||||||
|
|
||||||
def test_using_elements_argument(self):
|
def test_using_elements_argument(self):
|
||||||
wall = ifcopenshell.api.root.create_entity(self.file, ifc_class="IfcWall")
|
wall = ifcopenshell.api.root.create_entity(self.file, ifc_class="IfcWall")
|
||||||
slab = ifcopenshell.api.root.create_entity(self.file, ifc_class="IfcSlab")
|
slab = ifcopenshell.api.root.create_entity(self.file, ifc_class="IfcSlab")
|
||||||
|
|||||||
Reference in New Issue
Block a user