Skip to content
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

C-Language: Templates based property methods #100

Merged
merged 3 commits into from
Jun 20, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
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
98 changes: 84 additions & 14 deletions languages/c/Types.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@

import deepmerge from 'deepmerge'
import { getPath } from '../../src/shared/json-schema.mjs'
import { getTypeName, getModuleName, description, getObjectHandleManagement, getNativeType, getPropertyAccessors, capitalize, isOptional, generateEnum, getMapAccessors, getArrayAccessors, getArrayElementSchema } from './src/types/NativeHelpers.mjs'
import { getArrayAccessorsImpl, getMapAccessorsImpl, getObjectHandleManagementImpl, getPropertyAccessorsImpl } from './src/types/ImplHelpers.mjs'
import { getTypeName, getModuleName, description, getObjectHandleManagement, getNativeType, getPropertyAccessors, capitalize, isOptional, generateEnum, getMapAccessors, getArrayAccessors, getArrayElementSchema, getPropertyGetterSignature, getPropertyEventCallbackSignature, getPropertyEventRegisterSignature, getPropertyEventUnregisterSignature, getPropertySetterSignature } from './src/types/NativeHelpers.mjs'
import { getArrayAccessorsImpl, getMapAccessorsImpl, getObjectHandleManagementImpl, getParameterInstantiation, getPropertyAccessorsImpl, getResultInstantiation } from './src/types/ImplHelpers.mjs'
import { getJsonContainerDefinition, getJsonDataStructName } from './src/types/JSONHelpers.mjs'

const getSdkNameSpace = () => 'FireboltSDK'
Expand Down Expand Up @@ -166,33 +166,65 @@ const deepMergeAll = (module, name, schema, schemas, options) => {

return union
}
const hasTag = (method, tag) => {
return method.tags && method.tags.filter(t => t.name === tag).length > 0
}

function getMethodSignature(method, module, { destination, isInterface = false }) {
const extraParam = '${method.result.type}* ${method.result.name}'

const prefix = method.tags.find(t => t.name.split(":")[0] === "property") ? "Get" : ""
let signature = ''
let paramList = []
if(hasTag(method, 'property') || hasTag(method, 'property:readonly') || hasTag(method, 'property:immutable')) {

method.params.map(param => {
/*
paramList = [{name='', nativeType='', jsonType='', required=boolean}]
*/
paramList['nativeType'] = getSchemaType(param.schema, module, { title: true, name: param.name })
paramList['jsonType'] = getJsonType(param.schema, module, {name: param.name})
paramList['name'] = param.name
paramList['required'] = param.required

})

return 'uint32_t ${info.title}_' + prefix + '${method.Name}(' + extraParam + ')'
let resultType = method.result && getSchemaType(method.result.schema, module, { title: true, name: method.result.name, resultSchema: true}) || ''

signature = getPropertyGetterSignature(method, module, resultType, paramList) + ';\n\n'

if(hasTag(method, 'property') || hasTag(method, 'property:readonly')) {
signature += getPropertyEventCallbackSignature(method, module, resultType, paramList) + ';\n\n'
signature += getPropertyEventRegisterSignature(method, module, paramList) + ';\n\n'
signature += getPropertyEventUnregisterSignature(method, module) + ';\n\n'
}

if(hasTag(method, 'property')) {
signature += getPropertySetterSignature(method, module, resultType, paramList) + ';\n\n'
}
}
return signature
}


function getMethodSignatureParams(method, module, { destination }) {

return method.params.map(param => param.name + (!param.required ? '?' : '') + ': ' + getSchemaType(param.schema, module, { name: param.name, title: true, destination })).join(', ')
return method.params.map(param => getSchemaType(param.schema, module, { name: param.name, title: true, destination }) + (!param.required ? '* ' : ' ') + param.name ).join(', ')
}

const safeName = prop => prop.match(/[.+]/) ? '"' + prop + '"' : prop

function getSchemaType(schema, module, { name, prefix = '', destination, link = false, title = false, code = false, asPath = false, event = false, expandEnums = true, baseUrl = '' } = {}) {
let info = getSchemaTypeInfo(module, schema, name, module['x-schemas'], prefix, { title: title })
function getSchemaType(schema, module, { name, prefix = '', destination, resultSchema = false, link = false, title = false, code = false, asPath = false, event = false, expandEnums = true, baseUrl = '' } = {}) {
let info = getSchemaTypeInfo(module, schema, name, module['x-schemas'], prefix, { title: title, resultSchema: resultSchema, event: event })
return info.type
}

function getSchemaTypeInfo(module = {}, json = {}, name = '', schemas = {}, prefix = '', options = {level: 0, descriptions: true, title: false}) {
function getSchemaTypeInfo(module = {}, json = {}, name = '', schemas = {}, prefix = '', options = {level: 0, descriptions: true, title: false, resultSchema: false, event: false}) {

if (json.schema) {
json = json.schema
}

let stringAsHandle = options.resultSchema || options.event

let structure = {}
structure["type"] = ''
structure["json"] = []
Expand All @@ -219,7 +251,7 @@ function getSchemaTypeInfo(module = {}, json = {}, name = '', schemas = {}, pref
}
}
else if (json.const) {
structure.type = getNativeType(json)
structure.type = getNativeType(json, stringAsHandle)
structure.json = json
return structure
}
Expand All @@ -240,7 +272,9 @@ function getSchemaTypeInfo(module = {}, json = {}, name = '', schemas = {}, pref
}
else if (Array.isArray(json.type)) {
let type = json.type.find(t => t !== 'null')
console.log(`WARNING UNHANDLED: type is an array containing ${json.type}`)
let sch = JSON.parse(JSON.stringify(json))
sch.type = type
return getSchemaTypeInfo(module, sch, name, schemas, prefix, options)
}
else if (json.type === 'array' && json.items && (validJsonObjectProperties(json) === true)) {
let res = ''
Expand Down Expand Up @@ -300,7 +334,7 @@ function getSchemaTypeInfo(module = {}, json = {}, name = '', schemas = {}, pref
return structure
}
else if (json.type) {
structure.type = getNativeType(json)
structure.type = getNativeType(json, stringAsHandle)
structure.json = json
if (name || json.title) {
structure.name = capitalize(name || json.title)
Expand Down Expand Up @@ -534,6 +568,9 @@ const getJsonNativeType = json => {
else if (jsonType === 'boolean') {
type = 'WPEFramework::Core::JSON::Boolean'
}
else if (jsonType === 'null') {
type = 'void'
}
else {
throw 'Unknown JSON Native Type !!!'
}
Expand Down Expand Up @@ -601,7 +638,9 @@ function getJsonTypeInfo(module = {}, json = {}, name = '', schemas, prefix = ''
}
else if (Array.isArray(json.type)) {
let type = json.type.find(t => t !== 'null')
console.log(`WARNING UNHANDLED: type is an array containing ${json.type}`)
let sch = JSON.parse(JSON.stringify(json))
sch.type = type
return getJsonTypeInfo(module, sch, name, schemas, prefix )
}
else if (json.type === 'array' && json.items) {
let res
Expand Down Expand Up @@ -682,10 +721,41 @@ const enumReducer = (acc, val, i, arr) => {
return acc
}

function getSchemaInstantiation(schema, module, name, { instantiationType = '' } = {}) {

if(instantiationType === 'params') {
if (schema.params.length > 0) {
let paramList = []
schema.params.map(param => {
/*
paramList = [{name='', nativeType='', jsonType='', required=boolean}]
*/
const parameter = {}
parameter['nativeType'] = getSchemaType(param.schema, module, { title: true, name: param.name })
parameter['jsonType'] = getJsonType(param.schema, module, {name: param.name})
parameter['name'] = param.name
parameter['required'] = param.required
paramList.push(parameter)

})
return getParameterInstantiation(paramList)
}
} else if(instantiationType === 'result') {
let resultType = getSchemaType(schema, module, { title: true, name: name, resultSchema: true}) || ''
let resultJsonType = getJsonType(schema, module, {name: name}) || ''

return getResultInstantiation(name, resultType, resultJsonType)
}

return ''
}


export default {
getMethodSignature,
getMethodSignatureParams,
getSchemaShape,
getSchemaType,
getJsonType
getJsonType,
getSchemaInstantiation
}
63 changes: 62 additions & 1 deletion languages/c/src/types/ImplHelpers.mjs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { capitalize } from "./NativeHelpers.mjs"

const Indent = '\t'

const getSdkNameSpace = () => 'FireboltSDK'
Expand Down Expand Up @@ -288,9 +290,68 @@ const getMapAccessorsImpl = (objName, containerType, subPropertyType, accessorPr
return result
}

/*
paramList = [{name='', nativeType='', jsonType='', required=boolean}]
*/
function getParameterInstantiation(paramList, container = '') {

let impl = ` ${container.length>0 ? container : 'JsonObject'} jsonParameters;\n`
paramList.forEach(param => {
impl += `\n`
const jsonType = param.jsonType
if (jsonType.length) {
if (param.required) {
if (param.nativeType.includes('FireboltTypes_StringHandle')) {
impl += ` WPEFramework::Core::JSON::Variant ${capitalize(param.name)} = *(static_cast<${jsonType}*>(${param.name}));\n`
}
else {
impl += ` WPEFramework::Core::JSON::Variant ${capitalize(param.name)} = ${param.name};\n`
}
impl += ` jsonParameters.Set(_T("${param.name}"), ${capitalize(param.name)});`
}
else {
impl += ` if (${param.name} != nullptr) {\n`
if (param.nativeType.includes('char*')) {
impl += ` WPEFramework::Core::JSON::Variant ${capitalize(param.name)} = ${param.name};\n`
} else {

impl += ` WPEFramework::Core::JSON::Variant ${capitalize(param.name)} = *(${param.name});\n`
}
impl += ` jsonParameters.Set(_T("${param.name}"), ${capitalize(param.name)});\n`
impl += ` }`
}
}
})

return impl
}

function getResultInstantiation (name, nativeType, container, indentLevel = 3) {

let impl = ''

if (nativeType === 'char*' || nativeType === 'FireboltTypes_StringHandle') {
impl += `${' '.repeat(indentLevel)}${container}* strResult = new ${container}(jsonResult);` + '\n'
impl += `${' '.repeat(indentLevel)}*${name} = static_cast<${getFireboltStringType()}>(strResult);`
} else if (nativeType.includes('Handle')) {
impl += `${' '.repeat(indentLevel)}WPEFramework::Core::ProxyType<${container}>* resultPtr = new WPEFramework::Core::ProxyType<${container}>();\n`
impl += `${' '.repeat(indentLevel)}*resultPtr = WPEFramework::Core::ProxyType<${container}>::Create();\n`
impl += `${' '.repeat(indentLevel)}*(*resultPtr) = jsonResult;\n`
impl += `${' '.repeat(indentLevel)}*${name} = static_cast<${nativeType}>(resultPtr);`
} else {
impl += `${' '.repeat(indentLevel)}*${name} = jsonResult.Value();`
}

return impl

}


export {
getArrayAccessorsImpl,
getMapAccessorsImpl,
getObjectHandleManagementImpl,
getPropertyAccessorsImpl
getPropertyAccessorsImpl,
getParameterInstantiation,
getResultInstantiation
}
70 changes: 54 additions & 16 deletions languages/c/src/types/NativeHelpers.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -115,24 +115,32 @@ const getArrayElementSchema = (json, module, schemas = {}, name) => {
return result
}

const getNativeType = json => {
let type = ''
const getNativeType = (json, stringAsHandle = false) => {
let type
let jsonType = json.const ? typeof json.const : json.type
if (jsonType === 'string') {
type = 'char*'
type = 'char*'
if(stringAsHandle) {
type = getFireboltStringType()
}
}
else if (jsonType === 'number') {
type = 'float'
type = 'float'
}
else if (jsonType === 'integer') {
type = 'int32_t'
type = 'int32_t'

}
else if (jsonType === 'boolean') {
type = 'bool'
}
else if (jsonType === 'null' ) {
type = 'void'
}
return type
}


const getObjectHandleManagement = varName => {

let result = `typedef void* ${varName}Handle;
Expand Down Expand Up @@ -211,24 +219,53 @@ const generateEnum = (schema, prefix)=> {
}
}

function getPropertyGetterSignature(method, module, paramType) {
let m = `${capitalize(getModuleName(module))}_Get${capitalize(method.name)}`
return `${description(method.name, method.summary)}\nuint32 ${m}( ${paramType === 'char*' ? 'FireboltTypes_StringHandle' : paramType}* ${method.result.name || method.name} )`
/*
paramList = [{name='', nativeType='', jsonType='', required=boolean}]
*/

const getContextParams = (paramList) => paramList.map(param => param.nativeType + (!param.required ? '*' : '') + ' ' + param.name).join(', ')

function getPropertyGetterSignature(property, module, propType, paramList = []) {

let contextParams = ''
contextParams = getContextParams(paramList)
return `uint32_t ${capitalize(getModuleName(module))}_Get${capitalize(property.name)}( ${contextParams}${contextParams.length > 0 ? ', ':''}${propType}* ${property.result.name || property.name})`
}

function getPropertySetterSignature(property, module, propType, paramList = []) {
let contextParams = ''
contextParams = getContextParams(paramList)
return `uint32_t ${capitalize(getModuleName(module))}_Set${capitalize(property.name)}( ${contextParams}${contextParams.length > 0 ? ', ':''}${propType} ${property.result.name || property.name})`
}

function getPropertyEventCallbackSignature(property, module, propType, paramList = []) {

let contextParams = ''
contextParams = getContextParams(paramList)
return `/*Callback to listen to updates on ${property.Name} property*/\n` +
`typedef void (*On${capitalize(getModuleName(module))}${capitalize(property.name)}Changed)( ${contextParams}${contextParams.length > 0 ? ', ':''}const void* userData, ${propType} ${property.result.name || property.name})`
}

function getPropertySetterSignature(method, module, paramType) {
let m = `${capitalize(getModuleName(module))}_Set${capitalize(method.name)}`
return `${description(method.name, method.summary)}\nuint32 ${m}( ${paramType} ${method.result.name || method.name} )`
function getPropertyEventInnerCallbackSignature(method, module, schemas) {
let signature = `static void ${capitalize(getModuleName(module)) + capitalize(method.name)}`
}

function getPropertyEventCallbackSignature(method, module, paramType) {
return `typedef void (*On${capitalize(method.name)}Changed)(${paramType === 'char*' ? 'FireboltTypes_StringHandle' : paramType})`
function getPropertyEventRegisterSignature(property, module, paramList = []) {
let contextParams = ''
contextParams = getContextParams(paramList)

return `/*Register to listen to updates on ${capitalize(property.name)} property*/\n` +
`uint32_t ${capitalize(getModuleName(module))}_Register_${capitalize(property.name)}Update( ${contextParams}${contextParams.length > 0 ? ', ':''}On${capitalize(getModuleName(module))}${capitalize(property.name)}Changed userCB, const void* userData )`

}

function getPropertyEventSignature(method, module) {
return `${description(method.name, 'Listen to updates')}\n` + `uint32_t ${capitalize(getModuleName(module))}_Listen${capitalize(method.name)}Update(On${capitalize(method.name)}Changed notification, uint16_t* listenerId)`
function getPropertyEventUnregisterSignature(property, module) {
return `/*Unregister to listen to updates on ${capitalize(property.name)} property*/\n` +
`uint32_t ${capitalize(getModuleName(module))}_Unregister_${capitalize(property.name)}Update( On${capitalize(getModuleName(module))}${capitalize(property.name)}Changed userCB )`

}


export {
getHeaderText,
getIncludeGuardOpen,
Expand All @@ -240,7 +277,8 @@ export {
getPropertyGetterSignature,
getPropertySetterSignature,
getPropertyEventCallbackSignature,
getPropertyEventSignature,
getPropertyEventRegisterSignature,
getPropertyEventUnregisterSignature,
getMapAccessors,
getArrayAccessors,
capitalize,
Expand Down
9 changes: 9 additions & 0 deletions languages/c/templates/codeblocks/setter.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
/* ${method.name} - ${method.description} */
uint32_t ${info.title}_${method.Name}( ${method.signature.params} )
{
const string method = _T("${info.title}.${method.name}");
${if.params}
${method.params.serialization}
${end.if.params}
return FireboltSDK::Properties::Set(method, jsonParameters);
}
5 changes: 0 additions & 5 deletions languages/c/templates/declarations/default.c
Original file line number Diff line number Diff line change
@@ -1,5 +0,0 @@
/*
* ${method.summary}
* ${method.params}
*/
${method.signature};
5 changes: 5 additions & 0 deletions languages/c/templates/declarations/property.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
/*
* ${method.summary}
* ${method.params}
*/
${method.signature}
1 change: 0 additions & 1 deletion languages/c/templates/defaults/default.c
Original file line number Diff line number Diff line change
@@ -1 +0,0 @@
${method.name}: ${method.example.value}
1 change: 0 additions & 1 deletion languages/c/templates/defaults/property.c
Original file line number Diff line number Diff line change
@@ -1 +0,0 @@
${method.name}: function () { return MockProps.mock('${info.title}', '${method.name}', arguments, ${method.example.value}) }
Loading