Skip to content

Commit 8d4637d

Browse files
committed
Swift: tag -> pragma in codegen
For the use the former tags are meant for, pragma is a more meaningful name. It now also accepts both strings and lists of strings.
1 parent 3248f7b commit 8d4637d

File tree

5 files changed

+107
-44
lines changed

5 files changed

+107
-44
lines changed

swift/codegen/generators/qlgen.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ class FormatError(Exception):
1919
def get_ql_property(cls: schema.Class, prop: schema.Property):
2020
common_args = dict(
2121
type=prop.type if not prop.is_predicate else "predicate",
22-
skip_qltest="no_qltest" in prop.tags,
22+
skip_qltest="skip_qltest" in prop.pragmas,
2323
is_child=prop.is_child,
2424
is_optional=prop.is_optional,
2525
is_predicate=prop.is_predicate,
@@ -64,7 +64,7 @@ def get_ql_class(cls: schema.Class):
6464
final=not cls.derived,
6565
properties=[get_ql_property(cls, p) for p in cls.properties],
6666
dir=cls.dir,
67-
skip_qltest="no_qltest" in cls.tags,
67+
skip_qltest="skip_qltest" in cls.pragmas,
6868
)
6969

7070

swift/codegen/lib/schema.py

Lines changed: 31 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import pathlib
44
import re
5+
import typing
56
from dataclasses import dataclass, field
67
from typing import List, Set, Union, Dict, ClassVar
78

@@ -11,7 +12,7 @@
1112
class Error(Exception):
1213

1314
def __str__(self):
14-
return f"schema.Error{args}"
15+
return self.args[0]
1516

1617

1718
root_class_name = "Element"
@@ -27,7 +28,7 @@ class Property:
2728
name: str
2829
type: str = None
2930
is_child: bool = False
30-
tags: List[str] = field(default_factory=list)
31+
pragmas: List[str] = field(default_factory=list)
3132

3233

3334
@dataclass
@@ -63,7 +64,7 @@ class Class:
6364
derived: Set[str] = field(default_factory=set)
6465
properties: List[Property] = field(default_factory=list)
6566
dir: pathlib.Path = pathlib.Path()
66-
tags: List[str] = field(default_factory=list)
67+
pragmas: List[str] = field(default_factory=list)
6768

6869

6970
@dataclass
@@ -72,24 +73,38 @@ class Schema:
7273
includes: Set[str] = field(default_factory=set)
7374

7475

75-
def _parse_property(name: str, type: Union[str, Dict[str, str]], is_child: bool = False):
76-
if isinstance(type, dict):
77-
tags = type.get("_tags", [])
78-
type = type["type"]
76+
_StrOrList = Union[str, List[str]]
77+
78+
79+
def _auto_list(data: _StrOrList) -> List[str]:
80+
if isinstance(data, list):
81+
return data
82+
return [data]
83+
84+
85+
def _parse_property(name: str, data: Union[str, Dict[str, _StrOrList]], is_child: bool = False):
86+
if isinstance(data, dict):
87+
if "type" not in data:
88+
raise Error(f"property {name} has no type")
89+
pragmas = _auto_list(data.pop("_pragma", []))
90+
type = data.pop("type")
91+
if data:
92+
raise Error(f"unknown metadata {', '.join(data)} in property {name}")
7993
else:
80-
tags = []
94+
pragmas = []
95+
type = data
8196
if is_child and type[0].islower():
8297
raise Error(f"children must have class type, got {type} for {name}")
8398
if type.endswith("?*"):
84-
return RepeatedOptionalProperty(name, type[:-2], is_child=is_child, tags=tags)
99+
return RepeatedOptionalProperty(name, type[:-2], is_child=is_child, pragmas=pragmas)
85100
elif type.endswith("*"):
86-
return RepeatedProperty(name, type[:-1], is_child=is_child, tags=tags)
101+
return RepeatedProperty(name, type[:-1], is_child=is_child, pragmas=pragmas)
87102
elif type.endswith("?"):
88-
return OptionalProperty(name, type[:-1], is_child=is_child, tags=tags)
103+
return OptionalProperty(name, type[:-1], is_child=is_child, pragmas=pragmas)
89104
elif type == "predicate":
90-
return PredicateProperty(name, tags=tags)
105+
return PredicateProperty(name, pragmas=pragmas)
91106
else:
92-
return SingleProperty(name, type, is_child=is_child, tags=tags)
107+
return SingleProperty(name, type, is_child=is_child, pragmas=pragmas)
93108

94109

95110
class _DirSelector:
@@ -120,17 +135,16 @@ def load(path):
120135
if not k.startswith("_"):
121136
cls.properties.append(_parse_property(k, v))
122137
elif k == "_extends":
123-
if not isinstance(v, list):
124-
v = [v]
138+
v = _auto_list(v)
125139
for base in v:
126140
cls.bases.add(base)
127141
classes[base].derived.add(name)
128142
elif k == "_dir":
129143
cls.dir = pathlib.Path(v)
130144
elif k == "_children":
131145
cls.properties.extend(_parse_property(kk, vv, is_child=True) for kk, vv in v.items())
132-
elif k == "_tags":
133-
cls.tags = v
146+
elif k == "_pragma":
147+
cls.pragmas = _auto_list(v)
134148
else:
135149
raise Error(f"unknown metadata {k} for class {name}")
136150
if not cls.bases and cls.name != root_class_name:

swift/codegen/schema.yml

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -14,22 +14,22 @@ _directories:
1414

1515
Element:
1616
is_unknown: predicate
17-
_tags: [ no_qltest ]
17+
_pragma: skip_qltest
1818

1919
File:
2020
name: string
2121

2222
Locatable:
2323
location: Location?
24-
_tags: [ no_qltest ]
24+
_pragma: skip_qltest
2525

2626
Location:
2727
file: File
2828
start_line: int
2929
start_column: int
3030
end_line: int
3131
end_column: int
32-
_tags: [ no_qltest ]
32+
_pragma: skip_qltest
3333

3434
Type:
3535
diagnostics_name: string
@@ -385,7 +385,7 @@ EnumIsCaseExpr:
385385

386386
ErrorExpr:
387387
_extends: Expr
388-
_tags: [ no_qltest ] # unexpected emission
388+
_pragma: skip_qltest # unexpected emission
389389

390390
ExplicitCastExpr:
391391
_extends: Expr
@@ -460,7 +460,7 @@ ObjCSelectorExpr:
460460
_children:
461461
sub_expr: Expr
462462
method: AbstractFunctionDecl
463-
_tags: [ no_qltest ] # to be tested in integration tests
463+
_pragma: skip_qltest # to be tested in integration tests
464464

465465
OneWayExpr:
466466
_extends: Expr
@@ -502,7 +502,7 @@ SequenceExpr:
502502
_extends: Expr
503503
_children:
504504
elements: Expr*
505-
_tags: [ no_qltest ] # we should really never extract these, as these should be resolved to trees of operations
505+
_pragma: skip_qltest # we should really never extract these, as these should be resolved to trees of operations
506506

507507
SuperRefExpr:
508508
_extends: Expr
@@ -534,7 +534,7 @@ TypeExpr:
534534
UnresolvedDeclRefExpr:
535535
_extends: Expr
536536
name: string?
537-
_tags: [ no_qltest ] # we should really never extract these
537+
_pragma: skip_qltest # we should really never extract these
538538

539539
UnresolvedDotExpr:
540540
_extends: Expr
@@ -545,15 +545,15 @@ UnresolvedDotExpr:
545545
UnresolvedMemberExpr:
546546
_extends: Expr
547547
name: string
548-
_tags: [ no_qltest ] # we should really never extract these
548+
_pragma: skip_qltest # we should really never extract these
549549

550550
UnresolvedPatternExpr:
551551
_extends: Expr
552-
_tags: [ no_qltest ] # we should really never extract these
552+
_pragma: skip_qltest # we should really never extract these
553553

554554
UnresolvedSpecializeExpr:
555555
_extends: Expr
556-
_tags: [ no_qltest ] # we should really never extract these
556+
_pragma: skip_qltest # we should really never extract these
557557

558558
VarargExpansionExpr:
559559
_extends: Expr
@@ -821,11 +821,11 @@ ArrayToPointerExpr:
821821

822822
BridgeFromObjCExpr:
823823
_extends: ImplicitConversionExpr
824-
_tags: [ no_qltest ] # to be tested in integration tests
824+
_pragma: skip_qltest # to be tested in integration tests
825825

826826
BridgeToObjCExpr:
827827
_extends: ImplicitConversionExpr
828-
_tags: [ no_qltest ] # to be tested in integration tests
828+
_pragma: skip_qltest # to be tested in integration tests
829829

830830
ClassMetatypeToObjectExpr:
831831
_extends: ImplicitConversionExpr
@@ -835,7 +835,7 @@ CollectionUpcastConversionExpr:
835835

836836
ConditionalBridgeFromObjCExpr:
837837
_extends: ImplicitConversionExpr
838-
_tags: [ no_qltest ] # to be tested in integration tests
838+
_pragma: skip_qltest # to be tested in integration tests
839839

840840
CovariantFunctionConversionExpr:
841841
_extends: ImplicitConversionExpr

swift/codegen/test/test_qlgen.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -458,13 +458,13 @@ def test_test_properties_skipped(opts, generate_tests):
458458
write(opts.ql_test_output / "Derived" / "test.swift")
459459
assert generate_tests([
460460
schema.Class("Base", derived={"Derived"}, properties=[
461-
schema.SingleProperty("x", "string", tags=["no_qltest", "foo"]),
462-
schema.RepeatedProperty("y", "int", tags=["bar", "no_qltest"]),
461+
schema.SingleProperty("x", "string", pragmas=["skip_qltest", "foo"]),
462+
schema.RepeatedProperty("y", "int", pragmas=["bar", "skip_qltest"]),
463463
]),
464464
schema.Class("Derived", bases={"Base"}, properties=[
465-
schema.PredicateProperty("a", tags=["no_qltest"]),
465+
schema.PredicateProperty("a", pragmas=["skip_qltest"]),
466466
schema.OptionalProperty(
467-
"b", "int", tags=["bar", "no_qltest", "baz"]),
467+
"b", "int", pragmas=["bar", "skip_qltest", "baz"]),
468468
]),
469469
]) == {
470470
"Derived/Derived.ql": ql.ClassTester(class_name="Derived"),
@@ -474,7 +474,7 @@ def test_test_properties_skipped(opts, generate_tests):
474474
def test_test_base_class_skipped(opts, generate_tests):
475475
write(opts.ql_test_output / "Derived" / "test.swift")
476476
assert generate_tests([
477-
schema.Class("Base", derived={"Derived"}, tags=["no_qltest", "foo"], properties=[
477+
schema.Class("Base", derived={"Derived"}, pragmas=["skip_qltest", "foo"], properties=[
478478
schema.SingleProperty("x", "string"),
479479
schema.RepeatedProperty("y", "int"),
480480
]),
@@ -488,7 +488,7 @@ def test_test_final_class_skipped(opts, generate_tests):
488488
write(opts.ql_test_output / "Derived" / "test.swift")
489489
assert generate_tests([
490490
schema.Class("Base", derived={"Derived"}),
491-
schema.Class("Derived", bases={"Base"}, tags=["no_qltest", "foo"], properties=[
491+
schema.Class("Derived", bases={"Base"}, pragmas=["skip_qltest", "foo"], properties=[
492492
schema.SingleProperty("x", "string"),
493493
schema.RepeatedProperty("y", "int"),
494494
]),

swift/codegen/test/test_schema.py

Lines changed: 55 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -217,32 +217,81 @@ def test_property_with_explicit_type(load):
217217
]
218218

219219

220-
def test_property_with_explicit_type_and_tags(load):
220+
def test_property_with_explicit_type_and_pragmas(load):
221221
ret = load("""
222222
A:
223223
x:
224224
type: string*
225-
_tags: [foo, bar]
225+
_pragma: [foo, bar]
226226
""")
227227
assert ret.classes == [
228228
schema.Class(root_name, derived={'A'}),
229229
schema.Class('A', bases={root_name}, properties=[
230-
schema.RepeatedProperty('x', 'string', tags=["foo", "bar"]),
230+
schema.RepeatedProperty('x', 'string', pragmas=["foo", "bar"]),
231231
]),
232232
]
233233

234234

235-
def test_class_with_tags(load):
235+
def test_property_with_explicit_type_and_one_pragma(load):
236+
ret = load("""
237+
A:
238+
x:
239+
type: string*
240+
_pragma: foo
241+
""")
242+
assert ret.classes == [
243+
schema.Class(root_name, derived={'A'}),
244+
schema.Class('A', bases={root_name}, properties=[
245+
schema.RepeatedProperty('x', 'string', pragmas=["foo"]),
246+
]),
247+
]
248+
249+
250+
def test_property_with_explicit_type_and_unknown_metadata(load):
251+
with pytest.raises(schema.Error):
252+
load("""
253+
A:
254+
x:
255+
type: string*
256+
_what_is_this: [foo, bar]
257+
""")
258+
259+
260+
def test_property_with_dict_without_explicit_type(load):
261+
with pytest.raises(schema.Error):
262+
load("""
263+
A:
264+
x:
265+
typo: string*
266+
""")
267+
268+
269+
270+
def test_class_with_pragmas(load):
271+
ret = load("""
272+
A:
273+
x: string*
274+
_pragma: [foo, bar]
275+
""")
276+
assert ret.classes == [
277+
schema.Class(root_name, derived={'A'}),
278+
schema.Class('A', bases={root_name}, properties=[
279+
schema.RepeatedProperty('x', 'string'),
280+
], pragmas=["foo", "bar"]),
281+
]
282+
283+
284+
def test_class_with_one_pragma(load):
236285
ret = load("""
237286
A:
238287
x: string*
239-
_tags: [foo, bar]
288+
_pragma: foo
240289
""")
241290
assert ret.classes == [
242291
schema.Class(root_name, derived={'A'}),
243292
schema.Class('A', bases={root_name}, properties=[
244293
schema.RepeatedProperty('x', 'string'),
245-
], tags=["foo", "bar"]),
294+
], pragmas=["foo"]),
246295
]
247296

248297

0 commit comments

Comments
 (0)