8000 Add Go Bindings generation by nishakm · Pull Request #9 · JPEWdev/shacl2code · GitHub
[go: up one dir, main page]

Skip to content

Add Go Bindings generation #9

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

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from 1 commit
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
Prev Previous commit
Updates: abstract vs concrete
- Use the golang.py DATATYPES instead of the one in the jinja
  template.
- Organized the macros.
- Added checks for abstract vs concrete classes

Signed-off-by: Nisha Kumar <nisha.kumar@oracle.com>
  • Loading branch information
nishakm committed May 22, 2024
commit 25404807d6e943132f720b42bd74656e0b4a37ba
75 changes: 30 additions & 45 deletions src/shacl2code/lang/golang.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,42 +20,37 @@
"http://www.w3.org/2001/XMLSchema#dateTimeStamp": "DateTimeStamp",
}

RESERVED_WORDS = {
"package"
}

def export(name):
# export converts the shacl name into an exportable go type name
name_list = name.split('_')
for i in range(0,len(name_list)):
name_list[i] = name_list[i][0].upper() + name_list[i][1:]
return ''.join(name_list)
def upper_first(string):
# upper_first will capitalize the string
return string[0].upper() + string[1:]


def lower_first(string):
# lower_first sets the first character of a string to lower case
return string[0].lower() + string[1:]

def type_name(name):
parts = re.split(r'[^a-zA-Z0-9]', name)
part = parts[len(parts)-1]
return upper_first(part)

def type_name(clsname):
# type_name converts the class name into an exportable go type name
return upper_first(''.join(clsname).replace('_',''))

def struct_prop_name(prop):
# prop:
# class_id, comment, datatype, enum_values, max_count, min_count, path, pattern, varname
return lower_first(type_name(prop.varname))

def interface_method(propname):
# returns an interface method name
# The interface method names are capitalized so they can be exported
parts = propname.split('_')
parts[0] = upper_first(parts[0])
return ''.join(parts)

def prop_type(prop):
# prop:
# class_id, comment, datatype, enum_values, max_count, min_count, path, pattern, varname
if prop.datatype in DATATYPES:
typ = DATATYPES[prop.datatype]
else:
typ = type_name(prop.class_id)
def struct_name(clsname):
# Go structs are only used when a class is a concrete class
return lower_first(type_name(clsname)) + "Impl"

if prop.max_count is None or prop.max_count > 1:
typ = '[]' + typ

return typ
def struct_prop_name(propname):
# All properties in a Go struct are non-exportable
return propname.replace('_','')


def setter_prop_type(prop):
Expand All @@ -68,21 +63,21 @@ def struct_prop(prop):


def interface_getter(prop):
return upper_first(type_name(prop.varname)) + '() ' + prop_type(prop)
return type_name(prop.varname) + '() ' + prop_type(prop)


def interface_setter(prop):
return "Set" + upper_first(type_name(prop.varname)) + '(' + setter_prop_type(prop) + ') error'
return "Set" + type_name(prop.varname) + '(' + setter_prop_type(prop) + ') error'


def struct_getter(cls, prop):
return 'func (o *' + struct_name(cls) + ') ' + upper_first(type_name(prop.varname)) + '() ' + prop_type(prop) + '{\n' \
return 'func (o *' + struct_name(cls) + ') ' + type_name(prop.varname) + '() ' + prop_type(prop) + '{\n' \
+ ' return o.' + struct_prop_name(prop) + '\n' \
+ '}'


def struct_setter(cls, prop):
return 'func (o *' + struct_name(cls) + ') Set' + upper_first(type_name(prop.varname)) + '(v ' + setter_prop_type(prop) + ') error{\n' \
return 'func (o *' + struct_name(cls) + ') Set' + type_name(prop.varname) + '(v ' + setter_prop_type(prop) + ') error{\n' \
+ ' o.' + struct_prop_name(prop) + ' = v\n' \
+ ' return nil\n' \
+ '}'
Expand Down Expand Up @@ -110,23 +105,12 @@ def include_prop(classes, cls, prop):
return not parent_has_prop(classes, cls, prop)


def lower_first(str):
return str[0].lower() + str[1:]


def interface_name(cls):
return upper_first(type_name(cls.clsname))


def struct_name(cls):
name = lower_first(type_name(cls.clsname))
if name in RESERVED_WORDS:
return name + "Impl"
return name
return type_name(cls.clsname)


def upper_first(str):
return str[0].upper() + str[1:]


def indent(indent_with, str):
Expand All @@ -151,9 +135,9 @@ def get_arguments(cls, parser):

def get_extra_env(self):
return {
"export": export,
"type_name": type_name,
"struct_prop": struct_prop,
"interface_method": interface_method,
"struct_prop_name": struct_prop_name,
"struct_name": struct_name,
"struct_getter": struct_getter,
"struct_setter": struct_setter,
Expand All @@ -163,6 +147,7 @@ def get_extra_env(self):
"include_prop": include_prop,
"indent": indent,
"comment": comment,
"DATATYPES": DATATYPES,
}

def get_additional_render_args(self):
Expand Down
182 changes: 69 additions & 113 deletions src/shacl2code/lang/templates/golang.j2
Original file line number Diff line number Diff line change
Expand Up @@ -9,155 +9,111 @@
{%- macro array(prop) %}
{%- if prop.max_count and prop.max_count >= 1 -%}
[]
{%- endif %}
{%- endif -%}
{%- endmacro %}

{%- macro struct_props(class) %}
{%- for parent in class.parent_ids %}
{{ struct_props(classes.get(parent)) }}
{%- endfor %}

// ---------- {{ type_name(class.clsname) }} --------
{%- for prop in class.properties %}
{%- if include_prop(classes,class,prop) %}
{{ struct_prop(prop) }}
{%- endif %}
{%- endfor %}
{%- macro many(prop) %}
{%- if prop.max_count and prop.max_count >= 1 -%}
...
{%- endif -%}
{%- endmacro %}

{%- macro struct_funcs(base,class) %}
{%- for parent in class.parent_ids %}
{{ struct_funcs(base,classes.get(parent)) }}
{%- endfor %}

// ---------- {{ type_name(class.clsname) }} --------
{%- for prop in class.properties %}
{%- if include_prop(classes,class,prop) %}

{{ struct_getter(base,prop) }}

{{ struct_setter(base,prop) }}
{%- macro prop_type(prop) %}
{%- if prop.class_id -%}
{{ type_name(classes.get(prop.class_id).clsname) }}
{%- else -%}
{{ DATATYPES[prop.datatype] }}
{%- endif %}
{%- endfor %}
{%- endmacro %}

{%- macro interface_props(class) -%}
{%- for parent in class.parent_ids %}
{{ interface_name(classes.get(parent)) }}
{%- endfor %}

{%- for prop in class.properties %}
{%- if include_prop(classes,class,prop) %}

{{ comment(" // ", struct_prop(prop), prop.comment) }}
{{ interface_getter(prop) }}
{%- macro namedind(class) %}
type {{ type_name(class.clsname) }} struct {
ObjRef {{ type_name(class.clsname) }}Ref
}
{%- endmacro %}

{{ interface_setter(prop) }}
< 8000 /td> {%- endif %}
{%- endfor %}
{%- macro interface(class) %}
type {{ type_name(class.clsname) }} interface {
{% for parent in class.parent_ids %}
{{ type_name(classes.get(parent).clsname) }}
{% endfor %}
{% for prop in class.properties %}
{{ interface_method(prop.varname) }}() {{ array(prop) }}{{ prop_type(prop) }}
Set{{ interface_method(prop.varname) }}(p {{ many(prop) }}{{ prop_type(prop) }}) error
{% endfor %}
}
{%- endmacro %}

{%- macro interface_constructor(class) %}
func New{{ interface_name(class) }}() {{ interface_name(class) }} {
return &{{ struct_name(class) }}{}
{%- macro struct(class) %}
type {{ struct_name(class.clsname) }} struct {
{% for parent in class.parent_ids %}
//-----------{{ type_name(classes.get(parent).clsname) }}--------
{% for prop in classes.get(parent).properties %}
{{ struct_prop_name(prop.varname) }} {{ array(prop) }}{{ prop_type(prop) }}
{% endfor %}
{% endfor %}
{% if not class.named_individuals %}
{% for prop in class.properties %}
{{ struct_prop_name(prop.varname) }} {{ array(prop) }}{{ prop_type(prop) }}
{% endfor %}
{% endif %}
}
{%- endmacro %}

{%- macro datatype(prop) %}
{%- if prop.class_id -%}
{{ export(classes.get(prop.class_id).clsname) }}
{%- else -%}
{{ DATATYPES[prop.datatype] }}
{%- endif %}
{%- macro constructor(class) %}
func New{{ type_name(class.clsname) }}() {{ type_name(class.clsname) }} {
return &{{ struct_name(class.clsname) }}{}
}
{%- endmacro %}

{%- macro interface(class) -%}
type {{ export(class.clsname) }} interface {
{%- macro func(class) %}
{%- for prop in class.properties %}
{{ export(prop.varname) }}() {{ array(prop) }}{{ datatype(prop) }}
{%- endfor %}
func (o * {{ type_name(class.clsname) }}) {{ interface_method(prop.varname) }}() {{ prop_type(prop) }}{
return o.{{ struct_prop_name(prop.varname) }}
}
{% endmacro %}

{%- macro struct(class) -%}
type {{ export(class.clsname) }} struct {
{%- for prop in class.properties %}
func (o *{{ type_name(class.clsname) }}) Set{{ interface_method(prop.varname) }}(v {{ prop_type(prop) }}) error {
o.{{ struct_prop_name(prop.varname) }} = v
return nil
}
{%- endfor %}
{%- endmacro %}

{# go file content #}
package spdx_v{{ module }}
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

package {{ module }}

Remember that shacl2code is not (intended) to be specific to SPDX :)


// XSD types that don't have a Go equivalent
type PInt uint

func (p PInt) Check() PInt {
if p == 0 {
panic("0 Assignment not allowed for PInt")
}
return p
}

type DateTime string

type DateTimeStamp string

// Named Individuals handling
// NAMED INDIVIDUALS

{%- for class in classes %}
{%- if class.named_individuals %}

type {{ type_name(class.clsname) }} string
type {{ type_name(class.clsname) }}Ref string
var (
{%- for ind in class.named_individuals %}
{{ type_name(class.clsname) }}{{ type_name(ind.varname) }} {{ type_name(class.clsname) }} = "{{ ind._id }}"
{{ type_name(class.clsname) }}{{ ind.varname }} {{ type_name(class.clsname) }}Ref = "{{ ind._id }}"
{%- endfor %}
)
{%- endif %}
{%- endfor %}

{% set
DATATYPES = {
"http://www.w3.org/2001/XMLSchema#string": "string",
"http://www.w3.org/2001/XMLSchema#anyURI": "string",
"http://www.w3.org/2001/XMLSchema#integer": "int",
"http://www.w3.org/2001/XMLSchema#positiveInteger": "PInt",
"http://www.w3.org/2001/XMLSchema#nonNegativeInteger": "uint",
"http://www.w3.org/2001/XMLSchema#boolean": "bool",
"http://www.w3.org/2001/XMLSchema#decimal": "float64",
"http://www.w3.org/2001/XMLSchema#dateTime": "DateTime",
"http://www.w3.org/2001/XMLSchema#dateTimeStamp": "DateTimeStamp",
}
%}
// INTERFACES

{#var CONTEXT_URLS [{{ context.urls|length }}]string = [{{ context.urls|length }}]string{#}
{# {%- for url in context.urls %}"{{ url }}"{{ ',' if not loop.last }}{%- endfor %}}#}
{##}
{#// CLASSES AND INTERFACES#}
{% for class in classes %}
{% if class.named_individuals %}
{{ namedind(class) }}
{% else %}
{{ interface(class) }}
{% endif %}
{% endfor %}

{%- for class in classes %}
{%- if not class.named_individuals %}
type {{ interface_name(class) }} interface {
{{ interface_props(class) }}
}
{%- if not class.is_abstract %}

type {{ struct_name(class) }} struct {
{#- {%- if class.parent_ids %}#}
{#- {%- for parent in class.parent_ids %}#}
{#- {{ export(classes.get(parent).clsname) }}#}
{#- {%- endfor %}#}
{#- {%- endif %}#}
{{ struct_props(class) }}
{#- {%- if class.named_individuals %}#}
{#- ObjectRef {{ export(class.clsname) }}Ref#}
{#- {%- endif %}#}
}
// STRUCTS AND CONSTRUCTORS

{{ interface_constructor(class) }}
{% for class in concrete_classes %}
{{ struct(class) }}
{{ constructor(class) }}
{% endfor %}

{{ struct_funcs(class,class) }}
{%- endif %}
{%- endif %}
{%- endfor %}
// IMPLEMENTATIONS

{% for class in concrete_classes %}
{{ func(class) }}
{% endfor %}
0