Skip to content

Commit

Permalink
Merge pull request #39 from agerlach/julia
Browse files Browse the repository at this point in the history
Julia Support
  • Loading branch information
VVCAS-Sean committed Feb 13, 2024
2 parents ae2d47b + af9be17 commit 0d6e13f
Show file tree
Hide file tree
Showing 23 changed files with 1,531 additions and 1 deletion.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ specification of LMCP. Currently, *LmcpGen* creates libraries for the following
- C++
- C#
- Python
- Julia

Additionally, *LmcpGen* can create HTML documentation in the form of an easy-to-navigate webpage for viewing the
messages described in source MDMs.
Expand Down Expand Up @@ -72,6 +73,7 @@ command line options are as follows:
- `-cpp` Adds proper template and method name for C++ output. Note: creates c++11 compatible code.
- `-cs` Adds proper template and method name for C# output.
- `-py` Adds proper template and method name for Python output.
- `-jl` Adds proper template and method name for Julia output.
- `-xsd` Adds proper template and method name for XML schema output.
- `-doc` Adds proper template and method name for documentation output.
- `-dir <directory path>` path to the directory where files are to be written.
Expand Down
647 changes: 647 additions & 0 deletions src/avtas/lmcp/lmcpgen/JuliaMethods.java

Large diffs are not rendered by default.

6 changes: 6 additions & 0 deletions src/avtas/lmcp/lmcpgen/LmcpGen.java
Original file line number Diff line number Diff line change
Expand Up @@ -330,6 +330,11 @@ else if (args[i].equalsIgnoreCase("-ada")) {
methodClassName = "avtas.lmcp.lmcpgen.AdaMethods";
i -= 1;
}
else if (args[i].equalsIgnoreCase("-jl")) {
template = LmcpGen.class.getResource("/templates/julia.tl");
methodClassName = "avtas.lmcp.lmcpgen.JuliaMethods";
i -= 1;
}
else if (args[i].equalsIgnoreCase("-xsd")) {
template = LmcpGen.class.getResource("/templates/xsd.tl");
methodClassName = "avtas.lmcp.lmcpgen.XsdMethods";
Expand Down Expand Up @@ -407,6 +412,7 @@ private static String getHelpString() {
buf.append("-cs Adds proper template and method name for C# output.\n\n");
buf.append("-py Adds proper template and method name for Python output.\n\n");
buf.append("-aadl Adds proper template and method name for AADL output.\n\n");
buf.append("-jl Adds proper template and method name for Julia output.\n\n");
buf.append("-xsd Adds proper template and method name for XML schema output.\n\n");
buf.append("-doc Adds proper template and method name for documentation output.\n\n");
buf.append("-dir <directory path> path to the directory where files are to be written\n");
Expand Down
2 changes: 2 additions & 0 deletions src/avtas/lmcp/lmcpgen/LmcpGenGUI.java
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,8 @@ public class LmcpGenGUI {
JCheckBox htmlBox = new JCheckBox("Docs");
JCheckBox pythonBox = new JCheckBox("Python");
JCheckBox adaBox = new JCheckBox("Ada");
JCheckBox juliaBox = new JCheckBox("Julia");

JCheckBox customBox = new JCheckBox("Custom Language");
MDMInfo[] infos = null;
File outputDir = null;
Expand Down
2 changes: 1 addition & 1 deletion src/avtas/lmcp/lmcpgen/MDMReader.java
Original file line number Diff line number Diff line change
Expand Up @@ -350,7 +350,7 @@ else if (isEnum(f.type, f.seriesName, infos)) {
for (StructInfo s : info.structs) {
info.mdmDependencies.add(s.extends_series);
for (int i = 0; i < s.fields.length; i++) {
if (s.fields[i].isStruct) {
if (s.fields[i].isStruct || s.fields[i].isEnum) {
info.mdmDependencies.add(s.fields[i].seriesName);
}
}
Expand Down
1 change: 1 addition & 0 deletions src/avtas/lmcp/lmcpgen/gui_setup.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
<Package DisplayName="Python" TemplateListing="/templates/python.tl" MethodsClass="avtas.lmcp.lmcpgen.PythonMethods" SubFolder="py"/>
<Package DisplayName="Rust" TemplateListing="/templates/rust.tl" MethodsClass="avtas.lmcp.lmcpgen.RustMethods" SubFolder="rust"/>
<Package DisplayName="Ada" TemplateListing="/templates/ada.tl" MethodsClass="avtas.lmcp.lmcpgen.AdaMethods" SubFolder="ada"/>
<Package DisplayName="Julia" TemplateListing="/templates/julia.tl" MethodsClass="avtas.lmcp.lmcpgen.JuliaMethods" SubFolder="julia"/>
<Package DisplayName="Docs" TemplateListing="/templates/doc.tl" MethodsClass="avtas.lmcp.lmcpgen.DocMethods" SubFolder="doc"/>
<Package DisplayName="XML Schema" TemplateListing="/templates/xsd.tl" MethodsClass="avtas.lmcp.lmcpgen.XsdMethods" SubFolder="xsd"/>
<Package DisplayName="AADL" TemplateListing="/templates/aadl.tl" MethodsClass="avtas.lmcp.lmcpgen.AadlMethods" SubFolder="aadl"/>
Expand Down
22 changes: 22 additions & 0 deletions src/templates/julia.tl
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@

# Julia template listing



ONCE julia/lmcp.jl LMCP/src/LMCP.jl
ONCE julia/Project.toml LMCP/Project.toml
ONCE julia/AbstractLmcpMessage.jl LMCP/src/AbstractLmcpMessage.jl
ONCE julia/LMCPFactory.jl LMCP/src/LMCPFactory.jl
ONCE julia/precompilePack.jl LMCP/src/precompilePack.jl
ONCE julia/precompileXML.jl LMCP/src/precompileXML.jl
ONCE julia/LmcpServer.jl LMCP/test/LmcpServer.jl
ONCE julia/LmcpClient.jl LMCP/test/LmcpClient.jl
ONCE julia/JavaConnection.jl LMCP/test/JavaConnection.jl
ONCE julia/Readme.html LMCP/JuliaReadme.html
ONCE julia/installToRegistry.sh installToRegistry.sh
ONCE julia/runtests.jl LMCP/test/runtests.jl
ONCE julia/test_project.toml LMCP/test/Project.toml

PER_STRUCT julia/SeriesStruct.jl LMCP/src/-<series_dir>-/-<classname>-.jl
PER_ENUM julia/enum.jl LMCP/src/-<series_dir>-/-<enum_name>-Module.jl
PER_MDM julia/module.jl LMCP/src/-<series_dir>-/-<series_name>-.jl
261 changes: 261 additions & 0 deletions src/templates/julia/AbstractLmcpMessage.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,261 @@
## ===============================================================================
## Authors: AFRL/RQQA
## Organization: Air Force Research Laboratory, Aerospace Systems Directorate, Power and Control Division
##
## Copyright (c) 2017 Government of the United State of America, as represented by
## the Secretary of the Air Force. No copyright is claimed in the United States under
## Title 17, U.S. Code. All Other Rights Reserved.
## ===============================================================================

## This file was auto-created by LmcpGen. Modifications will be overwritten.

abstract type AbstractLmcpMessage end

function ==(a::T, b::T) where {T <: AbstractLmcpMessage}
names = fieldnames(T)
for name names
getfield(a, name) == getfield(b, name) ? nothing : return false
end
return true
end


full_lmcp_type_name(::Type{T}) where T <: AbstractLmcpMessage = "Lmcp"
full_lmcp_type_name(::T) where T <: AbstractLmcpMessage = full_lmcp_type_name(T)

lmcp_type(::Type{T}) where T <: AbstractLmcpMessage = "abstract"
lmcp_type(::T) where T <: AbstractLmcpMessage = lmcp_type(T)

lmcp_type_id(::Type{T}) where T <: AbstractLmcpMessage = UInt32(0)
lmcp_type_id(::T) where T <: AbstractLmcpMessage = lmcp_type_id(T)

series_name(::Type{T}) where T <: AbstractLmcpMessage = "ABSTRACT"
series_name(::T) where T <: AbstractLmcpMessage = series_name(T)

series_name_id(::Type{T}) where T <: AbstractLmcpMessage = Int64(0)
series_name_id(::T) where T <: AbstractLmcpMessage = series_name_id(T)

series_version(::Type{T}) where T <: AbstractLmcpMessage = UInt16(0)
series_version(::T) where T <: AbstractLmcpMessage = series_version(T)



function _write(io::IO, o)
write(io, hton(o))
end

function _write(io::IO, o::Enum)
_write(io, Int32(o))
end

function _write(io::IO, ::Nothing)
_write(io, false)
end

function _write(io::IO, o::String)
_write(io, UInt16(length(o))) + #length
write(io, o) #contents
end

function _write(io::IO, o::Vector, ltype::Type{T}=UInt16) where T<:Union{UInt16, UInt32}
bytes = _write(io, T(length(o)))
for i in o
bytes += _write(io, i)
end
return bytes
end

_write(io::IO, o::AbstractLmcpMessage) = write(io, o) #Forward to high level write
function write(io::IO, o::T) where T <: AbstractLmcpMessage

#write header
bytes = _write(io, true)
bytes += _write(io, series_name_id(T))
bytes += _write(io, lmcp_type_id(T))
bytes += _write(io, series_version(T))

# loop through all fields and write
for field in fieldnames(T)
if (T, field) in LARGE_ARRAY_REGISTRY
bytes += _write(io, getfield(o, field), UInt32)
continue
end
bytes += _write(io, getfield(o, field))
end

return bytes
end


function _read(io::IO, o)
ntoh(read(io, o))
end

function _read(io::IO, ::Type{String})
l = _read(io, UInt16)
String(read(io, l))
end

function _read(io::IO, ::Type{Vector{T}}, ltype::Type{T2}=UInt16) where {T, T2<:Union{UInt16, UInt32}}
l = _read(io, T2)
vec = T[]
sizehint!(vec, l)
for i 1:l
push!(vec, _read(io, T))
end
return vec
end

function _read(io::IO, ::Type{T}) where T <: Enum
T(_read(io, Int32)) # read as Int32 then conveert to Enum type T
end

read(io::IO, t::Type{AbstractLmcpMessage}) = _read(io, t) #Forward to high level read
function _read(io::IO, ::Type{Union{T, Nothing}}) where T <: AbstractLmcpMessage

# check if exists
exists = _read(io, Bool)
if !exists return nothing end

series_name = _read(io, Int64)
object_type = _read(io, UInt32)
series_version = _read(io, UInt16)

T2 = OBJECT_ID_REGISTRY[(series_name, object_type)]

_read(io, T2; skip_header = true) # skip header for message since already read
end


function _read(io::IO, ::Type{T}; skip_header = false) where T <: AbstractLmcpMessage
type = T
if !skip_header
exists = _read(io, Bool)
series_name = _read(io, Int64)
object_type = _read(io, UInt32)
series_version = _read(io, UInt16)
type = OBJECT_ID_REGISTRY[(series_name, object_type)]
end

values = map(fieldnames(type), fieldtypes(type)) do n, t
if (type, n) in LARGE_ARRAY_REGISTRY
v = _read(io, t, UInt32)
return v
end
v = _read(io, t)
v
end

type(values...)
end


function _toLmcpType(t::Type)
if t == Bool return "bool" end
if t == String return "string" end
if t == UInt8 return "byte" end
if t == Char return "char"end
if t == Float64 return "real64" end
if t == Float32 return "float32" end
if t == Int64 return "int64" end
if t == Int32 return "int32" end
if t == Int16 return "int16" end
if t == UInt32 return "uint32" end
if t == UInt16 return "uint16" end
if t <: AbstractLmcpMessage return lmcp_type(t) end
return "LMCPObject"
end

function _to_xml(xroot::LightXML.AbstractXMLNode, o)
LightXML.add_text(xroot, string(o))
return xroot
end

function _to_xml(xroot::LightXML.AbstractXMLNode, o::Type{T}) where T <: Enum
LightXML.add_text(xroot, string(Symbol(o)))
end

function _to_xml(xroot::LightXML.AbstractXMLNode, vector::Vector)
for v in vector
tmpChild = LightXML.new_child(xroot, _toLmcpType(typeof(v)))
if typeof(v) <: AbstractLmcpMessage
_to_xml(tmpChild, v)
else
LightXML.add_text(tmpChild, string(v))
end
end
return xroot
end

function _to_xml(xroot::LightXML.AbstractXMLNode, o::Nothing)
return xroot
end


function _to_xml(xroot::LightXML.AbstractXMLNode, o::T) where T <: AbstractLmcpMessage
LightXML.set_attribute(xroot, "Series", series_name(T))
type = typeof(o)
for (n, t) in zip(fieldnames(type), fieldtypes(type))
value = getproperty(o, n)
if isnothing(value) continue end
child = LightXML.new_child(xroot, string(n))
if t <: AbstractLmcpMessage || Nothing <: t #check if inner LMCP object
child = LightXML.new_child(child, lmcp_type(value))
end
_to_xml(child, getproperty(o, n))
end
return xroot
end


function _from_xml(xroot::LightXML.AbstractXMLNode, o::Type{T}) where T <: Number
text = LightXML.content(xroot)
return parse(T, text)
end

function _from_xml(xroot::LightXML.AbstractXMLNode, ::Type{String})
text = LightXML.content(xroot)
return text
end

function _from_xml(xroot::LightXML.AbstractXMLNode, ::Type{Vector{T}}) where T
vec = T[]
memberName = LightXML.child_elements(xroot)
for subChild in memberName
push!(vec, _from_xml(subChild, T))
end
return vec
end

function _from_xml(xroot::LightXML.AbstractXMLNode, ::Type{T}) where T <: Enum
text = LightXML.content(xroot)
return T(text)
end

function _from_xml(xroot::LightXML.AbstractXMLNode, o::Type{T}) where T <: AbstractLmcpMessage
lmcpNode = LightXML.has_attribute(xroot, "Series") ? xroot : collect(LightXML.child_elements(xroot))[1]
name = LightXML.name(lmcpNode)
series = LightXML.attribute(lmcpNode, "Series", required=true)
obj = TEXT_CREATION_REGISTRY[(series, name)]()
return _from_xml(lmcpNode, obj)
end

function _from_xml(xroot::LightXML.AbstractXMLNode, o::Type{Union{T, Nothing}}) where T <: AbstractLmcpMessage
lmcpNode = LightXML.has_attribute(xroot, "Series") ? xroot : collect(LightXML.child_elements(xroot))[1]
name = LightXML.name(lmcpNode)
series = LightXML.attribute(lmcpNode, "Series", required=true)

obj = TEXT_CREATION_REGISTRY[(series, name)]()
return _from_xml(lmcpNode, obj)
end

function _from_xml(xroot::LightXML.AbstractXMLNode, o::AbstractLmcpMessage)
type = typeof(o)
for (n, t) in zip(fieldnames(type), fieldtypes(type))
children = xroot[string(n)]
if length(children) == 0 continue end
value = _from_xml(children[1], t)
setproperty!(o, n, value)
end
return o
end
Loading

0 comments on commit 0d6e13f

Please sign in to comment.