Skip to content

Commit

Permalink
feat: support config entry mutual reference.
Browse files Browse the repository at this point in the history
  • Loading branch information
Peefy committed Feb 3, 2023
1 parent 98a8a9a commit bba23f4
Show file tree
Hide file tree
Showing 32 changed files with 313 additions and 108 deletions.
34 changes: 33 additions & 1 deletion kclvm/compiler/src/codegen/llvm/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,12 @@ use kclvm_sema::builtin;
use kclvm_sema::plugin;

use crate::codegen::abi::Align;
use crate::codegen::CodeGenContext;
use crate::codegen::{error as kcl_error, EmitOptions};
use crate::codegen::{
traits::*, ENTRY_NAME, GLOBAL_VAL_ALIGNMENT, KCL_CONTEXT_VAR_NAME, MODULE_NAME,
PKG_INIT_FUNCTION_SUFFIX,
};
use crate::codegen::{CodeGenContext, GLOBAL_LEVEL};
use crate::pkgpath_without_prefix;
use crate::value;

Expand Down Expand Up @@ -1452,6 +1452,38 @@ impl<'ctx> LLVMCodeGenContext<'ctx> {
existed
}

/// Append a variable or update the existed local variable.
pub fn add_or_update_local_variable(&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();
match variables_mut.get(&name.to_string()) {
// If the local varibale is found, store the new value for the variable.
Some(ptr) if index > GLOBAL_LEVEL && !self.local_vars.borrow().contains(name) => {
self.builder.build_store(*ptr, value);
existed = true;
}
_ => {}
}
}
// If not found, alloca a new varibale.
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 varibale into the current scope.
if let Some(last) = scopes.last_mut() {
let mut variables = last.variables.borrow_mut();
variables.insert(name.to_string(), ptr);
}
}
}

/// Append a variable or update the existed variable
pub fn add_or_update_global_variable(&self, name: &str, value: BasicValueEnum<'ctx>) {
// Find argument name in the scope
Expand Down
168 changes: 66 additions & 102 deletions kclvm/compiler/src/codegen/llvm/node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use inkwell::basic_block::BasicBlock;
use inkwell::module::Linkage;
use inkwell::values::{BasicValueEnum, CallableValue, FunctionValue};
use inkwell::{AddressSpace, IntPredicate};
use kclvm_ast::ast::{self, CallExpr};
use kclvm_ast::ast::{self, CallExpr, ConfigEntry, NodeRef};
use kclvm_ast::walker::TypedResultWalker;
use kclvm_runtime::{ApiFunc, PKG_PATH_PREFIX};

Expand Down Expand Up @@ -1860,56 +1860,7 @@ impl<'ctx> TypedResultWalker<'ctx> for LLVMCodeGenContext<'ctx> {
let tpe = self.value_ptr_type();
self.cond_br(is_truth, then_block, else_block);
self.builder.position_at_end(then_block);
let then_value = self.dict_value();
for item in &config_if_entry_expr.items {
let key = &item.node.key;
let value = &item.node.value;
let op = &item.node.operation;
let value = self.walk_expr(value).expect(kcl_error::COMPILE_ERROR_MSG);
if let Some(key) = key {
let mut insert_index = -1;
let key = match &key.node {
ast::Expr::Identifier(identifier) => {
let name = &identifier.names[0];
self.string_value(name)
}
ast::Expr::StringLit(string_lit) => {
self.string_value(string_lit.value.as_str())
}
ast::Expr::Subscript(subscript) => match &subscript.value.node {
ast::Expr::Identifier(identifier) => {
let has_index = match &subscript.index {
Some(index) => match &index.node {
ast::Expr::NumberLit(v) => match &v.value {
ast::NumberLitValue::Int(v) => {
insert_index = *v as i32;
true
}
_ => false,
},
_ => false,
},
_ => false,
};
if has_index {
let name = &identifier.names[0];
self.string_value(name)
} else {
self.walk_expr(key).expect(kcl_error::COMPILE_ERROR_MSG)
}
}
_ => self.walk_expr(key).expect(kcl_error::COMPILE_ERROR_MSG),
},
_ => self.walk_expr(key).expect(kcl_error::COMPILE_ERROR_MSG),
};
self.dict_insert_with_key_value(then_value, key, value, op.value(), insert_index);
} else {
self.build_void_call(
&ApiFunc::kclvm_dict_insert_unpack.name(),
&[then_value, value],
);
}
}
let then_value = self.walk_config_entries(&config_if_entry_expr.items)?;
let then_block = self.append_block("");
self.br(then_block);
self.builder.position_at_end(then_block);
Expand Down Expand Up @@ -1988,56 +1939,7 @@ impl<'ctx> TypedResultWalker<'ctx> for LLVMCodeGenContext<'ctx> {

fn walk_config_expr(&self, config_expr: &'ctx ast::ConfigExpr) -> Self::Result {
check_backtrack_stop!(self);
let config_value = self.dict_value();
for item in &config_expr.items {
let value = &item.node.value;
let op = &item.node.operation;
let value = self.walk_expr(value).expect(kcl_error::COMPILE_ERROR_MSG);
if let Some(key) = &item.node.key {
let mut insert_index = -1;
let key = match &key.node {
ast::Expr::Identifier(identifier) => {
let name = &identifier.names[0];
self.string_value(name)
}
ast::Expr::StringLit(string_lit) => {
self.string_value(string_lit.value.as_str())
}
ast::Expr::Subscript(subscript) => match &subscript.value.node {
ast::Expr::Identifier(identifier) => {
let has_index = match &subscript.index {
Some(index) => match &index.node {
ast::Expr::NumberLit(v) => match &v.value {
ast::NumberLitValue::Int(v) => {
insert_index = *v as i32;
true
}
_ => false,
},
_ => false,
},
_ => false,
};
if has_index {
let name = &identifier.names[0];
self.string_value(name)
} else {
self.walk_expr(key).expect(kcl_error::COMPILE_ERROR_MSG)
}
}
_ => self.walk_expr(key).expect(kcl_error::COMPILE_ERROR_MSG),
},
_ => self.walk_expr(key).expect(kcl_error::COMPILE_ERROR_MSG),
};
self.dict_insert_with_key_value(config_value, key, value, op.value(), insert_index);
} else {
self.build_void_call(
&ApiFunc::kclvm_dict_insert_unpack.name(),
&[config_value, value],
);
}
}
Ok(config_value)
self.walk_config_entries(&config_expr.items)
}

fn walk_check_expr(&self, check_expr: &'ctx ast::CheckExpr) -> Self::Result {
Expand Down Expand Up @@ -2846,6 +2748,68 @@ impl<'ctx> LLVMCodeGenContext<'ctx> {
self.br(start_block);
self.builder.position_at_end(end_for_block);
self.build_void_call(&ApiFunc::kclvm_iterator_delete.name(), &[iter_value]);
self.local_vars.borrow_mut().clear();
{
let mut local_vars = self.local_vars.borrow_mut();
for v in targets {
let name = &v.node.names[0];
local_vars.remove(name);
}
}
}

pub(crate) fn walk_config_entries(
&self,
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 {
let mut insert_index = -1;
let optional_name = match &key.node {
ast::Expr::Identifier(identifier) => Some(identifier.names[0].clone()),
ast::Expr::StringLit(string_lit) => Some(string_lit.value.clone()),
ast::Expr::Subscript(subscript) => {
let mut name = None;
if let ast::Expr::Identifier(identifier) = &subscript.value.node {
if let Some(index_node) = &subscript.index {
if let ast::Expr::NumberLit(number) = &index_node.node {
if let ast::NumberLitValue::Int(v) = number.value {
insert_index = v;
name = Some(identifier.names[0].clone())
}
}
}
}
name
}
_ => None,
};
// Store a local variable for every entry key.
let key = match optional_name {
Some(name) => {
self.add_or_update_local_variable(&name, value);
self.string_value(&name)
}
None => self.walk_expr(key)?,
};
self.dict_insert_with_key_value(
config_value,
key,
value,
item.node.operation.value(),
insert_index as i32,
);
} else {
// If the key does not exist, execute the logic of unpacking expression `**expr` here.
self.build_void_call(
&ApiFunc::kclvm_dict_insert_unpack.name(),
&[config_value, value],
);
}
}
self.leave_scope();
Ok(config_value)
}
}
32 changes: 31 additions & 1 deletion kclvm/sema/src/resolver/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use std::rc::Rc;

use super::{
node::TypeRef,
scope::{ScopeObject, ScopeObjectKind},
scope::{ScopeKind, ScopeObject, ScopeObjectKind},
Resolver,
};
use crate::ty::SchemaType;
Expand Down Expand Up @@ -378,6 +378,11 @@ impl<'ctx> Resolver<'ctx> {
&mut self,
entries: &'ctx [ast::NodeRef<ast::ConfigEntry>],
) -> TypeRef {
self.enter_scope(
self.ctx.start_pos.clone(),
self.ctx.end_pos.clone(),
ScopeKind::Config,
);
let mut key_types: Vec<TypeRef> = vec![];
let mut val_types: Vec<TypeRef> = vec![];
for item in entries {
Expand All @@ -403,6 +408,17 @@ impl<'ctx> Resolver<'ctx> {
Rc::new(Type::str_lit(name))
};
self.check_attr_ty(&key_ty, key.get_pos());
self.insert_object(
name,
ScopeObject {
name: name.to_string(),
start: key.get_pos(),
end: key.get_end_pos(),
ty: val_ty.clone(),
kind: ScopeObjectKind::Attribute,
used: false,
},
);
key_ty
} else {
self.str_ty()
Expand All @@ -424,6 +440,19 @@ impl<'ctx> Resolver<'ctx> {
let key_ty = self.expr(key);
let val_ty = self.expr(value);
self.check_attr_ty(&key_ty, key.get_pos());
if let ast::Expr::StringLit(string_lit) = &key.node {
self.insert_object(
&string_lit.value,
ScopeObject {
name: string_lit.value.clone(),
start: key.get_pos(),
end: key.get_end_pos(),
ty: val_ty.clone(),
kind: ScopeObjectKind::Attribute,
used: false,
},
);
}
key_types.push(key_ty);
val_types.push(val_ty.clone());
val_ty
Expand Down Expand Up @@ -491,6 +520,7 @@ impl<'ctx> Resolver<'ctx> {
}
self.clear_config_expr_context(stack_depth, false);
}
self.leave_scope();
let key_ty = sup(&key_types);
let val_ty = sup(&val_types);
Type::dict_ref(key_ty, val_ty)
Expand Down
2 changes: 2 additions & 0 deletions kclvm/sema/src/resolver/scope.rs
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,8 @@ pub enum ScopeKind {
CondStmt,
/// Lambda expression.
Lambda,
/// Config expression
Config,
}

impl Scope {
Expand Down
4 changes: 4 additions & 0 deletions test/grammar/datatype/dict/mutual_ref_0/main.k
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
data = {
name = "release"
metadata.name = name
}
4 changes: 4 additions & 0 deletions test/grammar/datatype/dict/mutual_ref_0/stdout.golden
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
data:
name: release
metadata:
name: release
4 changes: 4 additions & 0 deletions test/grammar/datatype/dict/mutual_ref_1/main.k
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
data = {
"name" = "release"
metadata.name = name
}
4 changes: 4 additions & 0 deletions test/grammar/datatype/dict/mutual_ref_1/stdout.golden
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
data:
name: release
metadata:
name: release
6 changes: 6 additions & 0 deletions test/grammar/datatype/dict/mutual_ref_10/main.k
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
_temp = 1
data = {
_temp = 2
temp = _temp
}
temp = _temp
3 changes: 3 additions & 0 deletions test/grammar/datatype/dict/mutual_ref_10/stdout.golden
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
data:
temp: 2
temp: 1
8 changes: 8 additions & 0 deletions test/grammar/datatype/dict/mutual_ref_11/main.k
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
_temp = 1
data = {
_temp = 2
if True:
_temp = 3
temp = _temp
}
temp = _temp
3 changes: 3 additions & 0 deletions test/grammar/datatype/dict/mutual_ref_11/stdout.golden
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
data:
temp: 3
temp: 1
7 changes: 7 additions & 0 deletions test/grammar/datatype/dict/mutual_ref_12/main.k
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
c = [
container | {
volumeMounts = [
{name = mount.name} for mount in [{"container" = "main", name = container + "Container"}] if mount.container == container.name
]
} for container in [{"name" = "main"}]
]
4 changes: 4 additions & 0 deletions test/grammar/datatype/dict/mutual_ref_12/stdout.golden
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
c:
- name: main
volumeMounts:
- name: mainContainer
5 changes: 5 additions & 0 deletions test/grammar/datatype/dict/mutual_ref_2/main.k
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
data = {
name = "release"
metadata.name = name
spec.template.metadata.name = name
}
8 changes: 8 additions & 0 deletions test/grammar/datatype/dict/mutual_ref_2/stdout.golden
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
data:
name: release
metadata:
name: release
spec:
template:
metadata:
name: release
Loading

0 comments on commit bba23f4

Please sign in to comment.