22
33import pathlib
44import re
5+ import typing
56from dataclasses import dataclass , field
67from typing import List , Set , Union , Dict , ClassVar
78
1112class Error (Exception ):
1213
1314 def __str__ (self ):
14- return f"schema.Error { args } "
15+ return self . args [ 0 ]
1516
1617
1718root_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
95110class _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 :
0 commit comments