diff --git a/lib/baobab/generator/generate_methods.v b/lib/baobab/generator/generate_methods.v index 4f637f2e..99e3051a 100644 --- a/lib/baobab/generator/generate_methods.v +++ b/lib/baobab/generator/generate_methods.v @@ -1,6 +1,6 @@ module generator -import freeflowuniverse.herolib.core.code { Folder, IFile, VFile, CodeItem, File, Function, Param, Import, Module, Struct, CustomCode } +import freeflowuniverse.herolib.core.code { Array, Folder, IFile, VFile, CodeItem, File, Function, Param, Import, Module, Struct, CustomCode, Result } import freeflowuniverse.herolib.core.texttools import freeflowuniverse.herolib.schemas.openrpc.codegen {content_descriptor_to_parameter} import freeflowuniverse.herolib.baobab.specification {ActorMethod, ActorSpecification} @@ -42,10 +42,11 @@ pub fn generate_methods_file(spec ActorSpecification) !VFile { // returns bodyless method prototype pub fn generate_method_function(actor_name string, method ActorMethod) !Function { actor_name_pascal := texttools.name_fix_snake_to_pascal(actor_name) + result_param := content_descriptor_to_parameter(method.result)! return Function{ name: texttools.name_fix_snake(method.name) receiver: code.new_param(v: 'mut actor ${actor_name_pascal}Actor')! - result: Param{...content_descriptor_to_parameter(method.result)!, is_result: true} + result: Param {...result_param, typ: Result{result_param.typ}} summary: method.summary description: method.description params: method.parameters.map(content_descriptor_to_parameter(it)!) @@ -80,7 +81,7 @@ fn generate_base_object_new_body(method ActorMethod) !string { fn generate_base_object_get_body(method ActorMethod) !string { parameter := content_descriptor_to_parameter(method.parameters[0])! result := content_descriptor_to_parameter(method.result)! - return 'return actor.osis.get[${result.typ.vgen()}](${parameter.name})!' + return 'return actor.osis.get[${result.typ.vgen()}](${texttools.name_fix_snake(parameter.name)})!' } fn generate_base_object_set_body(method ActorMethod) !string { @@ -90,10 +91,12 @@ fn generate_base_object_set_body(method ActorMethod) !string { fn generate_base_object_delete_body(method ActorMethod) !string { parameter := content_descriptor_to_parameter(method.parameters[0])! - return 'return actor.osis.delete(${parameter.name})!' + return 'actor.osis.delete(${texttools.name_fix_snake(parameter.name)})!' } fn generate_base_object_list_body(method ActorMethod) !string { result := content_descriptor_to_parameter(method.result)! - return 'return actor.osis.list[${result.typ.vgen()}]()!' + + base_object_type := (result.typ as Array).typ + return 'return actor.osis.list[${base_object_type.symbol()}]()!' } diff --git a/lib/baobab/generator/write_object_methods.v b/lib/baobab/generator/write_object_methods.v index 19b3ce45..305f69dd 100644 --- a/lib/baobab/generator/write_object_methods.v +++ b/lib/baobab/generator/write_object_methods.v @@ -1,14 +1,12 @@ module generator import freeflowuniverse.herolib.baobab.specification {BaseObject} -import freeflowuniverse.herolib.core.code { VFile, CodeItem, Function, Import, Param, Param, Struct, StructField, Type } +import freeflowuniverse.herolib.core.code { type_from_symbol, VFile, CodeItem, Function, Import, Param, Param, Struct, StructField, Type } import freeflowuniverse.herolib.core.texttools const id_param = Param{ name: 'id' - typ: Type{ - symbol: 'u32' - } + typ: type_from_symbol('u32') } // pub fn generate_object_code(actor Struct, object BaseObject) VFile { @@ -47,366 +45,362 @@ const id_param = Param{ // return file // } -// generate_object_methods generates CRUD actor methods for a provided structure -fn generate_get_method(actor Struct, object BaseObject) Function { - object_name := texttools.name_fix_pascal_to_snake(object.structure.name) - object_type := object.structure.name - - get_method := Function{ - name: 'get_${object_name}' - description: 'gets the ${object_name} with the given object id' - receiver: Param{ - mutable: true - name: 'actor' - typ: Type{ - symbol: actor.name - } - } - params: [generator.id_param] - result: Param{ - typ: Type{ - symbol: object.structure.name - } - is_result: true - } - body: 'return actor.backend.get[${object_type}](id)!' - } - return get_method -} - -// generate_object_methods generates CRUD actor methods for a provided structure -fn generate_set_method(actor Struct, object BaseObject) Function { - object_name := texttools.name_fix_pascal_to_snake(object.structure.name) - object_type := object.structure.name - - param_getters := generate_param_getters( - structure: object.structure - prefix: '' - only_mutable: true - ) - body := 'actor.backend.set[${object_type}](${object_name})!' - get_method := Function{ - name: 'set_${object_name}' - description: 'updates the ${object.structure.name} with the given object id' - receiver: Param{ - mutable: true - name: 'actor' - typ: Type{ - symbol: actor.name - } - } - params: [ - Param{ - name: object_name - typ: Type{ - symbol: object_type - } - }, - ] - result: Param{ - is_result: true - } - body: body - } - return get_method -} - -// generate_object_methods generates CRUD actor methods for a provided structure -fn generate_delete_method(actor Struct, object BaseObject) Function { - object_name := texttools.name_fix_pascal_to_snake(object.structure.name) - object_type := object.structure.name - - body := 'actor.backend.delete[${object_type}](id)!' - get_method := Function{ - name: 'delete_${object_name}' - description: 'deletes the ${object.structure.name} with the given object id' - receiver: Param{ - mutable: true - name: 'actor' - typ: Type{ - symbol: actor.name - } - } - params: [generator.id_param] - result: Param{ - is_result: true - } - body: body - } - return get_method -} - -// generate_object_methods generates CRUD actor methods for a provided structure -fn generate_new_method(actor Struct, object BaseObject) Function { - object_name := texttools.name_fix_pascal_to_snake(object.structure.name) - object_type := object.structure.name - - param_getters := generate_param_getters( - structure: object.structure - prefix: '' - only_mutable: false - ) - body := 'return actor.backend.new[${object_type}](${object_name})!' - new_method := Function{ - name: 'new_${object_name}' - description: 'news the ${object.structure.name} with the given object id' - receiver: Param{ - name: 'actor' - typ: Type{ - symbol: actor.name - } - mutable: true - } - params: [ - Param{ - name: object_name - typ: Type{ - symbol: object_type - } - }, - ] - result: Param{ - is_result: true - typ: Type{ - symbol: 'u32' - } - } - body: body - } - return new_method -} - -// generate_object_methods generates CRUD actor methods for a provided structure -fn generate_list_result_struct(actor Struct, object BaseObject) Struct { - object_name := texttools.name_fix_pascal_to_snake(object.structure.name) - object_type := object.structure.name - return Struct{ - name: '${object_type}List' - is_pub: true - fields: [ - StructField{ - name: 'items' - typ: Type{ - symbol: '[]${object_type}' - } - }, - ] - } -} - -// generate_object_methods generates CRUD actor methods for a provided structure -fn generate_list_method(actor Struct, object BaseObject) Function { - object_name := texttools.name_fix_pascal_to_snake(object.structure.name) - object_type := object.structure.name - - list_struct := Struct{ - name: '${object_type}List' - fields: [ - StructField{ - name: 'items' - typ: Type{ - symbol: '[]${object_type}' - } - }, - ] - } - - param_getters := generate_param_getters( - structure: object.structure - prefix: '' - only_mutable: false - ) - body := 'return ${object_type}List{items:actor.backend.list[${object_type}]()!}' - - result_struct := generate_list_result_struct(actor, object) - mut result := Param{} - result.typ.symbol = result_struct.name - result.is_result = true - new_method := Function{ - name: 'list_${object_name}' - description: 'lists all of the ${object_name} objects' - receiver: Param{ - name: 'actor' - typ: Type{ - symbol: actor.name - } - mutable: true - } - params: [] - result: result - body: body - } - return new_method -} - -fn generate_filter_params(actor Struct, object BaseObject) []Struct { - object_name := texttools.name_fix_pascal_to_snake(object.structure.name) - object_type := object.structure.name - - return [ - Struct{ - name: 'Filter${object_type}Params' - fields: [ - StructField{ - name: 'filter' - typ: Type{ - symbol: '${object_type}Filter' - } - }, - StructField{ - name: 'params' - typ: Type{ - symbol: 'FilterParams' - } - }, - ] - }, - Struct{ - name: '${object_type}Filter' - fields: object.structure.fields.filter(it.attrs.any(it.name == 'index')) - }, - ] -} - -// generate_object_methods generates CRUD actor methods for a provided structure -fn generate_filter_method(actor Struct, object BaseObject) Function { - object_name := texttools.name_fix_pascal_to_snake(object.structure.name) - object_type := object.structure.name - - param_getters := generate_param_getters( - structure: object.structure - prefix: '' - only_mutable: false - ) - params_type := 'Filter${object_type}Params' - body := 'return actor.backend.filter[${object_type}, ${object_type}Filter](filter.filter, filter.params)!' - return Function{ - name: 'filter_${object_name}' - description: 'lists all of the ${object_name} objects' - receiver: Param{ - name: 'actor' - typ: Type{ - symbol: actor.name - } - mutable: true - } - params: [ - Param{ - name: 'filter' - typ: Type{ - symbol: params_type - } - }, - ] - result: Param{ - typ: Type{ - symbol: '[]${object_type}' - } - is_result: true - } - body: body - } -} - // // generate_object_methods generates CRUD actor methods for a provided structure -// fn generate_object_methods(actor Struct, object BaseObject) []Function { +// fn generate_get_method(actor Struct, object BaseObject) Function { // object_name := texttools.name_fix_pascal_to_snake(object.structure.name) // object_type := object.structure.name -// mut funcs := []Function{} -// for method in object.methods { -// mut params := [Param{ -// name: 'id' +// get_method := Function{ +// name: 'get_${object_name}' +// description: 'gets the ${object_name} with the given object id' +// receiver: Param{ +// mutable: true +// name: 'actor' +// typ: type_from_symbol(actor.name) +// } +// } +// params: [generator.id_param] +// result: Param{ +// typ: type_from_symbol(object.structure.name) +// is_result: true +// } +// body: 'return actor.backend.get[${object_type}](id)!' +// } +// return get_method +// } + +// // generate_object_methods generates CRUD actor methods for a provided structure +// fn generate_set_method(actor Struct, object BaseObject) Function { +// object_name := texttools.name_fix_pascal_to_snake(object.structure.name) +// object_type := object.structure.name + +// param_getters := generate_param_getters( +// structure: object.structure +// prefix: '' +// only_mutable: true +// ) +// body := 'actor.backend.set[${object_type}](${object_name})!' +// get_method := Function{ +// name: 'set_${object_name}' +// description: 'updates the ${object.structure.name} with the given object id' +// receiver: Param{ +// mutable: true +// name: 'actor' +// typ: type_from_symbol(actor.name) +// } +// } +// params: [ +// Param{ +// name: object_name +// typ: Type{ +// symbol: object_type +// } +// }, +// ] +// result: Param{ +// is_result: true +// } +// body: body +// } +// return get_method +// } + +// // generate_object_methods generates CRUD actor methods for a provided structure +// fn generate_delete_method(actor Struct, object BaseObject) Function { +// object_name := texttools.name_fix_pascal_to_snake(object.structure.name) +// object_type := object.structure.name + +// body := 'actor.backend.delete[${object_type}](id)!' +// get_method := Function{ +// name: 'delete_${object_name}' +// description: 'deletes the ${object.structure.name} with the given object id' +// receiver: Param{ +// mutable: true +// name: 'actor' +// typ: Type{ +// symbol: actor.name +// } +// } +// params: [generator.id_param] +// result: Param{ +// is_result: true +// } +// body: body +// } +// return get_method +// } + +// // generate_object_methods generates CRUD actor methods for a provided structure +// fn generate_new_method(actor Struct, object BaseObject) Function { +// object_name := texttools.name_fix_pascal_to_snake(object.structure.name) +// object_type := object.structure.name + +// param_getters := generate_param_getters( +// structure: object.structure +// prefix: '' +// only_mutable: false +// ) +// body := 'return actor.backend.new[${object_type}](${object_name})!' +// new_method := Function{ +// name: 'new_${object_name}' +// description: 'news the ${object.structure.name} with the given object id' +// receiver: Param{ +// name: 'actor' +// typ: Type{ +// symbol: actor.name +// } +// mutable: true +// } +// params: [ +// Param{ +// name: object_name +// typ: Type{ +// symbol: object_type +// } +// }, +// ] +// result: Param{ +// is_result: true // typ: Type{ // symbol: 'u32' // } -// }] -// params << method.params -// funcs << Function{ -// name: method.name -// description: method.description -// receiver: Param{ -// name: 'actor' -// typ: Type{ -// symbol: actor.name -// } -// mutable: true -// } -// params: params -// result: method.result -// body: 'obj := actor.backend.get[${method.receiver.typ.symbol}](id)! -// obj.${method.name}(${method.params.map(it.name).join(',')}) -// actor.backend.set[${method.receiver.typ.symbol}](obj)! -// ' // } +// body: body // } - -// return funcs +// return new_method // } -@[params] -struct GenerateParamGetters { - structure Struct - prefix string - only_mutable bool // if true generates param.get methods for only mutable struct fields. Used for updating. -} +// // generate_object_methods generates CRUD actor methods for a provided structure +// fn generate_list_result_struct(actor Struct, object BaseObject) Struct { +// object_name := texttools.name_fix_pascal_to_snake(object.structure.name) +// object_type := object.structure.name +// return Struct{ +// name: '${object_type}List' +// is_pub: true +// fields: [ +// StructField{ +// name: 'items' +// typ: Type{ +// symbol: '[]${object_type}' +// } +// }, +// ] +// } +// } -fn generate_param_getters(params GenerateParamGetters) []string { - mut param_getters := []string{} - fields := if params.only_mutable { - params.structure.fields.filter(it.is_mut && it.is_pub) - } else { - params.structure.fields.filter(it.is_pub) - } - for field in fields { - if field.typ.symbol.starts_with_capital() { - subgetters := generate_param_getters(GenerateParamGetters{ - ...params - structure: field.structure - prefix: '${field.name}_' - }) - // name of the tested object, used for param declaration - // ex: fruits []Fruit becomes fruit_name - nested_name := field.structure.name.to_lower() - if field.typ.is_map { - param_getters.insert(0, '${nested_name}_key := params.get(\'${nested_name}_key\')!') - param_getters << '${field.name}: {${nested_name}_key: ${field.structure.name}}{' - } else if field.typ.is_array { - param_getters << '${field.name}: [${field.structure.name}{' - } else { - param_getters << '${field.name}: ${field.structure.name}{' - } - param_getters << subgetters - param_getters << if field.typ.is_array { '}]' } else { '}' } - continue - } +// // generate_object_methods generates CRUD actor methods for a provided structure +// fn generate_list_method(actor Struct, object BaseObject) Function { +// object_name := texttools.name_fix_pascal_to_snake(object.structure.name) +// object_type := object.structure.name - mut get_method := '${field.name}: params.get' - if field.typ.symbol != 'string' { - // TODO: check if params method actually exists - 'get_${field.typ.symbol}' - } +// list_struct := Struct{ +// name: '${object_type}List' +// fields: [ +// StructField{ +// name: 'items' +// typ: Type{ +// symbol: '[]${object_type}' +// } +// }, +// ] +// } - if field.default != '' { - get_method += '_default' - } +// param_getters := generate_param_getters( +// structure: object.structure +// prefix: '' +// only_mutable: false +// ) +// body := 'return ${object_type}List{items:actor.backend.list[${object_type}]()!}' + +// result_struct := generate_list_result_struct(actor, object) +// mut result := Param{} +// result.typ.symbol = result_struct.name +// result.is_result = true +// new_method := Function{ +// name: 'list_${object_name}' +// description: 'lists all of the ${object_name} objects' +// receiver: Param{ +// name: 'actor' +// typ: Type{ +// symbol: actor.name +// } +// mutable: true +// } +// params: [] +// result: result +// body: body +// } +// return new_method +// } - get_method = get_method + "('${params.prefix}${field.name}')!" - param_getters << get_method - } - return param_getters -} +// fn generate_filter_params(actor Struct, object BaseObject) []Struct { +// object_name := texttools.name_fix_pascal_to_snake(object.structure.name) +// object_type := object.structure.name -@[params] -struct GetChildField { - parent Struct @[required] - child Struct @[required] -} +// return [ +// Struct{ +// name: 'Filter${object_type}Params' +// fields: [ +// StructField{ +// name: 'filter' +// typ: Type{ +// symbol: '${object_type}Filter' +// } +// }, +// StructField{ +// name: 'params' +// typ: Type{ +// symbol: 'FilterParams' +// } +// }, +// ] +// }, +// Struct{ +// name: '${object_type}Filter' +// fields: object.structure.fields.filter(it.attrs.any(it.name == 'index')) +// }, +// ] +// } -fn get_child_field(params GetChildField) StructField { - fields := params.parent.fields.filter(it.typ.symbol == 'map[string]&${params.child.name}') - if fields.len != 1 { - panic('this should never happen') - } - return fields[0] -} +// // generate_object_methods generates CRUD actor methods for a provided structure +// fn generate_filter_method(actor Struct, object BaseObject) Function { +// object_name := texttools.name_fix_pascal_to_snake(object.structure.name) +// object_type := object.structure.name + +// param_getters := generate_param_getters( +// structure: object.structure +// prefix: '' +// only_mutable: false +// ) +// params_type := 'Filter${object_type}Params' +// body := 'return actor.backend.filter[${object_type}, ${object_type}Filter](filter.filter, filter.params)!' +// return Function{ +// name: 'filter_${object_name}' +// description: 'lists all of the ${object_name} objects' +// receiver: Param{ +// name: 'actor' +// typ: Type{ +// symbol: actor.name +// } +// mutable: true +// } +// params: [ +// Param{ +// name: 'filter' +// typ: Type{ +// symbol: params_type +// } +// }, +// ] +// result: Param{ +// typ: Type{ +// symbol: '[]${object_type}' +// } +// is_result: true +// } +// body: body +// } +// } + +// // // generate_object_methods generates CRUD actor methods for a provided structure +// // fn generate_object_methods(actor Struct, object BaseObject) []Function { +// // object_name := texttools.name_fix_pascal_to_snake(object.structure.name) +// // object_type := object.structure.name + +// // mut funcs := []Function{} +// // for method in object.methods { +// // mut params := [Param{ +// // name: 'id' +// // typ: Type{ +// // symbol: 'u32' +// // } +// // }] +// // params << method.params +// // funcs << Function{ +// // name: method.name +// // description: method.description +// // receiver: Param{ +// // name: 'actor' +// // typ: Type{ +// // symbol: actor.name +// // } +// // mutable: true +// // } +// // params: params +// // result: method.result +// // body: 'obj := actor.backend.get[${method.receiver.typ.symbol}](id)! +// // obj.${method.name}(${method.params.map(it.name).join(',')}) +// // actor.backend.set[${method.receiver.typ.symbol}](obj)! +// // ' +// // } +// // } + +// // return funcs +// // } + +// @[params] +// struct GenerateParamGetters { +// structure Struct +// prefix string +// only_mutable bool // if true generates param.get methods for only mutable struct fields. Used for updating. +// } + +// fn generate_param_getters(params GenerateParamGetters) []string { +// mut param_getters := []string{} +// fields := if params.only_mutable { +// params.structure.fields.filter(it.is_mut && it.is_pub) +// } else { +// params.structure.fields.filter(it.is_pub) +// } +// for field in fields { +// if field.typ.symbol.starts_with_capital() { +// subgetters := generate_param_getters(GenerateParamGetters{ +// ...params +// structure: field.structure +// prefix: '${field.name}_' +// }) +// // name of the tested object, used for param declaration +// // ex: fruits []Fruit becomes fruit_name +// nested_name := field.structure.name.to_lower() +// if field.typ.is_map { +// param_getters.insert(0, '${nested_name}_key := params.get(\'${nested_name}_key\')!') +// param_getters << '${field.name}: {${nested_name}_key: ${field.structure.name}}{' +// } else if field.typ.is_array { +// param_getters << '${field.name}: [${field.structure.name}{' +// } else { +// param_getters << '${field.name}: ${field.structure.name}{' +// } +// param_getters << subgetters +// param_getters << if field.typ.is_array { '}]' } else { '}' } +// continue +// } + +// mut get_method := '${field.name}: params.get' +// if field.typ.symbol != 'string' { +// // TODO: check if params method actually exists +// 'get_${field.typ.symbol}' +// } + +// if field.default != '' { +// get_method += '_default' +// } + +// get_method = get_method + "('${params.prefix}${field.name}')!" +// param_getters << get_method +// } +// return param_getters +// } + +// @[params] +// struct GetChildField { +// parent Struct @[required] +// child Struct @[required] +// } + +// fn get_child_field(params GetChildField) StructField { +// fields := params.parent.fields.filter(it.typ.symbol == 'map[string]&${params.child.name}') +// if fields.len != 1 { +// panic('this should never happen') +// } +// return fields[0] +// } diff --git a/lib/core/code/README.md b/lib/core/code/README.md index 41281034..6bb1c215 100644 --- a/lib/core/code/README.md +++ b/lib/core/code/README.md @@ -27,7 +27,7 @@ code_md := '' // describes the struct in markdown format for struct in structs { code_md += '# ${struct.name}' - code_md += 'Type: ${struct.typ.symbol}' + code_md += 'Type: ${struct.typ.symbol()}' code_md += '## Fields:' for field in struct.fields { code_md += '- ${field.name}' diff --git a/lib/core/code/function.v b/lib/core/code/function.v index 46b024d8..85d2e692 100644 --- a/lib/core/code/function.v +++ b/lib/core/code/function.v @@ -28,6 +28,66 @@ pub mut: struct_ Struct @[omitempty] } +pub type Type = Array | Object | Result | Integer | Alias | String + +pub struct Integer { + bytes u8 +} + +pub fn type_from_symbol(symbol_ string) Type { + mut symbol := symbol_.trim_space() + if symbol.starts_with('[]') { + return Array{type_from_symbol(symbol.all_after('[]'))} + } else if symbol == 'int' { + return Integer{} + } else if symbol == 'string' { + return String{} + } + return Object{symbol} +} + +pub fn (t Type) symbol() string { + return match t { + Array { '[]${t.typ.symbol()}' } + Object { t.name } + Result { '!${t.typ.symbol()}'} + Integer {'int'} + Alias {t.name} + String {'string'} + } +} + +pub struct String {} + +pub struct Array { +pub: + typ Type +} + +pub struct Object { +pub: + name string +} + +pub struct Result { +pub: + typ Type +} + +// // todo: maybe make 'is_' fields methods? +// pub struct Type { +// pub mut: +// is_reference bool @[str: skip] +// is_map bool @[str: skip] +// is_array bool +// is_mutable bool @[str: skip] +// is_shared bool @[str: skip] +// is_optional bool @[str: skip] +// is_result bool @[str: skip] +// symbol string +// mod string @[str: skip] +// } + @[params] pub struct Params{ pub: @@ -39,16 +99,6 @@ pub fn new_param(params Params) !Param { return parse_param(params.v)! } -pub struct Result { -pub mut: - typ Type @[omitempty] - description string @[omitempty] - name string @[omitempty] - result bool @[omitempty] // whether is result type - optional bool @[omitempty] // whether is result type - structure Struct @[omitempty] -} - pub fn new_function(code string) !Function { // TODO: implement function from file line return parse_function(code)! diff --git a/lib/core/code/model.v b/lib/core/code/model.v index 7aea3834..820ed72e 100644 --- a/lib/core/code/model.v +++ b/lib/core/code/model.v @@ -76,9 +76,7 @@ pub fn parse_param(code_ string) !Param { if split.len == 1 { // means anonymous param return Param{ - typ: Type{ - symbol: split[0] - } + typ: type_from_symbol(split[0]) mutable: is_mut } } @@ -87,41 +85,11 @@ pub fn parse_param(code_ string) !Param { } return Param{ name: split[0] - typ: Type{ - symbol: split[1] - } + typ: type_from_symbol(split[1]) mutable: is_mut } } -pub fn parse_result(code_ string) !Result { - code := code_.replace(' ', '').trim_space() - - return Result{ - result: code_.starts_with('!') - optional: code_.starts_with('?') - typ: Type{ - symbol: code.trim('!?') - is_optional: code.starts_with('?') - is_result: code.starts_with('!') - } - } -} - -// todo: maybe make 'is_' fields methods? -pub struct Type { -pub mut: - is_reference bool @[str: skip] - is_map bool @[str: skip] - is_array bool - is_mutable bool @[str: skip] - is_shared bool @[str: skip] - is_optional bool @[str: skip] - is_result bool @[str: skip] - symbol string - mod string @[str: skip] -} - pub struct Alias { pub: name string diff --git a/lib/core/code/utils.v b/lib/core/code/utils.v index da2f6796..c1349f36 100644 --- a/lib/core/code/utils.v +++ b/lib/core/code/utils.v @@ -34,10 +34,10 @@ pub fn inflate_types(mut code []CodeItem) { pub fn inflate_struct_fields(code []CodeItem, mut struct_ CodeItem) { for mut field in (struct_ as Struct).fields { // TODO: fix inflation for imported types - if field.typ.symbol.starts_with_capital() { + if field.typ.symbol().starts_with_capital() { field.structure = get_struct( code: code - name: field.typ.symbol + name: field.typ.symbol() ) or { continue } } } @@ -51,7 +51,7 @@ pub: pub fn (func Function) generate_call(params GenerateCallParams) !string { mut call := '' - if func.result.typ.symbol != '' { + if func.result.typ.symbol() != '' { call = 'result := ' } call += if params.receiver != '' { @@ -79,12 +79,12 @@ pub struct GenerateValueParams { } pub fn (param Param) generate_value() !string { - if param.typ.symbol == 'string' { + if param.typ.symbol() == 'string' { return "'mock_string_${rand.string(3)}'" - } else if param.typ.symbol == 'int' || param.typ.symbol == 'u32' { + } else if param.typ.symbol() == 'int' || param.typ.symbol() == 'u32' { return '42' - } else if param.typ.symbol[0].is_capital() { - return '${param.typ.symbol}{}' + } else if param.typ.symbol()[0].is_capital() { + return '${param.typ.symbol()}{}' } else { log.debug('mock values for types other than strings and ints are not yet supported') } diff --git a/lib/core/code/vgen.v b/lib/core/code/vgen.v index 52f4e465..b17728d1 100644 --- a/lib/core/code/vgen.v +++ b/lib/core/code/vgen.v @@ -43,21 +43,8 @@ pub fn (import_ Import) vgen() string { } // TODO: enfore that cant be both mutable and shared -pub fn (type_ Type) vgen() string { - mut type_str := '' - if type_.is_mutable { - type_str += 'mut ' - } else if type_.is_shared { - type_str += 'shared ' - } - - if type_.is_optional { - type_str += '?' - } else if type_.is_result { - type_str += '!' - } - - return '${type_str} ${type_.symbol}' +pub fn (t Type) vgen() string { + return t.symbol() } pub fn (field StructField) vgen() string { @@ -73,7 +60,7 @@ pub fn (field StructField) get_type_symbol() string { mut field_str := if field.structure.name != '' { field.structure.get_type_symbol() } else { - field.typ.symbol + field.typ.symbol() } if field.is_ref { @@ -111,12 +98,10 @@ pub fn vgen_generics(generics map[string]string) string { pub fn (function Function) vgen(options WriteOptions) string { mut params_ := function.params.map(Param{ ...it - typ: Type{ - symbol: if it.struct_.name != '' { - it.struct_.name - } else { - it.typ.symbol - } + typ: if it.struct_.name != '' { + type_from_symbol(it.struct_.name) + } else { + it.typ } }) @@ -129,17 +114,13 @@ pub fn (function Function) vgen(options WriteOptions) string { fields: optionals.map(StructField{ name: it.name description: it.description - typ: Type{ - symbol: it.typ.symbol - } + typ: it.typ }) } if optionals.len > 0 { params_ << Param{ name: 'options' - typ: Type{ - symbol: options_struct.name - } + typ: type_from_symbol(options_struct.name) } } @@ -172,22 +153,9 @@ pub fn (function Function) vgen(options WriteOptions) string { } pub fn (param Param) vgen() string { - // if param.name == '' { - // return '' - // } - sym := if param.struct_.name != '' { - param.struct_.get_type_symbol() - } else { - param.typ.symbol - } + sym := param.typ.symbol() param_name := texttools.name_fix_snake(param.name) mut vstr := '${param_name} ${sym}' - if param.typ.is_reference { - vstr = '&${vstr}' - } - if param.is_result { - vstr = '!${vstr}' - } if param.mutable { vstr = 'mut ${vstr}' } @@ -196,19 +164,6 @@ pub fn (param Param) vgen() string { // vgen_function generates a function statement for a function pub fn (struct_ Struct) vgen() string { - gen := VGenerator{false} - return gen.generate_struct(struct_) or { panic(err) } - // mut struct_str := $tmpl('templates/struct/struct.v.template') - // return struct_str - // result := os.execute_opt('echo "${struct_str.replace('$', '\$')}" | v fmt') or {panic(err)} - // return result.output -} - -pub struct VGenerator { - format bool -} - -pub fn (gen VGenerator) generate_struct(struct_ Struct) !string { name := if struct_.generics.len > 0 { '${struct_.name}${vgen_generics(struct_.generics)}' } else { @@ -221,13 +176,13 @@ pub fn (gen VGenerator) generate_struct(struct_ Struct) !string { '' } - priv_fields := struct_.fields.filter(!it.is_mut && !it.is_pub).map(gen.generate_struct_field(it)) - pub_fields := struct_.fields.filter(!it.is_mut && it.is_pub).map(gen.generate_struct_field(it)) - mut_fields := struct_.fields.filter(it.is_mut && !it.is_pub).map(gen.generate_struct_field(it)) - pub_mut_fields := struct_.fields.filter(it.is_mut && it.is_pub).map(gen.generate_struct_field(it)) + priv_fields := struct_.fields.filter(!it.is_mut && !it.is_pub).map(generate_struct_field(it)) + pub_fields := struct_.fields.filter(!it.is_mut && it.is_pub).map(generate_struct_field(it)) + mut_fields := struct_.fields.filter(it.is_mut && !it.is_pub).map(generate_struct_field(it)) + pub_mut_fields := struct_.fields.filter(it.is_mut && it.is_pub).map(generate_struct_field(it)) mut struct_str := $tmpl('templates/struct/struct.v.template') - if gen.format { + if false { result := os.execute_opt('echo "${struct_str.replace('$', '\$')}" | v fmt') or { log.debug(struct_str) panic(err) @@ -235,9 +190,13 @@ pub fn (gen VGenerator) generate_struct(struct_ Struct) !string { return result.output } return struct_str + // mut struct_str := $tmpl('templates/struct/struct.v.template') + // return struct_str + // result := os.execute_opt('echo "${struct_str.replace('$', '\$')}" | v fmt') or {panic(err)} + // return result.output } -pub fn (gen VGenerator) generate_struct_field(field StructField) string { +pub fn generate_struct_field(field StructField) string { symbol := field.get_type_symbol() mut vstr := '${field.name} ${symbol}' if field.description != '' { @@ -250,29 +209,6 @@ pub fn (custom CustomCode) vgen() string { return custom.text } -// vgen_function generates a function statement for a function -pub fn (result Result) vgen() string { - result_type := if result.structure.name != '' { - result.structure.get_type_symbol() - } else if result.typ.symbol == 'void' { - '' - } else { - if result.typ.is_array { - '[]${result.typ.symbol}' - } else { - result.typ.symbol - } - } - str := if result.result { - '!' - } else if result.typ.is_result { - '!' - } else { - '' - } - return '${str}${result_type}' -} - @[params] pub struct WriteOptions { pub: diff --git a/lib/schemas/jsonschema/codegen/codegen.v b/lib/schemas/jsonschema/codegen/codegen.v index 2b41bafd..1be1abd5 100644 --- a/lib/schemas/jsonschema/codegen/codegen.v +++ b/lib/schemas/jsonschema/codegen/codegen.v @@ -1,6 +1,6 @@ module codegen -import freeflowuniverse.herolib.core.code { Alias, Attribute, CodeItem, Struct, StructField, Type } +import freeflowuniverse.herolib.core.code { Alias, Attribute, CodeItem, Struct, StructField, Type, type_from_symbol, Object, Array} import freeflowuniverse.herolib.schemas.jsonschema { Schema, SchemaRef, Reference } const vtypes = { @@ -35,7 +35,7 @@ pub fn schema_to_structs(schema Schema) ![]string { typesymbol = ref_to_symbol(ref) } else { property = property_ as Schema - typesymbol = schema_to_type(property)! + typesymbol = schema_to_type(property)!.symbol() // recursively encode property if object // todo: handle duplicates if property.typ == 'object' { @@ -54,34 +54,36 @@ pub fn schema_to_structs(schema Schema) ![]string { } // schema_to_type generates a typesymbol for the schema -pub fn schema_to_type(schema Schema) !string { - mut property_str := '' +pub fn schema_to_type(schema Schema) !Type { if schema.typ == 'null' { - return '' + Type{} } - if schema.typ == 'object' { - if schema.title == '' { - return error('Object schemas must define a title.') - } - // todo: enforce uppercase - property_str = schema.title - } else if schema.typ == 'array' { + mut property_str := '' + return match schema.typ { + 'object' { + if schema.title == '' { + return error('Object schemas must define a title.') + } + Object{schema.title} + } + 'array' { // todo: handle multiple item schemas - if schema.items is SchemaRef { - // items := schema.items as SchemaRef - if schema.items is Schema { - items_schema := schema.items as Schema - property_str = '[]${items_schema.typ}' + if schema.items is []SchemaRef { + return error('items of type []SchemaRef not implemented') + } + Array { + typ: schemaref_to_type(schema.items as SchemaRef)! + } + } else { + if schema.typ in vtypes.keys() { + type_from_symbol(vtypes[schema.typ]) + } else if schema.title != '' { + type_from_symbol(schema.title) + } else { + return error('unknown type `${schema.typ}` ') } } - } else if schema.typ in vtypes.keys() { - property_str = vtypes[schema.typ] - } else if schema.title != '' { - property_str = schema.title - } else { - return error('unknown type `${schema.typ}` ') - } - return property_str + } } pub fn schema_to_code(schema Schema) !CodeItem { @@ -91,9 +93,7 @@ pub fn schema_to_code(schema Schema) !CodeItem { if schema.typ in vtypes { return Alias{ name: schema.title - typ: Type{ - symbol: vtypes[schema.typ] - } + typ: type_from_symbol(vtypes[schema.typ]) } } if schema.typ == 'array' { @@ -102,17 +102,13 @@ pub fn schema_to_code(schema Schema) !CodeItem { items_schema := schema.items as Schema return Alias{ name: schema.title - typ: Type{ - symbol: '[]${items_schema.typ}' - } + typ: type_from_symbol('[]${items_schema.typ}') } } else if schema.items is Reference { items_ref := schema.items as Reference return Alias{ name: schema.title - typ: Type{ - symbol: '[]${ref_to_symbol(items_ref)}' - } + typ: type_from_symbol('[]${ref_to_symbol(items_ref)}') } } } @@ -144,9 +140,7 @@ pub fn ref_to_field(schema_ref SchemaRef, name string) !StructField { if schema_ref is Reference { return StructField{ name: name - typ: Type{ - symbol: ref_to_symbol(schema_ref) - } + typ: type_from_symbol(ref_to_symbol(schema_ref)) } } else if schema_ref is Schema { mut field := StructField{ @@ -158,7 +152,7 @@ pub fn ref_to_field(schema_ref SchemaRef, name string) !StructField { field.anon_struct = schema_to_struct(schema_ref as Schema)! return field } else if schema_ref.typ in vtypes { - field.typ.symbol = vtypes[schema_ref.typ] + field.typ = type_from_symbol(vtypes[schema_ref.typ]) return field } return error('Schema type ${schema_ref.typ} not supported for code generation') @@ -170,9 +164,7 @@ pub fn schemaref_to_type(schema_ref SchemaRef) !Type { return if schema_ref is Reference { ref_to_type_from_reference(schema_ref as Reference) } else { - Type{ - symbol: schema_to_type(schema_ref as Schema)! - } + schema_to_type(schema_ref as Schema)! } } @@ -181,7 +173,5 @@ pub fn ref_to_symbol(reference Reference) string { } pub fn ref_to_type_from_reference(reference Reference) Type { - return Type{ - symbol: ref_to_symbol(reference) - } + return type_from_symbol(ref_to_symbol(reference)) } \ No newline at end of file diff --git a/lib/schemas/jsonschema/codegen/generate.v b/lib/schemas/jsonschema/codegen/generate.v index e79130ef..402ff76e 100644 --- a/lib/schemas/jsonschema/codegen/generate.v +++ b/lib/schemas/jsonschema/codegen/generate.v @@ -7,7 +7,7 @@ import freeflowuniverse.herolib.schemas.jsonschema { SchemaRef, Schema, Referenc pub fn sumtype_to_schema(sumtype code.Sumtype) SchemaRef { mut one_of := []SchemaRef{} for type_ in sumtype.types { - property_schema := typesymbol_to_schema(type_.symbol) + property_schema := typesymbol_to_schema(type_.symbol()) one_of << property_schema } @@ -25,7 +25,7 @@ pub fn struct_to_schema(struct_ Struct) SchemaRef { mut properties := map[string]SchemaRef{} for field in struct_.fields { mut property_schema := SchemaRef(Schema{}) - if field.typ.symbol.starts_with('_VAnonStruct') { + if field.typ.symbol().starts_with('_VAnonStruct') { property_schema = struct_to_schema(field.anon_struct) } else { property_schema = type_to_schema(field.typ) @@ -57,14 +57,7 @@ pub fn param_to_schema(param Param) SchemaRef { if param.struct_ != Struct{} { return struct_to_schema(param.struct_) } - return typesymbol_to_schema(param.typ.symbol) -} - -pub fn result_to_schema(result Result) SchemaRef { - if result.structure != Struct{} { - return struct_to_schema(result.structure) - } - return typesymbol_to_schema(result.typ.symbol) + return typesymbol_to_schema(param.typ.symbol()) } // typesymbol_to_schema receives a typesymbol, if the typesymbol belongs to a user defined struct @@ -172,12 +165,12 @@ pub fn typesymbol_to_schema(symbol_ string) SchemaRef { } pub fn type_to_schema(typ Type) SchemaRef { - mut symbol := typ.symbol.trim_string_left('!').trim_string_left('?') + mut symbol := typ.symbol().trim_string_left('!').trim_string_left('?') if symbol == '' { return SchemaRef(Schema{ typ: 'null' }) - } else if symbol.starts_with('[]') || typ.is_array { + } else if symbol.starts_with('[]') { mut array_type := symbol.trim_string_left('[]') return SchemaRef(Schema{ typ: 'array' diff --git a/lib/schemas/openrpc/codegen/generate_handler.v b/lib/schemas/openrpc/codegen/generate_handler.v index aacfb9a9..1dcef52b 100644 --- a/lib/schemas/openrpc/codegen/generate_handler.v +++ b/lib/schemas/openrpc/codegen/generate_handler.v @@ -55,7 +55,7 @@ pub fn generate_handler_test_file(o OpenRPC, receiver Struct, method_map map[str if method.params.len == 0 { continue } - if method.params[0].typ.symbol[0].is_capital() { + if method.params[0].typ.symbol()[0].is_capital() { continue } method_handle_test := Function{ @@ -64,7 +64,7 @@ pub fn generate_handler_test_file(o OpenRPC, receiver Struct, method_map map[str is_result: true } body: "mut handler := ${receiver.name}Handler {${handler_name}.get(name: actor_name)!} - request := new_jsonrpcrequest[${method.params[0].typ.symbol}]('${method.name}', ${get_mock_value(method.params[0].typ.symbol)!}) + request := new_jsonrpcrequest[${method.params[0].typ.symbol()}]('${method.name}', ${get_mock_value(method.params[0].typ.symbol())!}) response_json := handler.handle(request.to_json())!" } handle_tests << method_handle_test