Skip to content

Commit 065f222

Browse files
authored
Merge pull request #116 from Peefy/more-cpp-api-and-examples
feat: add more cpp api and examples
2 parents 240b13c + 357d563 commit 065f222

File tree

9 files changed

+249
-24
lines changed

9 files changed

+249
-24
lines changed

cpp/CMakeLists.txt

Lines changed: 12 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -40,27 +40,18 @@ set_target_properties(kcl-lib-cpp
4040
PROPERTIES ADDITIONAL_CLEAN_FILES ${CARGO_TARGET_DIR}
4141
)
4242

43-
add_executable(exec_api examples/exec_api.cpp)
44-
target_include_directories(exec_api PUBLIC ${CPP_INCLUDE_DIR})
45-
target_link_libraries(exec_api PUBLIC kcl-lib-cpp)
46-
# Platform-specific test configuration
47-
if(WIN32)
48-
target_link_libraries(exec_api PRIVATE userenv ws2_32 bcrypt)
49-
endif()
50-
if(APPLE)
51-
target_link_libraries(exec_api PRIVATE "-framework CoreFoundation -framework Security")
52-
endif()
53-
54-
add_executable(validate_api examples/validate_api.cpp)
55-
target_include_directories(validate_api PUBLIC ${CPP_INCLUDE_DIR})
56-
target_link_libraries(validate_api PUBLIC kcl-lib-cpp)
57-
# Platform-specific test configuration
58-
if(WIN32)
59-
target_link_libraries(validate_api PRIVATE userenv ws2_32 bcrypt)
60-
endif()
61-
if(APPLE)
62-
target_link_libraries(validate_api PRIVATE "-framework CoreFoundation -framework Security")
63-
endif()
43+
set(EXECUTABLES exec_api exec_with_deps_api override_api update_deps_api validate_api)
44+
foreach(EXE IN LISTS EXECUTABLES)
45+
add_executable(${EXE} examples/${EXE}.cpp)
46+
target_include_directories(${EXE} PUBLIC ${CPP_INCLUDE_DIR})
47+
target_link_libraries(${EXE} PUBLIC kcl-lib-cpp)
48+
if(WIN32)
49+
target_link_libraries(${EXE} PRIVATE userenv ws2_32 bcrypt)
50+
endif()
51+
if(APPLE)
52+
target_link_libraries(${EXE} PRIVATE "-framework CoreFoundation -framework Security")
53+
endif()
54+
endforeach()
6455

6556
# Platform-specific test configuration
6657
if(WIN32)
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
#include "kcl_lib.hpp"
2+
#include <iostream>
3+
4+
int main()
5+
{
6+
auto args = kcl_lib::UpdateDependenciesArgs {
7+
.manifest_path = rust::String("../test_data/update_dependencies"),
8+
};
9+
auto result = kcl_lib::update_dependencies(args);
10+
auto exec_args = kcl_lib::ExecProgramArgs {
11+
.k_filename_list = rust::Vec({ rust::String("../test_data/update_dependencies/main.k") }),
12+
.external_pkgs = result.external_pkgs,
13+
};
14+
auto exec_result = kcl_lib::exec_program(exec_args);
15+
std::cout << exec_result.yaml_result.c_str() << std::endl;
16+
return 0;
17+
}

cpp/examples/override_api.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
#include "kcl_lib.hpp"
2+
#include <iostream>
3+
4+
int main()
5+
{
6+
auto args = kcl_lib::OverrideFileArgs {
7+
.file = rust::String("../test_data/override_file/main.k"),
8+
.specs = rust::Vec({ rust::String("b.a=2") }),
9+
};
10+
auto result = kcl_lib::override_file(args);
11+
std::cout << result.result << std::endl;
12+
std::cout << result.parse_errors.size() << std::endl;
13+
return 0;
14+
}

cpp/examples/update_deps_api.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
#include "kcl_lib.hpp"
2+
#include <iostream>
3+
4+
int main()
5+
{
6+
auto args = kcl_lib::UpdateDependenciesArgs {
7+
.manifest_path = rust::String("../test_data/update_dependencies"),
8+
};
9+
auto result = kcl_lib::update_dependencies(args);
10+
std::cout << result.external_pkgs[0].pkg_name.c_str() << std::endl;
11+
std::cout << result.external_pkgs[1].pkg_name.c_str() << std::endl;
12+
return 0;
13+
}

cpp/examples/validate_api.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
#include "kcl_lib.hpp"
22
#include <iostream>
33

4-
int validate(const char* code_str, const char* data_str) {
4+
int validate(const char* code_str, const char* data_str)
5+
{
56
auto args = kcl_lib::ValidateCodeArgs();
67
args.code = rust::String(code_str);
78
args.data = rust::String(data_str);

cpp/src/lib.rs

Lines changed: 174 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,17 +45,50 @@ mod ffi {
4545
}
4646

4747
/// kcl main.k -E name=path
48+
#[derive(Clone)]
4849
pub struct ExternalPkg {
4950
pub pkg_name: String,
5051
pub pkg_path: String,
5152
}
5253

5354
/// kcl main.k -D name=value
55+
#[derive(Clone)]
5456
pub struct Argument {
57+
/// Name of the argument.
5558
pub name: String,
59+
/// Value of the argument.
5660
pub value: String,
5761
}
5862

63+
/// Message representing an error.
64+
pub struct Error {
65+
/// Level of the error (e.g., "Error", "Warning").
66+
pub level: String,
67+
/// Error code. (e.g., "E1001")
68+
pub code: String,
69+
/// List of error messages.
70+
pub messages: Vec<Message>,
71+
}
72+
73+
/// Message representing a detailed error message with a position.
74+
pub struct Message {
75+
/// The error message text.
76+
pub msg: String,
77+
/// The position in the source code where the error occurred.
78+
pub pos: Position,
79+
}
80+
81+
/// Message representing a position in the source code.
82+
#[derive(Default)]
83+
pub struct Position {
84+
/// Line number.
85+
pub line: i64,
86+
/// Column number.
87+
pub column: i64,
88+
/// Filename the position refers to.
89+
pub filename: String,
90+
}
91+
5992
/// Message for execute program response.
6093
pub struct ExecProgramResult {
6194
/// Result in JSON format.
@@ -94,23 +127,131 @@ mod ffi {
94127
err_message: String,
95128
}
96129

130+
/// Message for override file request arguments.
131+
pub struct OverrideFileArgs {
132+
/// Path of the file to override.
133+
file: String,
134+
/// List of override specifications.
135+
specs: Vec<String>,
136+
/// List of import paths.
137+
import_paths: Vec<String>,
138+
}
139+
140+
/// Message for override file response.
141+
pub struct OverrideFileResult {
142+
/// Result of the override operation.
143+
pub result: bool,
144+
// List of parse errors encountered.
145+
pub parse_errors: Vec<Error>,
146+
}
147+
148+
/// Message for update dependencies request arguments.
149+
pub struct UpdateDependenciesArgs {
150+
/// Path to the manifest file.
151+
pub manifest_path: String,
152+
/// Flag to vendor dependencies locally.
153+
pub vendor: bool,
154+
}
155+
156+
/// Message for update dependencies response.
157+
pub struct UpdateDependenciesResult {
158+
/// List of external packages updated.
159+
pub external_pkgs: Vec<ExternalPkg>,
160+
}
161+
97162
extern "Rust" {
163+
/// Execute KCL file with arguments and return the JSON/YAML result.
98164
fn exec_program(args: &ExecProgramArgs) -> Result<ExecProgramResult>;
165+
/// Validate code using schema and JSON/YAML data strings.
99166
fn validate_code(args: &ValidateCodeArgs) -> Result<ValidateCodeResult>;
167+
/// Override KCL file with arguments.
168+
/// See [https://www.kcl-lang.io/docs/user_docs/guides/automation](https://www.kcl-lang.io/docs/user_docs/guides/automation)
169+
/// for more override spec guide.
170+
fn override_file(args: &OverrideFileArgs) -> Result<OverrideFileResult>;
171+
/// Download and update dependencies defined in the `kcl.mod` file and return the
172+
/// external package name and location list.
173+
fn update_dependencies(args: &UpdateDependenciesArgs) -> Result<UpdateDependenciesResult>;
100174
}
101175
}
102176

103177
use ffi::*;
104178

179+
impl crate::ffi::Error {
180+
pub fn new(e: &kclvm_api::Error) -> Self {
181+
Self {
182+
level: e.level.clone(),
183+
code: e.code.clone(),
184+
messages: e
185+
.messages
186+
.iter()
187+
.map(|m| Message {
188+
msg: m.msg.clone(),
189+
pos: m
190+
.pos
191+
.as_ref()
192+
.map(|p| Position {
193+
line: p.line,
194+
column: p.column,
195+
filename: p.filename.clone(),
196+
})
197+
.unwrap_or_default(),
198+
})
199+
.collect(),
200+
}
201+
}
202+
}
203+
204+
impl UpdateDependenciesResult {
205+
pub fn new(r: kclvm_api::UpdateDependenciesResult) -> Self {
206+
Self {
207+
external_pkgs: r
208+
.external_pkgs
209+
.iter()
210+
.map(|p| ExternalPkg {
211+
pkg_name: p.pkg_name.clone(),
212+
pkg_path: p.pkg_path.clone(),
213+
})
214+
.collect(),
215+
}
216+
}
217+
}
218+
105219
/// Execute KCL file with arguments and return the JSON/YAML result.
106220
fn exec_program(args: &ExecProgramArgs) -> Result<ExecProgramResult> {
107221
let api = kclvm_api::API::default();
108222
let result = api.exec_program(&kclvm_api::ExecProgramArgs {
109223
work_dir: args.work_dir.clone(),
110224
k_filename_list: args.k_filename_list.clone(),
111225
k_code_list: args.k_code_list.clone(),
112-
// TODO: other arguments.
113-
..Default::default()
226+
args: args
227+
.args
228+
.iter()
229+
.map(|a| kclvm_api::Argument {
230+
name: a.name.clone(),
231+
value: a.value.clone(),
232+
})
233+
.collect::<Vec<kclvm_api::Argument>>(),
234+
external_pkgs: args
235+
.external_pkgs
236+
.iter()
237+
.map(|e| kclvm_api::ExternalPkg {
238+
pkg_name: e.pkg_name.clone(),
239+
pkg_path: e.pkg_path.clone(),
240+
})
241+
.collect::<Vec<kclvm_api::ExternalPkg>>(),
242+
overrides: args.overrides.clone(),
243+
strict_range_check: args.strict_range_check,
244+
disable_none: args.disable_none,
245+
verbose: args.verbose,
246+
debug: args.debug,
247+
sort_keys: args.sort_keys,
248+
show_hidden: args.show_hidden,
249+
compile_only: args.compile_only,
250+
path_selector: args.path_selector.clone(),
251+
fast_eval: args.fast_eval,
252+
disable_yaml_result: args.disable_yaml_result,
253+
include_schema_type_path: args.include_schema_type_path,
254+
print_override_ast: args.print_override_ast,
114255
})?;
115256
Ok(ExecProgramResult {
116257
yaml_result: result.yaml_result,
@@ -137,3 +278,34 @@ fn validate_code(args: &ValidateCodeArgs) -> Result<ValidateCodeResult> {
137278
err_message: result.err_message,
138279
})
139280
}
281+
282+
/// Override KCL file with arguments.
283+
/// See [https://www.kcl-lang.io/docs/user_docs/guides/automation](https://www.kcl-lang.io/docs/user_docs/guides/automation)
284+
/// for more override spec guide.
285+
fn override_file(args: &OverrideFileArgs) -> Result<OverrideFileResult> {
286+
let api = kclvm_api::API::default();
287+
let result = api.override_file(&kclvm_api::OverrideFileArgs {
288+
file: args.file.clone(),
289+
specs: args.specs.clone(),
290+
import_paths: args.import_paths.clone(),
291+
})?;
292+
Ok(OverrideFileResult {
293+
result: result.result,
294+
parse_errors: result
295+
.parse_errors
296+
.iter()
297+
.map(crate::ffi::Error::new)
298+
.collect(),
299+
})
300+
}
301+
302+
/// Download and update dependencies defined in the `kcl.mod` file and return the
303+
/// external package name and location list.
304+
fn update_dependencies(args: &UpdateDependenciesArgs) -> Result<UpdateDependenciesResult> {
305+
let api = kclvm_api::API::default();
306+
let result = api.update_dependencies(&kclvm_api::UpdateDependenciesArgs {
307+
manifest_path: args.manifest_path.clone(),
308+
vendor: args.vendor,
309+
})?;
310+
Ok(UpdateDependenciesResult::new(result))
311+
}

cpp/test_data/override_file/main.k

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
a = 1
2+
b = {
3+
"a": 2
4+
"b": 2
5+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
[package]
2+
name = "mod_update"
3+
edition = "0.0.1"
4+
version = "0.0.1"
5+
6+
[dependencies]
7+
helloworld = { oci = "oci://ghcr.io/kcl-lang/helloworld", tag = "0.1.0" }
8+
flask = { git = "https://github.com/kcl-lang/flask-demo-kcl-manifests", commit = "ade147b" }
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
import helloworld
2+
import flask
3+
4+
a = helloworld.The_first_kcl_program

0 commit comments

Comments
 (0)