Files
herolib/lib/core/code/model_function.v
2025-10-12 12:30:19 +03:00

163 lines
4.1 KiB
V

module code
import incubaid.herolib.core.texttools
pub struct Function {
pub:
name string @[omitempty]
receiver Param @[omitempty]
is_pub bool @[omitempty]
mod string @[omitempty]
pub mut:
summary string @[omitempty]
description string @[omitempty]
params []Param @[omitempty]
body string @[omitempty]
result Param @[omitempty]
has_return bool @[omitempty]
}
// vgen_function generates a function statement for a function
pub fn (function Function) vgen(options WriteOptions) string {
mut params_ := function.params.clone()
optionals := function.params.filter(it.is_optional)
options_struct := Struct{
name: '${texttools.pascal_case(function.name)}Options'
attrs: [Attribute{
name: 'params'
}]
fields: optionals.map(StructField{
name: it.name
description: it.description
typ: it.typ
})
}
if optionals.len > 0 {
params_ << Param{
name: 'options'
typ: type_from_symbol(options_struct.name)
}
}
params := params_.filter(!it.is_optional).map(it.vgen()).join(', ')
receiver_ := Param{
...function.receiver
typ: if function.receiver.typ is Result {
function.receiver.typ.typ
} else {
function.receiver.typ
}
}
receiver := if receiver_.vgen().trim_space() != '' {
'(${receiver_.vgen()})'
} else {
''
}
name := texttools.name_fix(function.name)
result := function.result.typ.vgen()
mut function_str := $tmpl('templates/function/function.v.template')
// if options.format {
// result := os.execute_opt('echo "${function_str.replace('$', '\\$')}" | v fmt') or {
// panic('${function_str}\n${err}')
// }
// function_str = result.output
// }
function_str = function_str.split_into_lines().filter(!it.starts_with('import ')).join('\n')
return if options_struct.fields.len != 0 {
'${options_struct.vgen()}\n${function_str}'
} else {
function_str
}
}
pub fn new_function(code string) !Function {
// TODO: implement function from file line
return parse_function(code)!
}
pub fn parse_function(code_ string) !Function {
// Extract comments and actual function code
mut lines := code_.split_into_lines()
mut comment_lines := []string{}
mut function_lines := []string{}
mut in_function := false
for line in lines {
trimmed := line.trim_space()
if !in_function && trimmed.starts_with('//') {
comment_lines << trimmed.trim_string_left('//').trim_space()
} else if !in_function && (trimmed.starts_with('pub fn') || trimmed.starts_with('fn')) {
in_function = true
function_lines << line
} else if in_function {
function_lines << line
}
}
// Process the function code
mut code := function_lines.join('\n').trim_space()
is_pub := code.starts_with('pub ')
if is_pub {
code = code.trim_string_left('pub ').trim_space()
}
is_fn := code.starts_with('fn ')
if !is_fn {
return error('invalid function format')
}
code = code.trim_string_left('fn ').trim_space()
receiver := if code.starts_with('(') {
param_str := code.all_after('(').all_before(')').trim_space()
code = code.all_after(')').trim_space()
parse_param(param_str)!
} else {
Param{}
}
name := code.all_before('(').trim_space()
code = code.trim_string_left(name).trim_space()
params_str := code.all_after('(').all_before(')')
params := if params_str.trim_space() != '' {
params_str_lst := params_str.split(',')
params_str_lst.map(parse_param(it)!)
} else {
[]Param{}
}
// Extract the result type, handling the ! for result types
mut result_type := code.all_after(')').all_before('{').replace(' ', '')
mut has_return := false
// Check if the result type contains !
if result_type.contains('!') {
has_return = true
result_type = result_type.replace('!', '')
}
result := new_param(
v: result_type
)!
body := if code.contains('{') { code.all_after('{').all_before_last('}') } else { '' }
// Process the comments into a description
description := comment_lines.join('\n')
return Function{
name: name
receiver: receiver
params: params
result: result
body: body
description: description
is_pub: is_pub
has_return: has_return
}
}