Skip to content

Commit

Permalink
enhance: doc parser support schema example
Browse files Browse the repository at this point in the history
  • Loading branch information
amyXia1994 committed Sep 8, 2023
1 parent d3a1111 commit 8cf50e6
Show file tree
Hide file tree
Showing 6 changed files with 47 additions and 11 deletions.
2 changes: 1 addition & 1 deletion kclvm/api/src/testdata/get-schema-type-mapping.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{
"file": "schema.k",
"code": "@info(name=\"ServerSchema\")\nschema Server:\n \"\"\"Server is the common user interface for long-running\n services adopting the best practice of Kubernetes.\n\n Attributes\n ----------\n workloadType: str, default is \"Deployment\", required\n Use this attribute to specify which kind of long-running service you want.\n Valid values: Deployment, CafeDeployment.\n See also: kusion_models/core/v1/workload_metadata.k.\n name: str, required\n A Server-level attribute.\n The name of the long-running service.\n See also: kusion_models/core/v1/metadata.k.\n labels: {str:str}, optional\n A Server-level attribute.\n The labels of the long-running service.\n See also: kusion_models/core/v1/metadata.k.\n\n Examples\n ----------------------\n myCustomApp = AppConfiguration {\n name = \"componentName\"\n }\n \"\"\"\n workloadType: str = \"Deployment\"\n @info(\"name\", key=\"value\")\n name: str\n labels?: {str:str}\n useCustomizeLables: True | False\n containers: [Container]\n\nschema Container:\n \"\"\"Container is the common user interface for long-running services.\n\n Attributes\n ----------\n name: str, required\n The name of the long-running container.\n \"\"\"\n name: str\n"
"code": "@info(name=\"ServerSchema\")\nschema Server:\n \"\"\"Server is the common user interface for long-running\n services adopting the best practice of Kubernetes.\n\n Attributes\n ----------\n workloadType: str, default is \"Deployment\", required\n Use this attribute to specify which kind of long-running service you want.\n Valid values: Deployment, CafeDeployment.\n See also: kusion_models/core/v1/workload_metadata.k.\n name: str, required\n A Server-level attribute.\n The name of the long-running service.\n See also: kusion_models/core/v1/metadata.k.\n labels: {str:str}, optional\n A Server-level attribute.\n The labels of the long-running service.\n See also: kusion_models/core/v1/metadata.k.\n\n Examples\n --------\n myCustomApp = AppConfiguration {\n name = \"componentName\"\n }\n \"\"\"\n workloadType: str = \"Deployment\"\n @info(\"name\", key=\"value\")\n name: str\n labels?: {str:str}\n useCustomizeLables: True | False\n containers: [Container]\n\nschema Container:\n \"\"\"Container is the common user interface for long-running services.\n\n Attributes\n ----------\n name: str, required\n The name of the long-running container.\n \"\"\"\n name: str\n"
}
40 changes: 34 additions & 6 deletions kclvm/sema/src/resolver/doc.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use pcre2::bytes::Regex;
use std::collections::HashSet;
use std::collections::{HashSet, HashMap};
use std::iter::Iterator;
use std::str;

Expand Down Expand Up @@ -259,7 +259,7 @@ fn parse_summary(doc: &mut Reader) -> String {
/// The description of each attribute will be returned as separate lines.
pub(crate) fn parse_doc_string(ori: &String) -> Doc {
if ori.is_empty() {
return Doc::new("".to_string(), vec![]);
return Doc::new("".to_string(), vec![], HashMap::new());
}
let mut ori = ori.clone();
strip_quotes(&mut ori);
Expand All @@ -274,19 +274,29 @@ pub(crate) fn parse_doc_string(ori: &String) -> Doc {

let attrs = parse_attr_list(attr_content);

Doc::new(summary, attrs)
let example_section = read_to_next_section(&mut doc);
let default_example_content = match example_section.len() {
0 | 1 | 2 => "".to_string(),
_ => example_section[2..].join("\n"),
};
let mut examples = HashMap::new();
examples.insert("Default example".to_string(), Example::new("".to_string(), "".to_string(), default_example_content));


Doc::new(summary, attrs, examples)
}

/// The Doc struct contains a summary of schema and all the attributes described in the the docstring.
#[derive(Debug, PartialEq, Eq, Clone)]
pub(crate) struct Doc {
pub summary: String,
pub attrs: Vec<Attribute>,
pub examples: HashMap<String, Example>,
}

impl Doc {
fn new(summary: String, attrs: Vec<Attribute>) -> Self {
Self { summary, attrs }
fn new(summary: String, attrs: Vec<Attribute>, examples: HashMap<String, Example>) -> Self {
Self { summary, attrs, examples: examples }
}
}

Expand All @@ -303,10 +313,24 @@ impl Attribute {
}
}

/// The Example struct contains the example summary and the literal content
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct Example {
pub summary: String,
pub description: String,
pub value: String,
}

impl Example {
fn new(summary: String, description: String, value: String) -> Self {
Self { summary, description, value }
}
}

#[cfg(test)]
mod tests {
use super::{clean_doc, is_at_section, read_to_next_section, strip_quotes, Reader};
use crate::resolver::doc::parse_doc_string;
use crate::resolver::doc::{parse_doc_string, Example};
use std::fs::File;
use std::io::prelude::*;
use std::path::PathBuf;
Expand Down Expand Up @@ -586,5 +610,9 @@ unindented line
"See also: kusion_models/core/v1/metadata.k.".to_string(),
]
);
assert!(doc.examples.contains_key("Default example"));
assert_eq!(doc.examples.get("Default example"), Some(&Example::new("".to_string(), "".to_string(), "myCustomApp = AppConfiguration {
name = \"componentName\"
}".to_string())));
}
}
7 changes: 6 additions & 1 deletion kclvm/sema/src/resolver/global.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ impl<'ctx> Resolver<'ctx> {
pkgpath: self.ctx.pkgpath.clone(),
filename: self.ctx.filename.clone(),
doc: parsed_doc.summary.clone(),
examples: parsed_doc.examples,
is_instance: false,
is_mixin,
is_protocol,
Expand Down Expand Up @@ -814,6 +815,7 @@ impl<'ctx> Resolver<'ctx> {
pkgpath: self.ctx.pkgpath.clone(),
filename: self.ctx.filename.clone(),
doc: parsed_doc.summary.clone(),
examples: parsed_doc.examples,
is_instance: false,
is_mixin: schema_stmt.is_mixin,
is_protocol: schema_stmt.is_protocol,
Expand Down Expand Up @@ -918,11 +920,14 @@ impl<'ctx> Resolver<'ctx> {
DecoratorTarget::Schema,
&rule_stmt.name.node,
);

let parsed_doc = parse_doc_string(&rule_stmt.doc);
SchemaType {
name: rule_stmt.name.node.clone(),
pkgpath: self.ctx.pkgpath.clone(),
filename: self.ctx.filename.clone(),
doc: rule_stmt.doc.clone(),
doc: parsed_doc.summary.clone(),
examples: parsed_doc.examples,
is_instance: false,
is_mixin: false,
is_protocol: false,
Expand Down
3 changes: 1 addition & 2 deletions kclvm/sema/src/resolver/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ mod arg;
mod attr;
mod calculation;
mod config;
mod doc;
pub mod doc;
mod format;
pub mod global;
mod import;
Expand All @@ -29,7 +29,6 @@ use crate::resolver::ty_alias::process_program_type_alias;
use crate::{resolver::scope::Scope, ty::SchemaType};
use kclvm_ast::ast::Program;
use kclvm_error::*;

use crate::ty::TypeContext;

use self::scope::{builtin_scope, ProgramScope};
Expand Down
2 changes: 1 addition & 1 deletion kclvm/sema/src/resolver/test_data/doc.k
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ schema Server:
See also: kusion_models/core/v1/metadata.k.

Examples
----------------------
--------
myCustomApp = AppConfiguration {
name = "componentName"
}
Expand Down
4 changes: 4 additions & 0 deletions kclvm/sema/src/ty/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ use kclvm_error::Position;
pub use unify::*;
pub use walker::walk_type;

use super::resolver::doc::Example;

#[cfg(test)]
mod tests;

Expand Down Expand Up @@ -175,6 +177,8 @@ pub struct SchemaType {
pub filename: String,
/// The schema definition document string.
pub doc: String,
/// The code snippets of the schema usage examples
pub examples: HashMap<String, Example>,
/// Indicates whether the schema is a type of a instance or
/// a type (value). Besides, it is necessary to distinguish
/// between a type instance and a type value, such as the following code:
Expand Down

0 comments on commit 8cf50e6

Please sign in to comment.