From 2a36798d7202ab5b2cea45ff33911f9e6721b420 Mon Sep 17 00:00:00 2001 From: Peefy Date: Mon, 19 Aug 2024 17:51:36 +0800 Subject: [PATCH] feat: add literal type default value pass and preprocess (#1583) Signed-off-by: peefy --- kclvm/ast/src/ast.rs | 10 +-- kclvm/sema/src/pre_process/config.rs | 7 +- kclvm/sema/src/pre_process/identifier.rs | 1 + .../src/pre_process/lit_ty_default_value.rs | 89 +++++++++++++++++++ kclvm/sema/src/pre_process/mod.rs | 3 + .../test_data/lit_ty_default_val.k | 7 ++ kclvm/sema/src/pre_process/tests.rs | 76 ++++++++++++++++ kclvm/sema/src/resolver/node.rs | 8 +- .../default_value/default_value_3/main.k | 9 ++ .../default_value_3/stdout.golden | 7 ++ 10 files changed, 207 insertions(+), 10 deletions(-) create mode 100644 kclvm/sema/src/pre_process/lit_ty_default_value.rs create mode 100644 kclvm/sema/src/pre_process/test_data/lit_ty_default_val.k create mode 100644 test/grammar/schema/default_value/default_value_3/main.k create mode 100644 test/grammar/schema/default_value/default_value_3/stdout.golden diff --git a/kclvm/ast/src/ast.rs b/kclvm/ast/src/ast.rs index f1675a4e2..c8f0ead3d 100644 --- a/kclvm/ast/src/ast.rs +++ b/kclvm/ast/src/ast.rs @@ -1347,15 +1347,13 @@ pub struct StringLit { } /// Generate ast.StringLit from String -impl TryFrom for StringLit { - type Error = &'static str; - - fn try_from(value: String) -> Result { - Ok(Self { +impl From for StringLit { + fn from(value: String) -> Self { + Self { value: value.clone(), raw_value: format!("{:?}", value), is_long_string: false, - }) + } } } diff --git a/kclvm/sema/src/pre_process/config.rs b/kclvm/sema/src/pre_process/config.rs index eac973eb8..d35457778 100644 --- a/kclvm/sema/src/pre_process/config.rs +++ b/kclvm/sema/src/pre_process/config.rs @@ -107,7 +107,7 @@ impl<'ctx> MutSelfMutWalker<'ctx> for ConfigNestAttrTransformer { } } -#[derive(Debug)] +#[derive(Debug, Default)] struct ConfigMergeTransformer {} #[derive(Debug)] @@ -355,9 +355,10 @@ fn unify_config_entries( entries } -/// Merge program +/// Merge program for multiple file config. +#[inline] pub fn merge_program(program: &mut ast::Program) { - let mut merger = ConfigMergeTransformer {}; + let mut merger = ConfigMergeTransformer::default(); merger.merge(program); } diff --git a/kclvm/sema/src/pre_process/identifier.rs b/kclvm/sema/src/pre_process/identifier.rs index 5ff159dab..c8ab5dffe 100644 --- a/kclvm/sema/src/pre_process/identifier.rs +++ b/kclvm/sema/src/pre_process/identifier.rs @@ -242,6 +242,7 @@ pub fn fix_qualified_identifier<'ctx>( } /// Fix AST raw identifier prefix `$`, e.g., $filter -> filter +#[inline] pub fn fix_raw_identifier_prefix(module: &'_ mut ast::Module) { RawIdentifierTransformer::default().walk_module(module); } diff --git a/kclvm/sema/src/pre_process/lit_ty_default_value.rs b/kclvm/sema/src/pre_process/lit_ty_default_value.rs new file mode 100644 index 000000000..1d91aef52 --- /dev/null +++ b/kclvm/sema/src/pre_process/lit_ty_default_value.rs @@ -0,0 +1,89 @@ +use kclvm_ast::ast; +use kclvm_ast::walker::MutSelfMutWalker; + +#[derive(Default)] +struct LitTypeDefaultValueTransformer; + +impl<'ctx> MutSelfMutWalker<'ctx> for LitTypeDefaultValueTransformer { + fn walk_schema_attr(&mut self, schema_attr: &'ctx mut ast::SchemaAttr) { + if schema_attr.value.is_none() && !schema_attr.is_optional { + if let ast::Type::Literal(literal_ty) = &schema_attr.ty.node { + let filename = schema_attr.ty.filename.clone(); + let line = schema_attr.ty.end_line; + // Append ` = ` width for th column. + let column = schema_attr.ty.end_column + 3; + schema_attr.op = Some(ast::AugOp::Assign); + match literal_ty { + ast::LiteralType::Bool(val) => { + let column_offset = if *val { 4 } else { 5 }; + schema_attr.value = Some(Box::new(ast::Node::new( + ast::Expr::NameConstantLit(ast::NameConstantLit { + value: if *val { + ast::NameConstant::True + } else { + ast::NameConstant::False + }, + }), + filename, + line, + column, + line, + column + column_offset, + ))); + } + ast::LiteralType::Int(val) => { + let value = val.value.to_string(); + let mut column_offset = value.len() as u64; + if let Some(suffix) = &val.suffix { + column_offset += suffix.value().len() as u64 + } + schema_attr.value = Some(Box::new(ast::Node::new( + ast::Expr::NumberLit(ast::NumberLit { + binary_suffix: val.suffix.clone(), + value: ast::NumberLitValue::Int(val.value), + }), + filename, + line, + column, + line, + column + column_offset, + ))); + } + ast::LiteralType::Float(val) => { + let value = kclvm_runtime::float_to_string(*val); + let column_offset = value.len() as u64; + schema_attr.value = Some(Box::new(ast::Node::new( + ast::Expr::NumberLit(ast::NumberLit { + binary_suffix: None, + value: ast::NumberLitValue::Float(*val), + }), + filename, + line, + column, + line, + column + column_offset, + ))); + } + ast::LiteralType::Str(val) => { + let value: ast::StringLit = val.to_string().into(); + let column_offset = value.raw_value.len() as u64; + schema_attr.value = Some(Box::new(ast::Node::new( + ast::Expr::StringLit(value), + filename, + line, + column, + line, + column + column_offset, + ))); + } + } + } + } + } +} + +/// Fix literal type default value. e.g., `a: "value"` -> `a: "value" = "value"`. +#[inline] +pub fn fix_lit_ty_default_value(module: &'_ mut ast::Module) { + LitTypeDefaultValueTransformer::default().walk_module(module); +} diff --git a/kclvm/sema/src/pre_process/mod.rs b/kclvm/sema/src/pre_process/mod.rs index 49d6ac928..977e51adc 100644 --- a/kclvm/sema/src/pre_process/mod.rs +++ b/kclvm/sema/src/pre_process/mod.rs @@ -1,5 +1,6 @@ mod config; mod identifier; +mod lit_ty_default_value; mod multi_assign; use indexmap::IndexMap; @@ -10,6 +11,7 @@ mod tests; pub use config::{fix_config_expr_nest_attr, merge_program}; pub use identifier::{fix_qualified_identifier, fix_raw_identifier_prefix}; +pub use lit_ty_default_value::fix_lit_ty_default_value; pub use multi_assign::transform_multi_assign; use crate::resolver::Options; @@ -36,6 +38,7 @@ pub fn pre_process_program(program: &mut ast::Program, opts: &Options) { fix_raw_identifier_prefix(module); fix_qualified_identifier(module, &mut import_names); fix_config_expr_nest_attr(module); + fix_lit_ty_default_value(module); } } if opts.merge_program { diff --git a/kclvm/sema/src/pre_process/test_data/lit_ty_default_val.k b/kclvm/sema/src/pre_process/test_data/lit_ty_default_val.k new file mode 100644 index 000000000..c259dcec2 --- /dev/null +++ b/kclvm/sema/src/pre_process/test_data/lit_ty_default_val.k @@ -0,0 +1,7 @@ +schema LitTyConfig: + val0: "val" + val1: 1 + val2: 1Ki + val3: 2.0 + val4: True + val5: False diff --git a/kclvm/sema/src/pre_process/tests.rs b/kclvm/sema/src/pre_process/tests.rs index 5daabe220..6400436c8 100644 --- a/kclvm/sema/src/pre_process/tests.rs +++ b/kclvm/sema/src/pre_process/tests.rs @@ -22,6 +22,82 @@ fn test_fix_qualified_identifier() { } } +#[test] +fn test_fix_lit_ty_default_value() { + let mut module = + parse_file_force_errors("./src/pre_process/test_data/lit_ty_default_val.k", None).unwrap(); + fix_lit_ty_default_value(&mut module); + if let ast::Stmt::Schema(schema_stmt) = &module.body[0].node { + if let ast::Stmt::SchemaAttr(schema_attr) = &schema_stmt.body[0].node { + assert_eq!( + schema_attr.value.as_ref().unwrap().node, + ast::Expr::StringLit(ast::StringLit { + is_long_string: false, + raw_value: "\"val\"".to_string(), + value: "val".to_string(), + }) + ) + } else { + panic!("invalid schema attr value") + } + if let ast::Stmt::SchemaAttr(schema_attr) = &schema_stmt.body[1].node { + assert_eq!( + schema_attr.value.as_ref().unwrap().node, + ast::Expr::NumberLit(ast::NumberLit { + value: ast::NumberLitValue::Int(1), + binary_suffix: None, + }) + ) + } else { + panic!("invalid schema attr value") + } + if let ast::Stmt::SchemaAttr(schema_attr) = &schema_stmt.body[2].node { + assert_eq!( + schema_attr.value.as_ref().unwrap().node, + ast::Expr::NumberLit(ast::NumberLit { + value: ast::NumberLitValue::Int(1), + binary_suffix: Some(ast::NumberBinarySuffix::Ki), + }) + ) + } else { + panic!("invalid schema attr value") + } + if let ast::Stmt::SchemaAttr(schema_attr) = &schema_stmt.body[3].node { + assert_eq!( + schema_attr.value.as_ref().unwrap().node, + ast::Expr::NumberLit(ast::NumberLit { + value: ast::NumberLitValue::Float(2.0), + binary_suffix: None, + }) + ) + } else { + panic!("invalid schema attr value") + } + if let ast::Stmt::SchemaAttr(schema_attr) = &schema_stmt.body[4].node { + assert_eq!( + schema_attr.value.as_ref().unwrap().node, + ast::Expr::NameConstantLit(ast::NameConstantLit { + value: ast::NameConstant::True, + }) + ) + } else { + panic!("invalid schema attr value") + } + if let ast::Stmt::SchemaAttr(schema_attr) = &schema_stmt.body[5].node { + assert_eq!( + schema_attr.value.as_ref().unwrap().node, + ast::Expr::NameConstantLit(ast::NameConstantLit { + value: ast::NameConstant::False, + }) + ) + } else { + panic!("invalid schema attr value") + } + } else { + panic!("invalid schema statement") + } +} + #[test] fn test_fix_raw_identifier_prefix() { let mut module = diff --git a/kclvm/sema/src/resolver/node.rs b/kclvm/sema/src/resolver/node.rs index 0150daaf6..67e06702a 100644 --- a/kclvm/sema/src/resolver/node.rs +++ b/kclvm/sema/src/resolver/node.rs @@ -456,7 +456,13 @@ impl<'ctx> MutSelfTypedResultWalker<'ctx> for Resolver<'ctx> { None, ), }, - None => bug!("invalid ast schema attr op kind"), + // Default is Assign + None => self.must_assignable_to( + value_ty, + expected_ty, + schema_attr.name.get_span_pos(), + None, + ), } } self.any_ty() diff --git a/test/grammar/schema/default_value/default_value_3/main.k b/test/grammar/schema/default_value/default_value_3/main.k new file mode 100644 index 000000000..25e960154 --- /dev/null +++ b/test/grammar/schema/default_value/default_value_3/main.k @@ -0,0 +1,9 @@ +schema Config: + val0: "val" + val1: 1 + val2: 1Ki + val3: 2.0 + val4: True + val5: False + +c = Config {} diff --git a/test/grammar/schema/default_value/default_value_3/stdout.golden b/test/grammar/schema/default_value/default_value_3/stdout.golden new file mode 100644 index 000000000..d555630f2 --- /dev/null +++ b/test/grammar/schema/default_value/default_value_3/stdout.golden @@ -0,0 +1,7 @@ +c: + val0: val + val1: 1 + val2: 1024.0 + val3: 2.0 + val4: true + val5: false