Skip to content

Commit

Permalink
feat(WIP): fmt
Browse files Browse the repository at this point in the history
  • Loading branch information
load1n9 committed Sep 26, 2023
1 parent 73f895f commit 7c7715c
Show file tree
Hide file tree
Showing 8 changed files with 477 additions and 62 deletions.
285 changes: 224 additions & 61 deletions Cargo.lock

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
members = [
"ast",
"cli",
"fmt",
"common",
"compiler",
"lexer",
Expand Down
2 changes: 1 addition & 1 deletion compiler/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,5 @@ edition = "2021"
whistle_common = { path = "../common/" }
whistle_parser = { path = "../parser/" }
whistle_ast = { path = "../ast/" }
wasm-encoder = "0.32.0"
wasm-encoder = "0.33.1"
byteorder = "1.4.3"
24 changes: 24 additions & 0 deletions fmt/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
[package]
name = "whistle_fmt"
version = "0.1.1"
edition = "2021"

[lib]
crate-type = ["lib", "cdylib"]

[dependencies]
anyhow = "1.0.64"
dprint-core = { version = "0.63.2", features = ["formatting"] }
serde = { version = "1.0.144", features = ["derive"] }
serde_json = { version = "1.0" }
text_lines = "0.6.0"
whistle_common = { path = "../common" }
whistle_ast = { path = "../ast" }
whistle_parser = { path = "../parser" }
whistle_preprocessor = { path = "../preprocessor" }
whistle_compiler = { path = "../compiler" }

[dev-dependencies]
debug-here = "0.2"
dprint-development = "0.9.1"
serde_json = { version = "1.0" }
11 changes: 11 additions & 0 deletions fmt/src/config/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
use dprint_core::configuration::NewLineKind;
use serde::{Deserialize, Serialize};

#[derive(Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct Configuration {
pub indent_width: u8,
pub line_width: u32,
pub use_tabs: bool,
pub new_line_kind: NewLineKind,
}
45 changes: 45 additions & 0 deletions fmt/src/gen/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
use std::borrow::BorrowMut;

use dprint_core::formatting::PrintItems;
use whistle_ast::{IdentType, IdentTyped, ProgramStmt, Stmt};

use crate::{config::Configuration, ParsedSource};

pub fn generate(parsed_source: &ParsedSource, _config: &Configuration) -> PrintItems {
let mut items = PrintItems::new();
let ast = &parsed_source.grammar;
for item in ast {
match item {
ProgramStmt::FunctionDecl {
export,
inline,
ident,
params,
ret_type,
stmt,
..
} => gen_fn(
items.borrow_mut(),
export,
inline,
ident,
params,
ret_type,
stmt,
),
_ => panic!("Unimplemented"),
};
}
items
}

pub fn gen_fn(
_items: &mut PrintItems,
_export: &bool,
_inline: &bool,
_ident: &str,
_params: &Vec<IdentTyped>,
_ret_type: &IdentType,
_stmts: &Vec<Stmt>,
) {
}
121 changes: 121 additions & 0 deletions fmt/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
#![feature(array_chunks)]

Check failure on line 1 in fmt/src/lib.rs

View workflow job for this annotation

GitHub Actions / check

`#![feature]` may not be used on the stable release channel

Check failure on line 1 in fmt/src/lib.rs

View workflow job for this annotation

GitHub Actions / test

`#![feature]` may not be used on the stable release channel
mod config;
mod gen;
mod utils;
use anyhow::Result;
use config::Configuration;
use dprint_core::configuration::resolve_new_line_kind;
use dprint_core::formatting::*;
use gen::generate;
use std::path::Path;
use whistle_ast::Grammar;
use whistle_parser::Parser;

pub struct ParsedSource {
pub parser: Parser,
pub grammar: Grammar,
pub text: String,
}

pub fn format_text(
_file_path: &Path,
file_text: &str,
config: &Configuration,
) -> Result<Option<String>> {
if utils::file_text_has_ignore_comment(file_text, "// whistle-ignore-file") {
Ok(None)
} else {
let parsed_source = utils::parse(file_text, false);
let parsed_source = ParsedSource {
parser: parsed_source.0,
grammar: parsed_source.1,
text: file_text.to_string(),
};
inner_format(&parsed_source, config)
}
}

/// Formats an already parsed source. This is useful as a performance optimization.
pub fn format_parsed_source(
source: ParsedSource,
config: &Configuration,
) -> Result<Option<String>> {
if utils::file_text_has_ignore_comment(&source.text, "// whistle-ignore-file") {
Ok(None)
} else {
// ensure_no_specific_syntax_errors(source)?;
inner_format(&source, config)
}
}

fn inner_format(parsed_source: &ParsedSource, config: &Configuration) -> Result<Option<String>> {
let result = dprint_core::formatting::format(
|| {
#[allow(clippy::let_and_return)]
let print_items = generate(parsed_source, config);
println!("{}", print_items.get_as_text());
print_items
},
config_to_print_options(parsed_source.text.as_str(), config),
);
if result == parsed_source.text.as_str() {
Ok(None)
} else {
Ok(Some(result))
}
}

fn config_to_print_options(file_text: &str, config: &Configuration) -> PrintOptions {
PrintOptions {
indent_width: config.indent_width,
max_width: config.line_width,
use_tabs: config.use_tabs,
new_line_text: resolve_new_line_kind(file_text, config.new_line_kind),
}
}

#[cfg(test)]
mod tests {
use super::*;
use std::path::PathBuf;

#[test]
fn test_format_text() {
let file_path = PathBuf::from("test.whistle");
let file_text = r#"
// whistle-ignore-file
export fn hi(): i32 {
return 5
}
"#;
let config = Configuration {
indent_width: 2,
line_width: 80,
use_tabs: false,
new_line_kind: dprint_core::configuration::NewLineKind::LineFeed,
};
let result = format_text(&file_path, file_text, &config).unwrap();
assert_eq!(result, None);
}

#[test]
fn test_format_text2() {
let file_path = PathBuf::from("test.whistle");
let file_text = r#"
export fn hi(): i32 {
return 5
}
"#;
let config = Configuration {
indent_width: 2,
line_width: 80,
use_tabs: false,
new_line_kind: dprint_core::configuration::NewLineKind::LineFeed,
};
let result = format_text(&file_path, file_text, &config).unwrap();
assert_eq!(
result,
Some("export fn hi(): i32 {\n return 5\n}\n".to_string())
);
}
}
50 changes: 50 additions & 0 deletions fmt/src/utils/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@


use whistle_ast::Grammar;
use whistle_common::{DiagnosticHandler, TokenItem};
use whistle_parser::*;
use whistle_preprocessor::Preprocessor;

pub fn file_text_has_ignore_comment(file_text: &str, ignore_file_comment_text: &str) -> bool {
let mut has_ignore_comment = false;
for line in file_text.lines() {
if line.trim().starts_with(ignore_file_comment_text) {
has_ignore_comment = true;
}
}
has_ignore_comment
}

pub fn preprocess(text: &str, print: bool) -> (Preprocessor, Vec<TokenItem>) {
let handler = DiagnosticHandler::new();
let mut processor = Preprocessor::new(handler);
processor.process(text);
handle_errors(&mut processor.handler);
let tokens = processor.finalize();

if print {
println!("{:#?}", tokens);
}

(processor, tokens)
}

pub fn parse(text: &str, print: bool) -> (Parser, Grammar) {
let (processor, tokens) = preprocess(text, false);
let mut parser = Parser::new(processor, tokens);
let grammar = parse_all(&mut parser);
handle_errors(&mut parser.handler);

if print {
println!("{:#?}", grammar);
}

(parser, grammar)
}

pub fn handle_errors(handler: &mut DiagnosticHandler) {
// TODO: format errors
if handler.errors.len() > 0 {
println!("{:#?}", handler.errors);
};
}

0 comments on commit 7c7715c

Please sign in to comment.