From 3fc5f3ec9561017dd0e779499dff6720eda50eb3 Mon Sep 17 00:00:00 2001 From: peefy Date: Thu, 20 Jun 2024 14:04:46 +0800 Subject: [PATCH] feat: optimize if stmt lazy eval Signed-off-by: peefy --- kclvm/compiler/src/codegen/llvm/backtrack.rs | 19 +++ kclvm/compiler/src/codegen/llvm/context.rs | 13 ++ kclvm/compiler/src/codegen/llvm/module.rs | 136 +++++++++++------- kclvm/compiler/src/codegen/llvm/node.rs | 38 +++-- kclvm/compiler/src/codegen/llvm/schema.rs | 132 ++++++++++------- kclvm/evaluator/src/context.rs | 23 ++- kclvm/evaluator/src/lazy.rs | 35 +++-- kclvm/evaluator/src/node.rs | 15 ++ .../schema/irrelevant_order/if_stmt_7/main.k | 6 + .../irrelevant_order/if_stmt_7/stdout.golden | 1 + .../schema/irrelevant_order/if_stmt_8/main.k | 9 ++ .../irrelevant_order/if_stmt_8/stdout.golden | 2 + 12 files changed, 312 insertions(+), 117 deletions(-) create mode 100644 test/grammar/schema/irrelevant_order/if_stmt_7/main.k create mode 100644 test/grammar/schema/irrelevant_order/if_stmt_7/stdout.golden create mode 100644 test/grammar/schema/irrelevant_order/if_stmt_8/main.k create mode 100644 test/grammar/schema/irrelevant_order/if_stmt_8/stdout.golden diff --git a/kclvm/compiler/src/codegen/llvm/backtrack.rs b/kclvm/compiler/src/codegen/llvm/backtrack.rs index ed3107962..937ea29dc 100644 --- a/kclvm/compiler/src/codegen/llvm/backtrack.rs +++ b/kclvm/compiler/src/codegen/llvm/backtrack.rs @@ -1,6 +1,7 @@ // Copyright The KCL Authors. All rights reserved. use super::context::LLVMCodeGenContext; +use crate::codegen::llvm::context::BacktrackKind; use crate::codegen::traits::BuilderMethods; use inkwell::values::BasicValueEnum; @@ -22,4 +23,22 @@ impl<'ctx> LLVMCodeGenContext<'ctx> { } false } + + #[inline] + pub(crate) fn is_backtrack_only_if(&self) -> bool { + if let Some(backtrack_meta) = self.backtrack_meta.borrow_mut().as_ref() { + matches!(backtrack_meta.kind, BacktrackKind::If) + } else { + false + } + } + + #[inline] + pub(crate) fn is_backtrack_only_or_else(&self) -> bool { + if let Some(backtrack_meta) = self.backtrack_meta.borrow_mut().as_ref() { + matches!(backtrack_meta.kind, BacktrackKind::OrElse) + } else { + false + } + } } diff --git a/kclvm/compiler/src/codegen/llvm/context.rs b/kclvm/compiler/src/codegen/llvm/context.rs index f1a60bac4..1a5fdedd0 100644 --- a/kclvm/compiler/src/codegen/llvm/context.rs +++ b/kclvm/compiler/src/codegen/llvm/context.rs @@ -69,12 +69,25 @@ pub struct Scope<'ctx> { pub arguments: RefCell>, } +/// Backtrack kind. +/// - If it is a normal kind, traverse all statements in the setter. +/// - If it is an if type, only traverse the if statement in the if stmt, skipping the else stmt. +/// - If it is an orelse type, only traverse the else statement, and make conditional judgments based on the inverse of the if stmt's cond. +#[derive(Default, Debug, Clone, PartialEq)] +pub enum BacktrackKind { + #[default] + Normal, + If, + OrElse, +} + /// Schema or Global internal order independent computation backtracking meta information. pub struct BacktrackMeta { pub target: String, pub level: usize, pub count: usize, pub stop: bool, + pub kind: BacktrackKind, } /// The LLVM code generator diff --git a/kclvm/compiler/src/codegen/llvm/module.rs b/kclvm/compiler/src/codegen/llvm/module.rs index 6a8146ac0..424695e53 100644 --- a/kclvm/compiler/src/codegen/llvm/module.rs +++ b/kclvm/compiler/src/codegen/llvm/module.rs @@ -9,6 +9,7 @@ use kclvm_runtime::ApiFunc; use kclvm_sema::pkgpath_without_prefix; use super::context::{BacktrackMeta, LLVMCodeGenContext}; +use crate::codegen::llvm::context::BacktrackKind; use crate::codegen::traits::{BuilderMethods, ProgramCodeGen, ValueMethods}; use crate::codegen::{error as kcl_error, ENTRY_NAME}; use crate::value; @@ -64,7 +65,8 @@ impl<'ctx> LLVMCodeGenContext<'ctx> { self.br(global_setter_block); self.builder.position_at_end(global_setter_block); let mut place_holder_map: IndexMap>> = IndexMap::new(); - let mut body_map: IndexMap>> = IndexMap::new(); + let mut body_map: IndexMap, BacktrackKind)>> = + IndexMap::new(); let pkgpath = &self.current_pkgpath(); // Setter function name format: "$set..$" self.emit_global_setters( @@ -83,7 +85,7 @@ impl<'ctx> LLVMCodeGenContext<'ctx> { } let stmt_list = body_map.get(k).expect(kcl_error::INTERNAL_ERROR_MSG); let mut if_level = 0; - for (attr_func, stmt) in functions.iter().zip(stmt_list) { + for (attr_func, (stmt, kind)) in functions.iter().zip(stmt_list) { let function = *attr_func; let name = function .get_name() @@ -102,6 +104,7 @@ impl<'ctx> LLVMCodeGenContext<'ctx> { level: if_level, count: 0, stop: false, + kind: kind.clone(), }); } else { if_level = 0; @@ -207,48 +210,51 @@ impl<'ctx> LLVMCodeGenContext<'ctx> { pkgpath: &str, is_in_if: bool, place_holder_map: &mut IndexMap>>, - body_map: &mut IndexMap>>, + body_map: &mut IndexMap, BacktrackKind)>>, in_if_names: &mut Vec, ) { - let add_stmt = - |name: &str, - stmt: &'ctx ast::Node, - place_holder_map: &mut IndexMap>>, - body_map: &mut IndexMap>>| { - // The function form e.g., $set.__main__.a(&Context, &LazyScope, &ValueRef, &ValueRef) - let var_key = format!("{}.{name}", pkgpath_without_prefix!(pkgpath)); - let function = - self.add_setter_function(&format!("{}.{}", value::GLOBAL_SETTER, var_key)); - let lambda_fn_ptr = self.builder.build_bitcast( - function.as_global_value().as_pointer_value(), - self.context.i64_type().ptr_type(AddressSpace::default()), - "", - ); - if !place_holder_map.contains_key(name) { - place_holder_map.insert(name.to_string(), vec![]); - } - let name_vec = place_holder_map - .get_mut(name) - .expect(kcl_error::INTERNAL_ERROR_MSG); - name_vec.push(function); - self.build_void_call( - &ApiFunc::kclvm_scope_add_setter.name(), - &[ - self.current_runtime_ctx_ptr(), - self.current_scope_ptr(), - self.native_global_string(pkgpath, "").into(), - self.native_global_string(name, "").into(), - lambda_fn_ptr, - ], - ); - let key = format!("{}.{name}", pkgpath_without_prefix!(pkgpath)); - self.setter_keys.borrow_mut().insert(key); - if !body_map.contains_key(name) { - body_map.insert(name.to_string(), vec![]); - } - let body_vec = body_map.get_mut(name).expect(kcl_error::INTERNAL_ERROR_MSG); - body_vec.push(stmt); - }; + let add_stmt = |name: &str, + stmt: &'ctx ast::Node, + kind: BacktrackKind, + place_holder_map: &mut IndexMap>>, + body_map: &mut IndexMap< + String, + Vec<(&'ctx ast::Node, BacktrackKind)>, + >| { + // The function form e.g., $set.__main__.a(&Context, &LazyScope, &ValueRef, &ValueRef) + let var_key = format!("{}.{name}", pkgpath_without_prefix!(pkgpath)); + let function = + self.add_setter_function(&format!("{}.{}", value::GLOBAL_SETTER, var_key)); + let lambda_fn_ptr = self.builder.build_bitcast( + function.as_global_value().as_pointer_value(), + self.context.i64_type().ptr_type(AddressSpace::default()), + "", + ); + if !place_holder_map.contains_key(name) { + place_holder_map.insert(name.to_string(), vec![]); + } + let name_vec = place_holder_map + .get_mut(name) + .expect(kcl_error::INTERNAL_ERROR_MSG); + name_vec.push(function); + self.build_void_call( + &ApiFunc::kclvm_scope_add_setter.name(), + &[ + self.current_runtime_ctx_ptr(), + self.current_scope_ptr(), + self.native_global_string(pkgpath, "").into(), + self.native_global_string(name, "").into(), + lambda_fn_ptr, + ], + ); + let key = format!("{}.{name}", pkgpath_without_prefix!(pkgpath)); + self.setter_keys.borrow_mut().insert(key); + if !body_map.contains_key(name) { + body_map.insert(name.to_string(), vec![]); + } + let body_vec = body_map.get_mut(name).expect(kcl_error::INTERNAL_ERROR_MSG); + body_vec.push((stmt, kind)); + }; for stmt in body { match &stmt.node { ast::Stmt::Unification(unification_stmt) => { @@ -256,7 +262,13 @@ impl<'ctx> LLVMCodeGenContext<'ctx> { if is_in_if { in_if_names.push(name.to_string()); } else { - add_stmt(name, stmt, place_holder_map, body_map); + add_stmt( + name, + stmt, + BacktrackKind::Normal, + place_holder_map, + body_map, + ); } } ast::Stmt::Assign(assign_stmt) => { @@ -265,7 +277,13 @@ impl<'ctx> LLVMCodeGenContext<'ctx> { if is_in_if { in_if_names.push(name.to_string()); } else { - add_stmt(name, stmt, place_holder_map, body_map); + add_stmt( + name, + stmt, + BacktrackKind::Normal, + place_holder_map, + body_map, + ); } } } @@ -275,7 +293,13 @@ impl<'ctx> LLVMCodeGenContext<'ctx> { if is_in_if { in_if_names.push(name.to_string()); } else { - add_stmt(name, stmt, place_holder_map, body_map); + add_stmt( + name, + stmt, + BacktrackKind::Normal, + place_holder_map, + body_map, + ); } } ast::Stmt::If(if_stmt) => { @@ -294,10 +318,10 @@ impl<'ctx> LLVMCodeGenContext<'ctx> { } } else { for name in &names { - add_stmt(name, stmt, place_holder_map, body_map); + add_stmt(name, stmt, BacktrackKind::If, place_holder_map, body_map); } - names.clear(); } + names.clear(); self.emit_global_setters( &if_stmt.orelse, pkgpath, @@ -312,17 +336,29 @@ impl<'ctx> LLVMCodeGenContext<'ctx> { } } else { for name in &names { - add_stmt(name, stmt, place_holder_map, body_map); + add_stmt( + name, + stmt, + BacktrackKind::OrElse, + place_holder_map, + body_map, + ); } - names.clear(); } + names.clear(); } ast::Stmt::SchemaAttr(schema_attr) => { let name = schema_attr.name.node.as_str(); if is_in_if { in_if_names.push(name.to_string()); } else { - add_stmt(name, stmt, place_holder_map, body_map); + add_stmt( + name, + stmt, + BacktrackKind::Normal, + place_holder_map, + body_map, + ); } } _ => {} diff --git a/kclvm/compiler/src/codegen/llvm/node.rs b/kclvm/compiler/src/codegen/llvm/node.rs index a4af3bae9..77a544ca9 100644 --- a/kclvm/compiler/src/codegen/llvm/node.rs +++ b/kclvm/compiler/src/codegen/llvm/node.rs @@ -16,6 +16,7 @@ use kclvm_sema::ty::{ANY_TYPE_STR, STR_TYPE_STR}; use crate::check_backtrack_stop; use crate::codegen::error as kcl_error; +use crate::codegen::llvm::context::BacktrackKind; use crate::codegen::llvm::context::BacktrackMeta; use crate::codegen::llvm::utils; use crate::codegen::traits::*; @@ -262,21 +263,38 @@ impl<'ctx> TypedResultWalker<'ctx> for LLVMCodeGenContext<'ctx> { fn walk_if_stmt(&self, if_stmt: &'ctx ast::IfStmt) -> Self::Result { check_backtrack_stop!(self); - let cond = self - .walk_expr(&if_stmt.cond) - .expect(kcl_error::COMPILE_ERROR_MSG); + let cond = self.walk_expr(&if_stmt.cond)?; let then_block = self.append_block(""); let else_block = self.append_block(""); let end_block = self.append_block(""); let is_truth = self.value_is_truthy(cond); self.cond_br(is_truth, then_block, else_block); self.builder.position_at_end(then_block); - self.walk_stmts(&if_stmt.body) - .expect(kcl_error::COMPILE_ERROR_MSG); + // Is backtrack only orelse stmt? + if self.is_backtrack_only_or_else() { + self.ok_result()?; + self.br(end_block); + self.builder.position_at_end(else_block); + self.walk_stmts(&if_stmt.orelse)?; + self.br(end_block); + self.builder.position_at_end(end_block); + return Ok(self.none_value()); + } + // Is backtrack only if stmt? + if self.is_backtrack_only_if() { + self.walk_stmts(&if_stmt.body)?; + self.br(end_block); + self.builder.position_at_end(else_block); + self.ok_result()?; + self.br(end_block); + self.builder.position_at_end(end_block); + return Ok(self.none_value()); + } + // Normal full if stmt. + self.walk_stmts(&if_stmt.body)?; self.br(end_block); self.builder.position_at_end(else_block); - self.walk_stmts(&if_stmt.orelse) - .expect(kcl_error::COMPILE_ERROR_MSG); + self.walk_stmts(&if_stmt.orelse)?; self.br(end_block); self.builder.position_at_end(end_block); Ok(self.none_value()) @@ -432,7 +450,8 @@ impl<'ctx> TypedResultWalker<'ctx> for LLVMCodeGenContext<'ctx> { pkgpath_without_prefix!(runtime_type), )); let mut place_holder_map: HashMap>> = HashMap::new(); - let mut body_map: HashMap>> = HashMap::new(); + let mut body_map: HashMap>, BacktrackKind)> = + HashMap::new(); // Enter the function self.push_function(function); // Lambda function body @@ -885,7 +904,7 @@ impl<'ctx> TypedResultWalker<'ctx> for LLVMCodeGenContext<'ctx> { if k == kclvm_runtime::CAL_MAP_INDEX_SIGNATURE { continue; } - let stmt_list = body_map.get(k).expect(kcl_error::INTERNAL_ERROR_MSG); + let (stmt_list, kind) = body_map.get(k).expect(kcl_error::INTERNAL_ERROR_MSG); let mut if_level = 0; for (attr_func, stmt) in functions.iter().zip(stmt_list) { let function = *attr_func; @@ -944,6 +963,7 @@ impl<'ctx> TypedResultWalker<'ctx> for LLVMCodeGenContext<'ctx> { level: if_level, count: 0, stop: false, + kind: kind.clone(), }); } else { if_level = 0; diff --git a/kclvm/compiler/src/codegen/llvm/schema.rs b/kclvm/compiler/src/codegen/llvm/schema.rs index e7ed89095..3f2cb33d2 100644 --- a/kclvm/compiler/src/codegen/llvm/schema.rs +++ b/kclvm/compiler/src/codegen/llvm/schema.rs @@ -9,6 +9,7 @@ use std::collections::HashMap; use std::str; use super::context::LLVMCodeGenContext; +use crate::codegen::llvm::context::BacktrackKind; use crate::codegen::traits::{ BuilderMethods, DerivedTypeMethods, DerivedValueCalculationMethods, ProgramCodeGen, ValueMethods, @@ -26,53 +27,56 @@ impl<'ctx> LLVMCodeGenContext<'ctx> { runtime_type: &str, is_in_if: bool, place_holder_map: &mut HashMap>>, - body_map: &mut HashMap>>, + body_map: &mut HashMap>, BacktrackKind)>, in_if_names: &mut Vec, ) { let schema_value = self .get_variable(value::SCHEMA_SELF_NAME) .expect(kcl_error::INTERNAL_ERROR_MSG); let value = self.undefined_value(); - let add_stmt = - |name: &str, - stmt: &'ctx ast::Node, - place_holder_map: &mut HashMap>>, - body_map: &mut HashMap>>| { - let function = self.add_function(&format!( - "{}.{}.{}", - value::SCHEMA_ATTR_NAME, - pkgpath_without_prefix!(runtime_type), - name - )); - let lambda_fn_ptr = self.builder.build_bitcast( - function.as_global_value().as_pointer_value(), - self.context.i64_type().ptr_type(AddressSpace::default()), - "", - ); - if !place_holder_map.contains_key(name) { - place_holder_map.insert(name.to_string(), vec![]); - } - let name_vec = place_holder_map - .get_mut(name) - .expect(kcl_error::INTERNAL_ERROR_MSG); - name_vec.push(function); - self.default_collection_insert_int_pointer(cal_map, name, lambda_fn_ptr); - self.default_collection_insert_value( - cal_map, - &format!("{}_{}", name, kclvm_runtime::CAL_MAP_RUNTIME_TYPE), - self.string_value(runtime_type), - ); - self.default_collection_insert_value( - cal_map, - &format!("{}_{}", name, kclvm_runtime::CAL_MAP_META_LINE), - self.int_value(stmt.line as i64), - ); - if !body_map.contains_key(name) { - body_map.insert(name.to_string(), vec![]); - } - let body_vec = body_map.get_mut(name).expect(kcl_error::INTERNAL_ERROR_MSG); - body_vec.push(stmt); - }; + let add_stmt = |name: &str, + stmt: &'ctx ast::Node, + kind: BacktrackKind, + place_holder_map: &mut HashMap>>, + body_map: &mut HashMap< + String, + (Vec<&'ctx ast::Node>, BacktrackKind), + >| { + let function = self.add_function(&format!( + "{}.{}.{}", + value::SCHEMA_ATTR_NAME, + pkgpath_without_prefix!(runtime_type), + name + )); + let lambda_fn_ptr = self.builder.build_bitcast( + function.as_global_value().as_pointer_value(), + self.context.i64_type().ptr_type(AddressSpace::default()), + "", + ); + if !place_holder_map.contains_key(name) { + place_holder_map.insert(name.to_string(), vec![]); + } + let name_vec = place_holder_map + .get_mut(name) + .expect(kcl_error::INTERNAL_ERROR_MSG); + name_vec.push(function); + self.default_collection_insert_int_pointer(cal_map, name, lambda_fn_ptr); + self.default_collection_insert_value( + cal_map, + &format!("{}_{}", name, kclvm_runtime::CAL_MAP_RUNTIME_TYPE), + self.string_value(runtime_type), + ); + self.default_collection_insert_value( + cal_map, + &format!("{}_{}", name, kclvm_runtime::CAL_MAP_META_LINE), + self.int_value(stmt.line as i64), + ); + if !body_map.contains_key(name) { + body_map.insert(name.to_string(), (vec![], kind)); + } + let (body_vec, _) = body_map.get_mut(name).expect(kcl_error::INTERNAL_ERROR_MSG); + body_vec.push(stmt); + }; if let Some(index_signature) = index_signature { self.default_collection_insert_value( cal_map, @@ -89,7 +93,13 @@ impl<'ctx> LLVMCodeGenContext<'ctx> { if is_in_if { in_if_names.push(name.to_string()); } else { - add_stmt(name, stmt, place_holder_map, body_map); + add_stmt( + name, + stmt, + BacktrackKind::Normal, + place_holder_map, + body_map, + ); } } ast::Stmt::Assign(assign_stmt) => { @@ -99,7 +109,13 @@ impl<'ctx> LLVMCodeGenContext<'ctx> { if is_in_if { in_if_names.push(name.to_string()); } else { - add_stmt(name, stmt, place_holder_map, body_map); + add_stmt( + name, + stmt, + BacktrackKind::Normal, + place_holder_map, + body_map, + ); } } } @@ -110,7 +126,13 @@ impl<'ctx> LLVMCodeGenContext<'ctx> { if is_in_if { in_if_names.push(name.to_string()); } else { - add_stmt(name, stmt, place_holder_map, body_map); + add_stmt( + name, + stmt, + BacktrackKind::Normal, + place_holder_map, + body_map, + ); } } ast::Stmt::If(if_stmt) => { @@ -131,10 +153,10 @@ impl<'ctx> LLVMCodeGenContext<'ctx> { } } else { for name in &names { - add_stmt(name, stmt, place_holder_map, body_map); + add_stmt(name, stmt, BacktrackKind::If, place_holder_map, body_map); } - names.clear(); } + names.clear(); self.emit_left_identifiers( &if_stmt.orelse, &None, @@ -151,10 +173,16 @@ impl<'ctx> LLVMCodeGenContext<'ctx> { } } else { for name in &names { - add_stmt(name, stmt, place_holder_map, body_map); + add_stmt( + name, + stmt, + BacktrackKind::OrElse, + place_holder_map, + body_map, + ); } - names.clear(); } + names.clear(); } ast::Stmt::SchemaAttr(schema_attr) => { let name = schema_attr.name.node.as_str(); @@ -162,7 +190,13 @@ impl<'ctx> LLVMCodeGenContext<'ctx> { if is_in_if { in_if_names.push(name.to_string()); } else { - add_stmt(name, stmt, place_holder_map, body_map); + add_stmt( + name, + stmt, + BacktrackKind::Normal, + place_holder_map, + body_map, + ); } } _ => {} diff --git a/kclvm/evaluator/src/context.rs b/kclvm/evaluator/src/context.rs index b02e35238..6fef0d73c 100644 --- a/kclvm/evaluator/src/context.rs +++ b/kclvm/evaluator/src/context.rs @@ -7,7 +7,7 @@ use kclvm_runtime::{BacktraceFrame, MAIN_PKG_PATH}; use crate::{ error as kcl_error, func::{FunctionCaller, FunctionEvalContextRef}, - lazy::{BacktrackMeta, Setter}, + lazy::{BacktrackMeta, Setter, SetterKind}, proxy::{Frame, Proxy}, rule::RuleCaller, schema::SchemaCaller, @@ -247,19 +247,40 @@ impl<'ctx> Evaluator<'ctx> { } } + #[inline] pub(crate) fn push_backtrack_meta(&self, setter: &Setter) { let meta = &mut self.backtrack_meta.borrow_mut(); meta.push(BacktrackMeta { stopped: setter.stopped.clone(), is_break: false, + kind: setter.kind.clone(), }); } + #[inline] pub(crate) fn pop_backtrack_meta(&self) { let meta = &mut self.backtrack_meta.borrow_mut(); meta.pop(); } + #[inline] + pub(crate) fn is_backtrack_only_if(&self) -> bool { + let meta = &mut self.backtrack_meta.borrow_mut(); + match meta.last().map(|m| matches!(m.kind, SetterKind::If)) { + Some(r) => r, + None => false, + } + } + + #[inline] + pub(crate) fn is_backtrack_only_or_else(&self) -> bool { + let meta = &mut self.backtrack_meta.borrow_mut(); + match meta.last().map(|m| matches!(m.kind, SetterKind::OrElse)) { + Some(r) => r, + None => false, + } + } + pub(crate) fn push_scope_cover(&self, start: usize, stop: usize) { self.scope_covers.borrow_mut().push((start, stop)); } diff --git a/kclvm/evaluator/src/lazy.rs b/kclvm/evaluator/src/lazy.rs index 66c4910a2..4a48a653e 100644 --- a/kclvm/evaluator/src/lazy.rs +++ b/kclvm/evaluator/src/lazy.rs @@ -78,6 +78,18 @@ impl LazyEvalScope { } } +/// Setter kind. +/// - If it is a normal kind, traverse all statements in the setter. +/// - If it is an if type, only traverse the if statement in the if stmt, skipping the else stmt. +/// - If it is an orelse type, only traverse the else statement, and make conditional judgments based on the inverse of the if stmt's cond. +#[derive(PartialEq, Clone, Default, Debug)] +pub enum SetterKind { + #[default] + Normal, + If, + OrElse, +} + /// Setter function definition. #[derive(PartialEq, Clone, Default, Debug)] pub struct Setter { @@ -87,6 +99,11 @@ pub struct Setter { pub stmt: usize, /// If the statement is a if statement, stop the backtrack process at the stopped statement index. pub stopped: Option, + /// Setter kind. + /// - If it is a normal kind, traverse all statements in the setter. + /// - If it is an if type, only traverse the if statement in the if stmt, skipping the else stmt. + /// - If it is an orelse type, only traverse the else statement, and make conditional judgments based on the inverse of the if stmt's cond. + pub kind: SetterKind, } /// Merge setters and set the value with default undefined value. @@ -133,6 +150,7 @@ pub(crate) fn merge_setters( pub struct BacktrackMeta { pub stopped: Option, pub is_break: bool, + pub kind: SetterKind, } impl<'ctx> Evaluator<'ctx> { @@ -166,7 +184,8 @@ impl<'ctx> Evaluator<'ctx> { let add_stmt = |name: &str, i: usize, stopped: Option, - body_map: &mut IndexMap>| { + body_map: &mut IndexMap>, + kind: SetterKind| { if !body_map.contains_key(name) { body_map.insert(name.to_string(), vec![]); } @@ -175,6 +194,7 @@ impl<'ctx> Evaluator<'ctx> { index, stmt: i, stopped, + kind, }); }; for (i, stmt) in body.iter().enumerate() { @@ -184,7 +204,7 @@ impl<'ctx> Evaluator<'ctx> { if is_in_if { in_if_names.push((name.to_string(), stmt.id.clone())); } else { - add_stmt(name, i, None, body_map); + add_stmt(name, i, None, body_map, SetterKind::Normal); } } ast::Stmt::Assign(assign_stmt) => { @@ -193,7 +213,7 @@ impl<'ctx> Evaluator<'ctx> { if is_in_if { in_if_names.push((name.to_string(), stmt.id.clone())); } else { - add_stmt(name, i, None, body_map); + add_stmt(name, i, None, body_map, SetterKind::Normal); } } } @@ -203,7 +223,7 @@ impl<'ctx> Evaluator<'ctx> { if is_in_if { in_if_names.push((name.to_string(), stmt.id.clone())); } else { - add_stmt(name, i, None, body_map); + add_stmt(name, i, None, body_map, SetterKind::Normal); } } ast::Stmt::If(if_stmt) => { @@ -215,10 +235,9 @@ impl<'ctx> Evaluator<'ctx> { } } else { for (name, id) in &names { - add_stmt(name, i, Some(id.clone()), body_map); + add_stmt(name, i, Some(id.clone()), body_map, SetterKind::If); } } - names.clear(); self.emit_setters_with(&if_stmt.orelse, body_map, true, &mut names, index); if is_in_if { @@ -227,7 +246,7 @@ impl<'ctx> Evaluator<'ctx> { } } else { for (name, id) in &names { - add_stmt(name, i, Some(id.clone()), body_map); + add_stmt(name, i, Some(id.clone()), body_map, SetterKind::OrElse); } } names.clear(); @@ -237,7 +256,7 @@ impl<'ctx> Evaluator<'ctx> { if is_in_if { in_if_names.push((name.to_string(), stmt.id.clone())); } else { - add_stmt(name, i, None, body_map); + add_stmt(name, i, None, body_map, SetterKind::Normal); } } _ => {} diff --git a/kclvm/evaluator/src/node.rs b/kclvm/evaluator/src/node.rs index 01f8c2a7b..7e0a43f95 100644 --- a/kclvm/evaluator/src/node.rs +++ b/kclvm/evaluator/src/node.rs @@ -229,6 +229,21 @@ impl<'ctx> TypedResultWalker<'ctx> for Evaluator<'ctx> { fn walk_if_stmt(&self, if_stmt: &'ctx ast::IfStmt) -> Self::Result { let cond = self.walk_expr(&if_stmt.cond)?; let is_truth = self.value_is_truthy(&cond); + // Is backtrack only orelse stmt? + if self.is_backtrack_only_or_else() { + if !is_truth { + self.walk_stmts(&if_stmt.orelse)?; + } + return self.ok_result(); + } + // Is backtrack only if stmt? + if self.is_backtrack_only_if() { + if is_truth { + self.walk_stmts(&if_stmt.body)?; + } + return self.ok_result(); + } + // Normal full if stmt. if is_truth { self.walk_stmts(&if_stmt.body)?; } else { diff --git a/test/grammar/schema/irrelevant_order/if_stmt_7/main.k b/test/grammar/schema/irrelevant_order/if_stmt_7/main.k new file mode 100644 index 000000000..a4ca0aecd --- /dev/null +++ b/test/grammar/schema/irrelevant_order/if_stmt_7/main.k @@ -0,0 +1,6 @@ +_a = 1 +if True: + _a += 1 +elif False: + _a += 1 +a = _a diff --git a/test/grammar/schema/irrelevant_order/if_stmt_7/stdout.golden b/test/grammar/schema/irrelevant_order/if_stmt_7/stdout.golden new file mode 100644 index 000000000..9dfc208df --- /dev/null +++ b/test/grammar/schema/irrelevant_order/if_stmt_7/stdout.golden @@ -0,0 +1 @@ +a: 2 diff --git a/test/grammar/schema/irrelevant_order/if_stmt_8/main.k b/test/grammar/schema/irrelevant_order/if_stmt_8/main.k new file mode 100644 index 000000000..77a9ba1fe --- /dev/null +++ b/test/grammar/schema/irrelevant_order/if_stmt_8/main.k @@ -0,0 +1,9 @@ +schema Name: + _a = 1 + if True: + _a += 1 + elif False: + _a += 1 + a = _a + +name = Name{} diff --git a/test/grammar/schema/irrelevant_order/if_stmt_8/stdout.golden b/test/grammar/schema/irrelevant_order/if_stmt_8/stdout.golden new file mode 100644 index 000000000..e727a4e4f --- /dev/null +++ b/test/grammar/schema/irrelevant_order/if_stmt_8/stdout.golden @@ -0,0 +1,2 @@ +name: + a: 2