Skip to content

Commit

Permalink
C-Language: Templates based property methods (#100)
Browse files Browse the repository at this point in the history
* feat: Add method templates for properties

* feat: Property setters using templates

* fix: Macro name correction
  • Loading branch information
sramani-metro authored and HaseenaSainul committed Aug 8, 2023
1 parent 8818654 commit a168c8d
Show file tree
Hide file tree
Showing 14 changed files with 243 additions and 49 deletions.
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}) }
File renamed without changes.
Loading

0 comments on commit a168c8d

Please sign in to comment.