Files
herolib/lib/baobab/generator/generate_methods.v
2025-02-13 03:29:36 +03:00

122 lines
4.6 KiB
V

module generator
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 {ContentDescriptor}
import freeflowuniverse.herolib.schemas.openrpc.codegen {content_descriptor_to_parameter, content_descriptor_to_struct}
import freeflowuniverse.herolib.schemas.jsonschema {Schema}
import freeflowuniverse.herolib.schemas.jsonschema.codegen as jsonschema_codegen {schema_to_struct}
import freeflowuniverse.herolib.baobab.specification {ActorMethod, ActorSpecification}
const crud_prefixes = ['new', 'get', 'set', 'delete', 'list']
pub fn generate_methods_file(spec ActorSpecification) !VFile {
name_snake := texttools.snake_case(spec.name)
actor_name_pascal := texttools.snake_case_to_pascal(spec.name)
receiver := generate_methods_receiver(spec.name)
receiver_param := Param {
mutable: true
name: name_snake[0].ascii_str() // receiver is first letter of domain
typ: code.Result{code.Object{receiver.name}}
}
mut items := [CodeItem(receiver), CodeItem(generate_core_factory(receiver_param))]
for method in spec.methods {
items << generate_method_code(receiver_param, ActorMethod{...method, category: spec.method_type(method)})!
}
return VFile {
name: 'methods'
imports: [Import{mod: 'freeflowuniverse.herolib.baobab.osis', types: ['OSIS']}]
items: items
}
}
fn generate_methods_receiver(name string) code.Struct {
return code.Struct {
is_pub: true
name: '${texttools.pascal_case(name)}'
fields: [code.StructField{is_mut: true, name: 'osis', typ:code.Object{'OSIS'}}]
}
}
fn generate_core_factory(receiver code.Param) code.Function {
return code.Function {
is_pub: true
name: 'new_${receiver.typ.symbol()}'
body: "return ${receiver.typ.symbol().trim_left('!?')}{osis: osis.new()!}"
result: receiver
}
}
// returns bodyless method prototype
pub fn generate_method_code(receiver code.Param, method ActorMethod) ![]CodeItem {
result_param := content_descriptor_to_parameter(method.result)!
mut method_code := []CodeItem{}
// TODO: document assumption
obj_params := method.parameters.filter(if it.schema is Schema {it.schema.typ == 'object'} else {false}).map(content_descriptor_to_struct(it))
if obj_param := obj_params[0] {
method_code << obj_param
}
// check if method is a Base Object CRUD Method and
// if so generate the method's body
body := match method.category {
.base_object_new { base_object_new_body(receiver, method)! }
.base_object_get { base_object_get_body(receiver, method)! }
.base_object_set { base_object_set_body(receiver, method)! }
.base_object_delete { base_object_delete_body(receiver, method)! }
.base_object_list { base_object_list_body(receiver, method)! }
else {"panic('implement')"}
}
fn_prototype := generate_method_prototype(receiver, method)!
method_code << Function{
...fn_prototype
body: body
}
return method_code
}
// returns bodyless method prototype
pub fn generate_method_prototype(receiver code.Param, method ActorMethod) !Function {
result_param := content_descriptor_to_parameter(method.result)!
return Function{
name: texttools.snake_case(method.name)
receiver: receiver
result: Param {...result_param, typ: Result{result_param.typ}}
summary: method.summary
description: method.description
params: method.parameters.map(content_descriptor_to_parameter(it)!)
}
}
fn base_object_new_body(receiver Param, method ActorMethod) !string {
parameter := content_descriptor_to_parameter(method.parameters[0])!
return 'return ${receiver.name}.osis.new[${parameter.typ.vgen()}](${texttools.snake_case(parameter.name)})!'
}
fn base_object_get_body(receiver Param, method ActorMethod) !string {
parameter := content_descriptor_to_parameter(method.parameters[0])!
result := content_descriptor_to_parameter(method.result)!
return 'return ${receiver.name}.osis.get[${result.typ.vgen()}](${texttools.snake_case(parameter.name)})!'
}
fn base_object_set_body(receiver Param, method ActorMethod) !string {
parameter := content_descriptor_to_parameter(method.parameters[0])!
return 'return ${receiver.name}.osis.set[${parameter.typ.vgen()}](${parameter.name})!'
}
fn base_object_delete_body(receiver Param, method ActorMethod) !string {
parameter := content_descriptor_to_parameter(method.parameters[0])!
return '${receiver.name}.osis.delete(${texttools.snake_case(parameter.name)})!'
}
fn base_object_list_body(receiver Param, method ActorMethod) !string {
result := content_descriptor_to_parameter(method.result)!
base_object_type := (result.typ as Array).typ
return 'return ${receiver.name}.osis.list[${base_object_type.symbol()}]()!'
}