...
This commit is contained in:
@@ -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
|
||||
Reference in New Issue
Block a user