Skip to content

Commit

Permalink
feat: impl format tool.
Browse files Browse the repository at this point in the history
  • Loading branch information
Peefy committed May 26, 2022
1 parent 457f7a5 commit 96925e2
Show file tree
Hide file tree
Showing 47 changed files with 734 additions and 18 deletions.
8 changes: 8 additions & 0 deletions kclvm/Cargo.lock

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

28 changes: 28 additions & 0 deletions kclvm/tools/Cargo.lock

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

2 changes: 2 additions & 0 deletions kclvm/tools/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ edition = "2021"
[dependencies]
indexmap = "1.0"
fancy-regex = "0.7.1"
walkdir = "2"
anyhow = "1.0"

kclvm-ast = {path = "../ast", version = "0.1.0"}
kclvm-error = {path = "../error", version = "0.1.0"}
Expand Down
88 changes: 88 additions & 0 deletions kclvm/tools/src/format/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
use anyhow::{anyhow, Result};
use std::path::Path;
use walkdir::WalkDir;

use crate::printer::print_ast_module;
use kclvm_parser::parse_file;

#[cfg(test)]
mod tests;

const KCL_FILE_PATTERN: &str = ".k";

/// Format options
#[derive(Debug, Default)]
pub struct FormatOptions {
pub is_stdout: bool,
pub recursively: bool,
}

/// Formats kcl file or directory path contains kcl files and
/// returns the changed file paths.
pub fn format<P: AsRef<Path>>(path: P, opts: &FormatOptions) -> Result<Vec<String>> {
let mut changed_paths: Vec<String> = vec![];
let path_ref = path.as_ref();
if path_ref.is_dir() {
for file in &get_kcl_files(path, opts.recursively)? {
if format_file(file, opts)? {
changed_paths.push(file.clone())
}
}
} else if path_ref.is_file() {
let file = path_ref.to_str().unwrap().to_string();
if format_file(&file, opts)? {
changed_paths.push(file)
}
}
if !opts.is_stdout {
let n = changed_paths.len();
println!(
"KCL format done and {} {} formatted:",
n,
if n <= 1 { "file was" } else { "files were" }
);
for p in &changed_paths {
println!("{}", p);
}
}
Ok(changed_paths)
}

/// Format a code source and return the formatted source and
/// whether the source is changed.
pub fn format_source(src: &str) -> Result<(String, bool)> {
let module = match parse_file("", Some(src.to_string())) {
Ok(module) => module,
Err(err) => return Err(anyhow!("{}", err)),
};
let formatted_src = print_ast_module(&module);
let is_formatted = src != formatted_src;
Ok((formatted_src, is_formatted))
}

/// Format a file and return
fn format_file(file: &str, opts: &FormatOptions) -> Result<bool> {
let src = std::fs::read_to_string(file)?;
let (source, is_formatted) = format_source(&src)?;
if opts.is_stdout {
println!("{}", source);
} else {
std::fs::write(file, &source)?
}
Ok(is_formatted)
}

/// Get kcl files from path.
fn get_kcl_files<P: AsRef<Path>>(path: P, recursively: bool) -> Result<Vec<String>> {
let mut files = vec![];
for entry in WalkDir::new(path).into_iter().filter_map(|e| e.ok()) {
let path = entry.path();
if path.is_file() {
let file = path.to_str().unwrap();
if file.ends_with(KCL_FILE_PATTERN) && (recursively || entry.depth() == 1) {
files.push(file.to_string())
}
}
}
Ok(files)
}
4 changes: 4 additions & 0 deletions kclvm/tools/src/format/test_data/format_data/assert.golden
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
assert True if True, "message"
# Comment
assert False if data, "message"
assert 1
3 changes: 3 additions & 0 deletions kclvm/tools/src/format/test_data/format_data/assert.input
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
assert True if True, "message"
assert False if data , "message" # Comment
assert 1
4 changes: 4 additions & 0 deletions kclvm/tools/src/format/test_data/format_data/blankline.golden
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
a = 1
b = 2
c = 3
d = 4
12 changes: 12 additions & 0 deletions kclvm/tools/src/format/test_data/format_data/blankline.input
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@

a=1


b= 2


c =3



d = 4
9 changes: 9 additions & 0 deletions kclvm/tools/src/format/test_data/format_data/breakline.golden
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import math
schema Base:
name: str

schema Person(Base):
age: int

person = Person {}

6 changes: 6 additions & 0 deletions kclvm/tools/src/format/test_data/format_data/breakline.input
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import math
schema Base:
name: str
schema Person(Base):
age: int
person = Person{}
13 changes: 13 additions & 0 deletions kclvm/tools/src/format/test_data/format_data/check.golden
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
schema Person:
firstName: str = "John"
lastName: str
times: int

check:
len(lastName) > 0 if times > 5

JohnDoe = Person {
"lastName": "Doe"
"times": 10
}

12 changes: 12 additions & 0 deletions kclvm/tools/src/format/test_data/format_data/check.input
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@

schema Person:
firstName: str = "John"
lastName: str
times: int
check:
len(lastName) > 0 if times > 5

JohnDoe = Person {
"lastName": "Doe"
"times":10
}
80 changes: 80 additions & 0 deletions kclvm/tools/src/format/test_data/format_data/codelayout.golden
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import math as alias_math
schema Person(Base):
# inline comment
name: str
age: int

check:
age > 0 if age, "age must > 0"

person = Person {
name: "Alice"
age: 18
}

if True:
a = 1
elif True:
b = 2
else:
c = 3
d = 1 + 2
e = (1 + 2)
f = [1, 2, 3]
g = {"key": "value"}
# block comment
print(1)
dct = {"key": "value"}
lst = [1, 2, 3]
h = dct['key']
i = lst[1]
x = 1
y = 2
long_variable = 3
i = i + 1
submitted += 1
x = x * 2 - 1
hypot2 = x * x + y * y
_c = (a + b) * (a - b)
_b = 2
_c = 3
_d = 4
_value = (1 + 2 * 3)
_value = (1 + 2 * 3)
_value = 1 + -2 * ~3
_list = [1, 2, 3]
_list = [*_list, [4, 5, 6]]
_list = [*_list, [4, 5, 6]]
_dict = {**{"k": "v"}, **{"k": "v"}}
a = [1, 2, 3]
b = [
1
2
3
4
5
6
]
_dict = {
"k1": "v1"
"k2": "v2"
"k3": "v3"
"k4": "v4"
"k5": "v5"
}
foo = 1
if foo is not None:
_a = 1
_dict |= {}
hello = "world{}".format(1)[2:4:].lower()
range_int = [i for i in range(10) if i > 1]

op = 1 + 2 - -3 + (3 - 1) // 3
op += 1
op -= 12 + 23
print(" ", end='')
log = math.log(12)
aa = 1
assert aa == 1 if aa, "message"
aaaa = (1 + 2 / 2) if _a == 2 + +134.3 else ("a" * 3)
bbbb = "{}".format(a)
Loading

0 comments on commit 96925e2

Please sign in to comment.