8000 Initial golang implementation · JPEWdev/shacl2code@d89b841 · GitHub
[go: up one dir, main page]

Skip to content

Commit d89b841

Browse files
committed
Initial golang implementation
The initial implementation of the golang binding generation
1 parent f30a3ce commit d89b841

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

62 files changed

+14769
-1
lines changed

src/shacl2code/lang/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,4 @@
1010
from .jinja import JinjaRender # noqa: F401
1111
from .jsonschema import JsonSchemaRender # noqa: F401
1212
from .python import PythonRender # noqa: F401
13+
from .golang import GoLangRender # noqa: F401

src/shacl2code/lang/golang.py

Lines changed: 279 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,279 @@
1+
#
2+
# Copyright (c) 2024 Joshua Watt
3+
#
4+
# SPDX-License-Identifier: MIT
5+
6+
from .common import JinjaTemplateRender
7+
from .lang import language, TEMPLATE_DIR
8+
9+
from pathlib import Path
10+
11+
import re
12+
13+
GO_KEYWORDS = (
14+
"break",
15+
"default",
16+
"func",
17+
"interface",
18+
"select",
19+
"case",
20+
"defer",
21+
"go",
22+
"map",
23+
"struct",
24+
"chan",
25+
"else",
26+
"goto",
27+
"package",
28+
"switch",
29+
"const",
30+
"fallthrough",
31+
"if",
32+
"range",
33+
"type",
34+
"continue",
35+
"for",
36+
"import",
37+
"return",
38+
"var",
39+
)
40+
41+
42+
def varname(*name, public=True):
43+
new_name = []
44+
for n in name:
45+
for s in re.split(r"[^a-zA-Z0-9]+", n):
46+
if not s:
47+
continue
48+
new_name.append(s)
49+
if public:
50+
new_name = [s[0].upper() + s[1:] for s in new_name]
51+
else:
52+
new_name = [new_name[0][0].lower() + new_name[0][1:]] + [
53+
s[0].upper() + s[1:] for s in new_name[1:]
54+
]
55+
new_name = "".join(new_name)
56+
if new_name in GO_KEYWORDS:
57+
new_name = new_name + "_"
58+
return new_name
59+
60+
61+
def struct_name(cls):
62+
return varname(*cls.clsname) + "Object"
63+
64+
65+
def interface_name(cls):
66+
return varname(*cls.clsname)
67+
68+
69+
def class_type_var(cls):
70+
return varname(*cls.clsname, public=False) + "Type"
71+
72+
73+
def prop_name(prop):
74+
return varname(prop.varname, public=False)
75+
76+
77+
def prop_is_list(prop):
78+
return prop.max_count is None or prop.max_count != 1
79+
80+
81+
def prop_go_type(prop, classes):
82+
if prop.enum_values:
83+
return "string"
84+
85+
if prop.class_id:
86+
intf = interface_name(classes.get(prop.class_id))
87+
return f"Ref[{intf}]"
88+
89+
if prop.datatype == "http://www.w3.org/2001/XMLSchema#string":
90+
return "string"
91+
92+
if prop.datatype == "http://www.w3.org/2001/XMLSchema#anyURI":
93+
return "string"
94+
95+
if prop.datatype == "http://www.w3.org/2001/XMLSchema#integer":
96+
return "int"
97+
98+
if prop.datatype == "http://www.w3.org/2001/XMLSchema#positiveInteger":
99+
return "int"
100+
101+
if prop.datatype == "http://www.w3.org/2001/XMLSchema#nonNegativeInteger":
102+
return "int"
103+
104+
if prop.datatype == "http://www.w3.org/2001/XMLSchema#boolean":
105+
return "bool"
106+
107+
if prop.datatype == "http://www.w3.org/2001/XMLSchema#decimal":
108+
return "float64"
109+
110+
if prop.datatype == "http://www.w3.org/2001/XMLSchema#dateTime":
111+
return "time.Time"
112+
113+
if prop.datatype == "http://www.w3.org/2001/XMLSchema#dateTimeStamp":
114+
return "time.Time"
115+
116+
raise Exception("Unknown data type " + prop.datatype) # pragma: no cover
117+
118+
119+
def prop_ctx_name(cls, prop):
120+
return varname(*cls.clsname, public=False) + varname(prop.varname) + "Context"
121+
122+
123+
def prop_decode_func(cls, prop, classes):
124+
if prop.enum_values:
125+
func = "DecodeIRI"
126+
127+
elif prop.class_id:
128+
func = "Decode" + interface_name(classes.get(prop.class_id))
129+
130+
elif prop.datatype == "http://www.w3.org/2001/XMLSchema#string":
131+
func = "DecodeString"
132+
133+
elif prop.datatype == "http://www.w3.org/2001/XMLSchema#anyURI":
134+
func = "DecodeString"
135+
136+
elif prop.datatype == "http://www.w3.org/2001/XMLSchema#integer":
137+
func = "DecodeInteger"
138+
139+
elif prop.datatype == "http://www.w3.org/2001/XMLSchema#positiveInteger":
140+
func = "DecodeInteger"
141+
142+
elif prop.datatype == "http://www.w3.org/2001/XMLSchema#nonNegativeInteger":
143+
func = "DecodeInteger"
144+
145+
elif prop.datatype == "http://www.w3.org/2001/XMLSchema#boolean":
146+
func = "DecodeBoolean"
147+
148+
elif prop.datatype == "http://www.w3.org/2001/XMLSchema#decimal":
149+
func = "DecodeFloat"
150+
151+
elif prop.datatype == "http://www.w3.org/2001/XMLSchema#dateTime":
152+
func = "DecodeDateTime"
153+
154+
elif prop.datatype == "http://www.w3.org/2001/XMLSchema#dateTimeStamp":
155+
func = "DecodeDateTimeStamp"
156+
157+
else:
158+
raise Exception("Unknown data type " + prop.datatype) # pragma: no cover
159+
160+
if prop_is_list(prop):
161+
return f"DecodeList[{prop_go_type(prop, classes)}](value, path, {prop_ctx_name(cls, prop)}, {func}, obj.{varname(prop.varname)}())"
162+
163+
return f"{func}(value, path, {prop_ctx_name(cls, prop)}, obj.{varname(prop.varname)}())"
164+
165+
166+
def prop_encode_func(cls, prop, classes):
167+
if prop.enum_values:
168+
func = "EncodeIRI"
169+
170+
elif prop.class_id:
171+
func = "EncodeRef[" + interface_name(classes.get(prop.class_id)) + "]"
172+
173+
elif prop.datatype == "http://www.w3.org/2001/XMLSchema#string":
174+
func = "EncodeString"
175+
176+
elif prop.datatype == "http://www.w3.org/2001/XMLSchema#anyURI":
177+
func = "EncodeString"
178+
179+
elif prop.datatype == "http://www.w3.org/2001/XMLSchema#integer":
180+
func = "EncodeInteger"
181+
182+
elif prop.datatype == "http://www.w3.org/2001/XMLSchema#positiveInteger":
183+
func = "EncodeInteger"
184+
185+
elif prop.datatype == "http://www.w3.org/2001/XMLSchema#nonNegativeInteger":
186+
func = "EncodeInteger"
187+
188+
elif prop.datatype == "http://www.w3.org/2001/XMLSchema#boolean":
189+
func = "EncodeBoolean"
190+
191+
elif prop.datatype == "http://www.w3.org/2001/XMLSchema#decimal":
192+
func = "EncodeFloat"
193+
194+
elif prop.datatype == "http://www.w3.org/2001/XMLSchema#dateTime":
195+
func = "EncodeDateTime"
196+
197+
elif prop.datatype == "http://www.w3.org/2001/XMLSchema#dateTimeStamp":
198+
func = "EncodeDateTime"
199+
200+
else:
201+
raise Exception("Unknown data type " + prop.datatype) # pragma: no cover
202+
203+
if prop_is_list(prop):
204+
return f'EncodeList[{prop_go_type(prop, classes)}](self.{prop_name(prop)}.Get(), path.PushPath("{prop_name(prop)}"), {prop_ctx_name(cls, prop)}, state, {func})'
205+
206+
return f'{func}(self.{prop_name(prop)}.Get(), path.PushPath("{prop_name(prop)}"), {prop_ctx_name(cls, prop)}, state)'
207+
208+
209+
@language("golang")
210+
class GoLangRender(JinjaTemplateRender):
211+
HELP = "Go Schema"
212+
213+
FILES = (
214+
"classes.go",
215+
"decode.go",
216+
"encode.go",
217+
"errorhandler.go",
218+
"errors.go",
219+
"extensible.go",
220+
"linkstate.go",
221+
"listproperty.go",
222+
"optional.go",
223+
"path.go",
224+
"property.go",
225+
"ref.go",
226+
"reflistproperty.go",
227+
"refproperty.go",
228+
"shaclobject.go",
229+
"shaclobjectset.go",
230+
"shacltype.go",
231+
"util.go",
232+
"validator.go",
233+
)
234+
235+
def __init__(self, args):
236+
super().__init__()
237+
self.__output = args.output
238+
self.__render_args = {
239+
"package": args.package,
240+
}
241+
242+
@classmethod
243+
def get_arguments(cls, parser):
244+
parser.add_argument(
245+
"-p",
246+
"--package",
247+
help="Go Package Name",
248+
default="model",
249+
)
250+
parser.add_argument(
251+
"--output",
252+
"-o",
253+
type=Path,
254+
help="Output directory",
255+
required=True,
256+
)
257+
258+
def get_outputs(self):
259+
t = TEMPLATE_DIR / "golang"
260+
261+
for s in self.FILES:
262+
yield self.__output / s, t / (s + ".j2"), {}
263+
264+
def get_extra_env(self):
265+
return {
266+
"varname": varname,
267+
"struct_name": struct_name,
268+
"interface_name": interface_name,
269+
"class_type_var": class_type_var,
270+
"prop_name": prop_name,
271+
"prop_is_list": prop_is_list,
272+
"prop_go_type": prop_go_type,
273+
"prop_ctx_name": prop_ctx_name,
274+
"prop_decode_func": prop_decode_func,
275+
"prop_encode_func": prop_encode_func,
276+
}
277+
278+
def get_additional_render_args(self):
279+
return self.__render_args

0 commit comments

Comments
 (0)
0