This commit is contained in:
2025-11-23 05:01:31 +01:00
parent 679108eb9e
commit 0916ff07f8

View File

@@ -1,73 +1,270 @@
# Code Model
A set of models that represent code, such as structs and functions. The motivation behind this module is to provide a more generic, and lighter alternative to v.ast code models, that can be used for code parsing and code generation across multiple languages.
A comprehensive module for parsing, analyzing, and generating V code. The Code Model provides lightweight, language-agnostic structures to represent code elements like structs, functions, imports, and types.
## Using Codemodel
## Overview
While the models in this module can be used in any domain, the models here are used extensively in the modules [codeparser](../codeparser/) and codegen (under development). Below are examples on how codemodel can be used for parsing and generating code.
## Code parsing with codemodel
The `code` module is useful for:
As shown in the example below, the codemodels returned by the parser can be used to infer information about the code written
- **Code Parsing**: Parse V files into structured models
- **Code Analysis**: Extract information about functions, structs, and types
- **Code Generation**: Generate V code from models using `vgen()`
- **Static Analysis**: Inspect and traverse code using language utilities
- **Documentation Generation**: Serialize code into other formats (JSON, Markdown, etc.)
```js
code := codeparser.parse("somedir") // code is a list of code models
## Core Components
num_functions := code.filter(it is Function).len
structs := code.filter(it is Struct)
println("This directory has ${num_functions} functions")
println('The directory has the structs: ${structs.map(it.name)}')
### Code Structures (Models)
- **`Struct`**: Represents V struct definitions with fields, visibility, and generics
- **`Function`**: Represents functions/methods with parameters, return types, and bodies
- **`Interface`**: Represents V interface definitions
- **`VFile`**: Represents a complete V file with module, imports, constants, and items
- **`Module`**: Represents a V module with nested files and folders
- **`Import`**: Represents import statements
- **`Param`**: Represents function parameters with types and modifiers
- **`Type`**: Union type supporting arrays, maps, results, objects, and basic types
- **`Const`**: Represents constant definitions
### Type System
The `Type` union supports:
- Basic types: `String`, `Boolean`, `Integer` (signed/unsigned, 8/16/32/64-bit)
- Composite types: `Array`, `Map`, `Object`
- Function types: `Function`
- Result types: `Result` (for error handling with `!`)
- Aliases: `Alias`
## Usage Examples
### Parsing a V File
```v
import incubaid.herolib.core.code
import os
// Read and parse a V file
content := os.read_file('path/to/file.v')!
vfile := code.parse_vfile(content)!
// Access parsed elements
println('Module: ${vfile.mod}')
println('Imports: ${vfile.imports.len}')
println('Structs: ${vfile.structs().len}')
println('Functions: ${vfile.functions().len}')
```
or can be used as intermediate structures to serialize code into some other format:
### Analyzing Structs
```js
code_md := ''
```v
import incubaid.herolib.core.code
// describes the struct in markdown format
for struct in structs {
code_md += '# ${struct.name}'
code_md += 'Type: ${struct.typ.symbol()}'
code_md += '## Fields:'
for field in struct.fields {
code_md += '- ${field.name}'
// Parse a struct definition
struct_code := 'pub struct User {
pub:
name string
age int
}'
vfile := code.parse_vfile(struct_code)!
structs := vfile.structs()
for struct_ in structs {
println('Struct: ${struct_.name}')
println(' Is public: ${struct_.is_pub}')
for field in struct_.fields {
println(' Field: ${field.name} (${field.typ.symbol()})')
}
}
```
The [openrpc/docgen](../openrpc/docgen/) module demonstrates a good use case, where codemodels are serialized into JSON schema's, to generate an OpenRPC description document from a client in v.## V Language Utilities
The `vlang_utils.v` file provides a set of utility functions for working with V language files and code. These utilities are useful for:
1. **File Operations**
- `list_v_files(dir string) ![]string` - Lists all V files in a directory, excluding generated files
- `get_module_dir(mod string) string` - Converts a V module path to a directory path
2. **Code Inspection and Analysis**
- `get_function_from_file(file_path string, function_name string) !string` - Extracts a function definition from a file
- `get_function_from_module(module_path string, function_name string) !string` - Searches for a function across all files in a module
- `get_type_from_module(module_path string, type_name string) !string` - Searches for a type definition across all files in a module
3. **V Language Tools**
- `vtest(fullpath string) !string` - Runs V tests on files or directories
- `vvet(fullpath string) !string` - Runs V vet on files or directories
### Example Usage
### Analyzing Functions
```v
// Find and extract a function definition
function_def := code.get_function_from_module('/path/to/module', 'my_function') or {
eprintln('Could not find function: ${err}')
return
}
println(function_def)
import incubaid.herolib.core.code
// Run tests on a directory
test_results := code.vtest('/path/to/module') or {
eprintln('Tests failed: ${err}')
return
fn_code := 'pub fn greet(name string) string {
return "Hello, \${name}!"
}'
vfile := code.parse_vfile(fn_code)!
functions := vfile.functions()
for func in functions {
println('Function: ${func.name}')
println(' Public: ${func.is_pub}')
println(' Parameters: ${func.params.len}')
println(' Returns: ${func.result.typ.symbol()}')
}
println(test_results)
```
These utilities are particularly useful when working with code generation, static analysis, or when building developer tools that need to inspect V code.
### Code Generation
```v
import incubaid.herolib.core.code
// Create a struct model
my_struct := code.Struct{
name: 'Person'
is_pub: true
fields: [
code.StructField{
name: 'name'
typ: code.type_from_symbol('string')
is_pub: true
},
code.StructField{
name: 'age'
typ: code.type_from_symbol('int')
is_pub: true
}
]
}
// Generate V code from the model
generated_code := my_struct.vgen()
println(generated_code)
// Output: pub struct Person { ... }
```
### V Language Utilities
```v
import incubaid.herolib.core.code
// List all V files in a directory (excludes generated files ending with _.v)
v_files := code.list_v_files('/path/to/module')!
// Get a specific function from a module
func := code.get_function_from_module('/path/to/module', 'my_function')!
println('Found function: ${func.name}')
// Get a type definition from a module
type_def := code.get_type_from_module('/path/to/module', 'MyStruct')!
println(type_def)
// Run V tests
test_results := code.vtest('/path/to/module')!
```
### Working With Modules and Files
```v
import incubaid.herolib.core.code
// Create a module structure
my_module := code.Module{
name: 'mymodule'
description: 'My awesome module'
version: '1.0.0'
license: 'apache2'
files: [
code.VFile{
name: 'structs'
mod: 'mymodule'
// ... add items
}
]
}
// Write module to disk
write_opts := code.WriteOptions{
overwrite: false
format: true
compile: false
}
my_module.write('/output/path', write_opts)!
```
### Advanced Features
### Custom Code Generation
```v
import incubaid.herolib.core.code
// Generate a function call from a Function model
func := code.Function{
name: 'calculate'
params: [
code.Param{ name: 'x', typ: code.type_from_symbol('int') },
code.Param{ name: 'y', typ: code.type_from_symbol('int') }
]
result: code.Param{ typ: code.type_from_symbol('int') }
}
call := func.generate_call(receiver: 'calculator')!
// Output: result := calculator.calculate(...)
```
### Type Conversion
```v
import incubaid.herolib.core.code
// Convert from type symbol to Type model
t := code.type_from_symbol('[]string')
// Get the V representation
v_code := t.vgen() // Output: "[]string"
// Get the TypeScript representation
ts_code := t.typescript() // Output: "string[]"
// Get the symbol representation
symbol := t.symbol() // Output: "[]string"
```
## Complete Example
See the working example at **`examples/core/code/code_parser.vsh`** for a complete demonstration of:
- Listing V files in a directory
- Parsing multiple V files
- Extracting and analyzing structs and functions
- Summarizing module contents
Run it with:
```bash
vrun ~/code/github/incubaid/herolib/examples/core/code/code_parser.vsh
```
## Coding Instructions
When using the Code module:
1. **Always parse before analyzing**: Use `parse_vfile()`, `parse_struct()`, or `parse_function()` to create models from code strings
2. **Use type filters**: Filter code items by type using `.filter(it is StructType)` pattern
3. **Check visibility**: Always verify `is_pub` flag when examining public API
4. **Handle errors**: Code parsing can fail; always use `!` or `or` blocks
5. **Generate code carefully**: Use `WriteOptions` to control formatting, compilation, and testing
6. **Use language utilities**: Prefer `get_function_from_module()` over manual file searching
7. **Cache parsed results**: Store `VFile` objects if you need to access them multiple times
8. **Document generated code**: Add descriptions to generated structs and functions
## API Reference
### Parsing Functions
- `parse_vfile(code string) !VFile` - Parse an entire V file
- `parse_struct(code string) !Struct` - Parse a struct definition
- `parse_function(code string) !Function` - Parse a function definition
- `parse_param(code string) !Param` - Parse a parameter
- `parse_type(type_str string) Type` - Parse a type string
- `parse_const(code string) !Const` - Parse a constant
- `parse_import(code string) Import` - Parse an import statement
### Code Generation
- `vgen(code []CodeItem) string` - Generate V code from code items
- `Struct.vgen() string` - Generate struct V code
- `Function.vgen() string` - Generate function V code
- `Interface.vgen() string` - Generate interface V code
- `Import.vgen() string` - Generate import statement
### Language Utilities
- `list_v_files(dir string) ![]string` - List V files in directory
- `get_function_from_module(module_path string, name string) !Function` - Find function
- `get_type_from_module(module_path string, name string) !string` - Find type definition
- `get_module_dir(mod string) string` - Convert module name to directory path