Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: support config entry mutual reference. #395

Merged
merged 2 commits into from
Feb 7, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0.4.4
0.4.5
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
2 changes: 1 addition & 1 deletion kclvm/version/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// Copyright 2021 The KCL Authors. All rights reserved.

pub const VERSION: &str = "0.4.4";
pub const VERSION: &str = "0.4.5";
pub const CHECK_SUM: &str = "c5339e572207211e46477825e8aca903";

pub fn get_full_version() -> String {
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
}
Loading