Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: feat parser api for multiple SDKs #978

Merged
merged 8 commits into from
Jan 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions kclvm/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 0 additions & 11 deletions kclvm/api/src/capi_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ use crate::gpyrpc::*;
use crate::service::capi::*;
use once_cell::sync::Lazy;
use prost::Message;
use ra_ap_vfs::Vfs;
use serde::de::DeserializeOwned;
use std::default::Default;
use std::ffi::{CStr, CString};
Expand Down Expand Up @@ -144,16 +143,6 @@ fn test_c_api_call_exec_program_with_compile_only() {
);
}

#[test]
fn test_c_api_call_exec_program_with_recursive() {
test_c_api::<ExecProgramArgs, ExecProgramResult, _>(
"KclvmService.ExecProgram",
"exec-program-with-recursive.json",
"exec-program-with-recursive.response.json",
|_| {},
);
}

#[test]
fn test_c_api_validate_code() {
test_c_api_without_wrapper::<ValidateCodeArgs, ValidateCodeResult>(
Expand Down
42 changes: 42 additions & 0 deletions kclvm/api/src/service/capi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,8 @@ pub extern "C" fn kclvm_service_call(
pub(crate) fn kclvm_get_service_fn_ptr_by_name(name: &str) -> u64 {
match name {
"KclvmService.Ping" => ping as *const () as u64,
"KclvmService.ParseFile" => parse_file as *const () as u64,
"KclvmService.ParseProgram" => parse_program as *const () as u64,
"KclvmService.ExecProgram" => exec_program as *const () as u64,
"KclvmService.OverrideFile" => override_file as *const () as u64,
"KclvmService.GetSchemaType" => get_schema_type as *const () as u64,
Expand All @@ -129,6 +131,46 @@ pub(crate) fn ping(serv: *mut kclvm_service, args: *const c_char) -> *const c_ch
call!(serv, args, PingArgs, ping)
}

/// parse_file provides users with the ability to parse kcl single file
///
/// # Parameters
///
/// `serv`: [*mut kclvm_service]
/// The pointer of &\[[KclvmServiceImpl]]
///
///
/// `args`: [*const c_char]
/// the items and compile parameters selected by the user in the KCL CLI
/// serialized as protobuf byte sequence
///
/// # Returns
///
/// result: [*const c_char]
/// Result of the call serialized as protobuf byte sequence
pub(crate) fn parse_file(serv: *mut kclvm_service, args: *const c_char) -> *const c_char {
call!(serv, args, ParseFileArgs, parse_file)
}

/// parse_program provides users with the ability to parse kcl program
///
/// # Parameters
///
/// `serv`: [*mut kclvm_service]
/// The pointer of &\[[KclvmServiceImpl]]
///
///
/// `args`: [*const c_char]
/// the items and compile parameters selected by the user in the KCL CLI
/// serialized as protobuf byte sequence
///
/// # Returns
///
/// result: [*const c_char]
/// Result of the call serialized as protobuf byte sequence
pub(crate) fn parse_program(serv: *mut kclvm_service, args: *const c_char) -> *const c_char {
call!(serv, args, ParseProgramArgs, parse_program)
}

/// exec_program provides users with the ability to execute KCL code
///
/// # Parameters
Expand Down
33 changes: 32 additions & 1 deletion kclvm/api/src/service/into.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
use crate::gpyrpc::{CliConfig, KeyValuePair, LoadSettingsFilesResult};
use crate::gpyrpc::{CliConfig, Error, KeyValuePair, LoadSettingsFilesResult, Message, Position};
use kclvm_config::settings::SettingsFile;
use kclvm_error::Diagnostic;

pub(crate) trait IntoLoadSettingsFiles {
/// Convert self into the LoadSettingsFiles structure.
fn into_load_settings_files(self, files: &[String]) -> LoadSettingsFilesResult;
}

pub(crate) trait IntoError {
fn into_error(self) -> Error;
}

impl IntoLoadSettingsFiles for SettingsFile {
fn into_load_settings_files(self, files: &[String]) -> LoadSettingsFilesResult {
LoadSettingsFilesResult {
Expand Down Expand Up @@ -34,3 +39,29 @@ impl IntoLoadSettingsFiles for SettingsFile {
}
}
}

impl IntoError for Diagnostic {
fn into_error(self) -> Error {
Error {
level: self.level.to_string(),
code: format!(
"{:?}",
self.code.unwrap_or(kclvm_error::DiagnosticId::Error(
kclvm_error::ErrorKind::InvalidSyntax,
))
),
messages: self
.messages
.iter()
.map(|m| Message {
msg: m.message.clone(),
pos: Some(Position {
filename: m.range.0.filename.clone(),
line: m.range.0.line as i64,
column: m.range.0.column.unwrap_or_default() as i64,
}),
})
.collect(),
}
}
}
18 changes: 18 additions & 0 deletions kclvm/api/src/service/jsonrpc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,22 @@ fn register_kclvm_service(io: &mut IoHandler) {
};
futures::future::ready(catch!(kclvm_service_impl, args, ping))
});
io.add_method("KclvmService.ParseFile", |params: Params| {
let kclvm_service_impl = KclvmServiceImpl::default();
let args: ParseFileArgs = match params.parse() {
Ok(val) => val,
Err(err) => return futures::future::ready(Err(err)),
};
futures::future::ready(catch!(kclvm_service_impl, args, parse_file))
});
io.add_method("KclvmService.ParseProgram", |params: Params| {
let kclvm_service_impl = KclvmServiceImpl::default();
let args: ParseProgramArgs = match params.parse() {
Ok(val) => val,
Err(err) => return futures::future::ready(Err(err)),
};
futures::future::ready(catch!(kclvm_service_impl, args, parse_program))
});
io.add_method("KclvmService.ExecProgram", |params: Params| {
let kclvm_service_impl = KclvmServiceImpl::default();
let args: ExecProgramArgs = match params.parse() {
Expand Down Expand Up @@ -183,6 +199,8 @@ fn register_builtin_service(io: &mut IoHandler) {
let result = ListMethodResult {
method_name_list: vec![
"KclvmService.Ping".to_owned(),
"KclvmService.ParseFile".to_owned(),
"KclvmService.ParseProgram".to_owned(),
"KclvmService.ExecProgram".to_owned(),
"KclvmService.OverrideFile".to_owned(),
"KclvmService.GetSchemaType".to_owned(),
Expand Down
86 changes: 86 additions & 0 deletions kclvm/api/src/service/service_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ use anyhow::anyhow;
use kcl_language_server::rename;
use kclvm_config::settings::build_settings_pathbuf;
use kclvm_driver::canonicalize_input_files;
use kclvm_parser::load_program;
use kclvm_parser::parse_file;
use kclvm_parser::LoadProgramOptions;
use kclvm_parser::ParseSession;
use kclvm_query::get_schema_type;
use kclvm_query::override_file;
Expand All @@ -27,6 +30,7 @@ use kclvm_tools::vet::validator::LoaderKind;
use kclvm_tools::vet::validator::ValidateOption;
use tempfile::NamedTempFile;

use super::into::IntoError;
use super::into::IntoLoadSettingsFiles;
use super::ty::kcl_schema_ty_to_pb_ty;
use super::util::transform_str_para;
Expand Down Expand Up @@ -60,6 +64,88 @@ impl KclvmServiceImpl {
})
}

/// Parse KCL program with entry files.
///
/// # Examples
///
/// ```
/// use kclvm_api::service::service_impl::KclvmServiceImpl;
/// use kclvm_api::gpyrpc::*;
/// use std::path::Path;
/// // File case
/// let serv = KclvmServiceImpl::default();
/// let args = &ParseProgramArgs {
/// paths: vec![Path::new(".").join("src").join("testdata").join("test.k").canonicalize().unwrap().display().to_string(),],
/// ..Default::default()
/// };
/// let result = serv.parse_program(args).unwrap();
/// assert_eq!(result.errors.len(), 0);
/// assert_eq!(result.paths.len(), 1);
/// ```
pub fn parse_program(&self, args: &ParseProgramArgs) -> anyhow::Result<ParseProgramResult> {
let sess = Arc::new(ParseSession::default());
let mut package_maps = HashMap::new();
for p in &args.external_pkgs {
package_maps.insert(p.pkg_name.to_string(), p.pkg_path.to_string());
}
let paths: Vec<&str> = args.paths.iter().map(|p| p.as_str()).collect();
let result = load_program(
sess,
&paths,
Some(LoadProgramOptions {
k_code_list: args.sources.clone(),
package_maps,
..Default::default()
}),
None,
)?;
let ast_json = serde_json::to_string(&result.program)?;

Ok(ParseProgramResult {
ast_json,
paths: result
.paths
.iter()
.map(|p| p.to_str().unwrap().to_string())
.collect(),
errors: result.errors.into_iter().map(|e| e.into_error()).collect(),
})
}

/// Parse KCL single file to Module AST JSON string with import
/// dependencies and parse errors.
///
/// # Examples
///
/// ```
/// use kclvm_api::service::service_impl::KclvmServiceImpl;
/// use kclvm_api::gpyrpc::*;
/// use std::path::Path;
/// // File case
/// let serv = KclvmServiceImpl::default();
/// let args = &ParseFileArgs {
/// path: Path::new(".").join("src").join("testdata").join("parse").join("main.k").canonicalize().unwrap().display().to_string(),
/// ..Default::default()
/// };
/// let result = serv.parse_file(args).unwrap();
/// assert_eq!(result.errors.len(), 0);
/// assert_eq!(result.deps.len(), 2);
/// ```
pub fn parse_file(&self, args: &ParseFileArgs) -> anyhow::Result<ParseFileResult> {
let result = parse_file(&args.path, transform_str_para(&args.source))?;
let ast_json = serde_json::to_string(&result.module)?;

Ok(ParseFileResult {
ast_json,
deps: result
.deps
.iter()
.map(|p| p.to_str().unwrap().to_string())
.collect(),
errors: result.errors.into_iter().map(|e| e.into_error()).collect(),
})
}

/// Execute KCL file with args. **Note that it is not thread safe.**
///
/// # Examples
Expand Down
7 changes: 0 additions & 7 deletions kclvm/api/src/testdata/exec-program-with-recursive.json

This file was deleted.

This file was deleted.

Empty file.
5 changes: 5 additions & 0 deletions kclvm/api/src/testdata/parse/main.k
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import pkg1
import pkg2

a1 = pkg1.a
a2 = pkg2.a
1 change: 1 addition & 0 deletions kclvm/api/src/testdata/parse/pkg1/pkg.k
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
a = 1
1 change: 1 addition & 0 deletions kclvm/api/src/testdata/parse/pkg2/pkg.k
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
a = 1
Loading
Loading