Skip to content

Commit

Permalink
fix: local var set value in the config internal scope
Browse files Browse the repository at this point in the history
  • Loading branch information
Peefy committed Jun 27, 2024
1 parent 3a333b9 commit af7354e
Show file tree
Hide file tree
Showing 8 changed files with 102 additions and 62 deletions.
42 changes: 17 additions & 25 deletions kclvm/compiler/src/codegen/llvm/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1717,40 +1717,32 @@ impl<'ctx> LLVMCodeGenContext<'ctx> {
level
}

/// Append a variable or update the existed local variable.
pub fn add_or_update_local_variable(&self, name: &str, value: BasicValueEnum<'ctx>) {
/// Append a variable or update the existed local variable within the current scope.
pub fn add_or_update_local_variable_within_scope(
&self,
name: &str,
value: BasicValueEnum<'ctx>,
) {
let current_pkgpath = self.current_pkgpath();
let mut pkg_scopes = self.pkg_scopes.borrow_mut();
let msg = format!("pkgpath {} is not found", current_pkgpath);
let scopes = pkg_scopes.get_mut(&current_pkgpath).expect(&msg);
let mut existed = false;
// Query the variable in all scopes.
for i in 0..scopes.len() {
let index = scopes.len() - i - 1;
let variables_mut = scopes[index].variables.borrow_mut();
let index = scopes.len() - 1;
if let Some(scope) = scopes.last_mut() {
let mut variables_mut = scope.variables.borrow_mut();
match variables_mut.get(&name.to_string()) {
// If the local variable is found, store the new value for the variable.
// We cannot update rule/lambda/schema arguments because they are read-only.
Some(ptr)
if index > GLOBAL_LEVEL
&& !self.local_vars.borrow().contains(name)
&& !scopes[index].arguments.borrow().contains(name) =>
{
Some(ptr) if index > GLOBAL_LEVEL => {
self.builder.build_store(*ptr, value);
existed = true;
}
_ => {}
}
}
// If not found, alloc a new variable.
if !existed {
let ptr = self.builder.build_alloca(self.value_ptr_type(), name);
self.builder.build_store(ptr, value);
// Store the value for the variable and add the variable into the current scope.
if let Some(last) = scopes.last_mut() {
let mut variables = last.variables.borrow_mut();
variables.insert(name.to_string(), ptr);
}
_ => {
let ptr = self.builder.build_alloca(self.value_ptr_type(), name);
self.builder.build_store(ptr, value);
// Store the value for the variable and add the variable into the current scope.
variables_mut.insert(name.to_string(), ptr);
}
};
}
}

Expand Down
20 changes: 12 additions & 8 deletions kclvm/compiler/src/codegen/llvm/node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1972,9 +1972,7 @@ impl<'ctx> TypedResultWalker<'ctx> for LLVMCodeGenContext<'ctx> {
config_if_entry_expr: &'ctx ast::ConfigIfEntryExpr,
) -> Self::Result {
check_backtrack_stop!(self);
let cond = self
.walk_expr(&config_if_entry_expr.if_cond)
.expect(kcl_error::COMPILE_ERROR_MSG);
let cond = self.walk_expr(&config_if_entry_expr.if_cond)?;
let then_block = self.append_block("");
let else_block = self.append_block("");
let end_block = self.append_block("");
Expand All @@ -1992,7 +1990,12 @@ impl<'ctx> TypedResultWalker<'ctx> for LLVMCodeGenContext<'ctx> {
self.br(end_block);
self.builder.position_at_end(else_block);
let else_value = if let Some(orelse) = &config_if_entry_expr.orelse {
self.walk_expr(orelse).expect(kcl_error::COMPILE_ERROR_MSG)
// Config or config if entry expr.
if let ast::Expr::Config(config_expr) = &orelse.node {
self.walk_config_entries(&config_expr.items)?
} else {
self.walk_expr(orelse)?
}
} else {
self.none_value()
};
Expand Down Expand Up @@ -2076,7 +2079,10 @@ impl<'ctx> TypedResultWalker<'ctx> for LLVMCodeGenContext<'ctx> {

fn walk_config_expr(&self, config_expr: &'ctx ast::ConfigExpr) -> Self::Result {
check_backtrack_stop!(self);
self.walk_config_entries(&config_expr.items)
self.enter_scope();
let result = self.walk_config_entries(&config_expr.items);
self.leave_scope();
result
}

fn walk_check_expr(&self, check_expr: &'ctx ast::CheckExpr) -> Self::Result {
Expand Down Expand Up @@ -2830,7 +2836,6 @@ impl<'ctx> LLVMCodeGenContext<'ctx> {
items: &'ctx [NodeRef<ConfigEntry>],
) -> CompileResult<'ctx> {
let config_value = self.dict_value();
self.enter_scope();
for item in items {
let value = self.walk_expr(&item.node.value)?;
if let Some(key) = &item.node.key {
Expand Down Expand Up @@ -2869,7 +2874,7 @@ impl<'ctx> LLVMCodeGenContext<'ctx> {
if let Some(name) = &optional_name {
let value =
self.dict_get(config_value, self.native_global_string(name, "").into());
self.add_or_update_local_variable(name, value);
self.add_or_update_local_variable_within_scope(name, value);
}
} else {
// If the key does not exist, execute the logic of unpacking expression `**expr` here.
Expand All @@ -2879,7 +2884,6 @@ impl<'ctx> LLVMCodeGenContext<'ctx> {
);
}
}
self.leave_scope();
Ok(config_value)
}
}
16 changes: 11 additions & 5 deletions kclvm/evaluator/src/node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -836,7 +836,12 @@ impl<'ctx> TypedResultWalker<'ctx> for Evaluator<'ctx> {
Ok(if is_truth {
self.walk_config_entries(&config_if_entry_expr.items)?
} else if let Some(orelse) = &config_if_entry_expr.orelse {
self.walk_expr(orelse)?
// Config or config if entry expr.
if let ast::Expr::Config(config_expr) = &orelse.node {
self.walk_config_entries(&config_expr.items)?
} else {
self.walk_expr(orelse)?
}
} else {
self.none_value()
})
Expand Down Expand Up @@ -927,7 +932,10 @@ impl<'ctx> TypedResultWalker<'ctx> for Evaluator<'ctx> {

#[inline]
fn walk_config_expr(&self, config_expr: &'ctx ast::ConfigExpr) -> Self::Result {
self.walk_config_entries(&config_expr.items)
self.enter_scope();
let result = self.walk_config_entries(&config_expr.items);
self.leave_scope();
result
}

fn walk_check_expr(&self, check_expr: &'ctx ast::CheckExpr) -> Self::Result {
Expand Down Expand Up @@ -1509,7 +1517,6 @@ impl<'ctx> Evaluator<'ctx> {

pub(crate) fn walk_config_entries(&self, items: &'ctx [NodeRef<ConfigEntry>]) -> EvalResult {
let mut config_value = self.dict_value();
self.enter_scope();
for item in items {
let value = self.walk_expr(&item.node.value)?;
if let Some(key) = &item.node.key {
Expand Down Expand Up @@ -1547,14 +1554,13 @@ impl<'ctx> Evaluator<'ctx> {
);
if let Some(name) = &optional_name {
let value = self.dict_get_value(&config_value, name);
self.add_or_update_local_variable(name, value);
self.add_or_update_local_variable_within_scope(name, value);
}
} else {
// If the key does not exist, execute the logic of unpacking expression `**expr` here.
config_value.dict_insert_unpack(&mut self.runtime_ctx.borrow_mut(), &value)
}
}
self.leave_scope();
Ok(config_value)
}
}
31 changes: 7 additions & 24 deletions kclvm/evaluator/src/scope.rs
Original file line number Diff line number Diff line change
Expand Up @@ -301,34 +301,17 @@ impl<'ctx> Evaluator<'ctx> {
level
}

/// Append a variable or update the existed local variable.
pub fn add_or_update_local_variable(&self, name: &str, value: ValueRef) {
/// Append a variable or update the existed local variable within the current scope.
pub(crate) fn add_or_update_local_variable_within_scope(&self, name: &str, value: ValueRef) {
let current_pkgpath = self.current_pkgpath();
let is_local_var = self.is_local_var(name);
let pkg_scopes = &mut self.pkg_scopes.borrow_mut();
let msg = format!("pkgpath {} is not found", current_pkgpath);
let scopes = pkg_scopes.get_mut(&current_pkgpath).expect(&msg);
let mut existed = false;
// Query the variable in all scopes.
for i in 0..scopes.len() {
let index = scopes.len() - i - 1;
let is_argument = scopes[index].arguments.contains(name);
let variables_mut = &mut scopes[index].variables;
match variables_mut.get(&name.to_string()) {
// If the local variable is found, store the new value for the variable.
// We cannot update rule/lambda/schema arguments because they are read-only.
Some(_) if index > GLOBAL_LEVEL && !is_local_var && !is_argument => {
variables_mut.insert(name.to_string(), value.clone());
existed = true;
}
_ => {}
}
}
// If not found, alloc a new variable.
if !existed {
// Store the value for the variable and add the variable into the current scope.
if let Some(last) = scopes.last_mut() {
last.variables.insert(name.to_string(), value);
let index = scopes.len() - 1;
if let Some(scope) = scopes.last_mut() {
let variables_mut = &mut scope.variables;
if index > GLOBAL_LEVEL {
variables_mut.insert(name.to_string(), value.clone());
}
}
}
Expand Down
24 changes: 24 additions & 0 deletions test/grammar/datatype/dict/mutual_ref_15/main.k
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
render = lambda {
a = {
foo: "bar"
}
b = {
foo2: "bar2"
a: {
b: "c"
}
}
c = [a, b]
}

out = render()
a = {
foo: "bar"
}
b = {
foo2: "bar2"
a: {
b: "c"
}
}
c = [a, b]
16 changes: 16 additions & 0 deletions test/grammar/datatype/dict/mutual_ref_15/stdout.golden
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
out:
- foo: bar
- foo2: bar2
a:
b: c
a:
foo: bar
b:
foo2: bar2
a:
b: c
c:
- foo: bar
- foo2: bar2
a:
b: c
9 changes: 9 additions & 0 deletions test/grammar/datatype/dict/mutual_ref_16/main.k
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
level0 = {
name = "orange"
level1_a = {
name = "apple"
}
level1_b = {
name = "pine" + name
}
}
6 changes: 6 additions & 0 deletions test/grammar/datatype/dict/mutual_ref_16/stdout.golden
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
level0:
name: orange
level1_a:
name: apple
level1_b:
name: pineorange

0 comments on commit af7354e

Please sign in to comment.