Skip to content

Commit

Permalink
feat: top level variable back reference
Browse files Browse the repository at this point in the history
Signed-off-by: peefy <xpf6677@163.com>
  • Loading branch information
Peefy committed May 7, 2024
1 parent e9b70da commit 5069c1e
Show file tree
Hide file tree
Showing 27 changed files with 153 additions and 45 deletions.
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0.8.7
0.9.0
9 changes: 5 additions & 4 deletions kclvm/compiler/src/codegen/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@
use std::error;
use std::fmt::{self, Debug};

pub const VALUE_TYPE_NOT_FOUND_MSG: &str = "Type is not found";
pub const CONTEXT_VAR_NOT_FOUND_MSG: &str = "Context variable is not found";
pub const FUNCTION_RETURN_VALUE_NOT_FOUND_MSG: &str = "Function return value is not found";
pub const COMPILE_ERROR_MSG: &str = "Compile error";
pub const VALUE_TYPE_NOT_FOUND_MSG: &str = "Internal error, value type is not found";
pub const CONTEXT_VAR_NOT_FOUND_MSG: &str = "Internal error, context variable is not found";
pub const INTERNAL_ERROR_MSG: &str = "Internal error, please report a bug to us";
pub const FUNCTION_RETURN_VALUE_NOT_FOUND_MSG: &str =
"Internal error, function return value is not found";
pub const COMPILE_ERROR_MSG: &str = "Compile error";
pub const CODE_GEN_ERROR_MSG: &str = "Code gen error";
pub const INVALID_OPERATOR_MSG: &str = "Invalid operator";
pub const INVALID_JOINED_STR_MSG: &str = "Invalid AST JoinedString value";
Expand Down
66 changes: 63 additions & 3 deletions kclvm/compiler/src/codegen/llvm/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1311,8 +1311,10 @@ impl<'ctx> LLVMCodeGenContext<'ctx> {
let tpe = self.value_ptr_type().into_pointer_type();
let void_type = self.context.void_type();
let context_ptr_type = self.context_ptr_type();
let fn_type = tpe.fn_type(&[context_ptr_type.into()], false);
let void_fn_type = void_type.fn_type(&[context_ptr_type.into()], false);
let scope_ptr_type = self.scope_ptr_type();
let fn_type = tpe.fn_type(&[context_ptr_type.into(), scope_ptr_type.into()], false);
let void_fn_type =
void_type.fn_type(&[context_ptr_type.into(), scope_ptr_type.into()], false);
let has_main_pkg = self.program.pkgs.contains_key(MAIN_PKG_PATH);
let function = if self.no_link {
let mut modules = self.modules.borrow_mut();
Expand Down Expand Up @@ -1756,6 +1758,18 @@ impl<'ctx> LLVMCodeGenContext<'ctx> {
let variables = last.variables.borrow();
if let Some(var) = variables.get(&name.to_string()) {
self.builder.build_store(*var, value);
if save_scope {
self.build_void_call(
&ApiFunc::kclvm_scope_set.name(),
&[
self.current_runtime_ctx_ptr(),
self.current_scope_ptr(),
self.native_global_string(&current_pkgpath, "").into(),
self.native_global_string(name, "").into(),
value,
],
);
}
existed = true;
}
}
Expand All @@ -1766,6 +1780,18 @@ impl<'ctx> LLVMCodeGenContext<'ctx> {
let var_name = format!("${}.${}", pkgpath_without_prefix!(pkgpath), name);
let pointer = self.new_global_kcl_value_ptr(&var_name);
self.builder.build_store(pointer, value);
if save_scope {
self.build_void_call(
&ApiFunc::kclvm_scope_set.name(),
&[
self.current_runtime_ctx_ptr(),
self.current_scope_ptr(),
self.native_global_string(&current_pkgpath, "").into(),
self.native_global_string(name, "").into(),
value,
],
);
}
if !variables.contains_key(name) {
variables.insert(name.to_string(), pointer);
}
Expand Down Expand Up @@ -1993,7 +2019,41 @@ impl<'ctx> LLVMCodeGenContext<'ctx> {
}
}
} else {
self.builder.build_load(*var, name)
// Not a local schema attribute or a global type.
let key = format!("{}.{name}", pkgpath_without_prefix!(pkgpath));
let is_in_lambda = self.is_in_lambda();
if !is_in_schema
&& !is_in_lambda
&& index <= GLOBAL_LEVEL
&& !self.local_vars.borrow().contains(name)
&& self.setter_keys.borrow().contains(&key)
{
let target = self
.target_vars
.borrow_mut()
.last()
.expect(kcl_error::INTERNAL_ERROR_MSG)
.clone();
self.build_call(
&ApiFunc::kclvm_scope_get.name(),
&[
// Runtime context ptr
self.current_runtime_ctx_ptr(),
// Scope ptr
self.current_scope_ptr(),
// Package path
self.native_global_string(&pkgpath, "").into(),
// Attribute name
self.native_global_string(name, "").into(),
// Target
self.native_global_string(&target, "").into(),
// Default
self.builder.build_load(*var, name),
],
)
} else {
self.builder.build_load(*var, name)
}
};
result = Ok(value);
break;
Expand Down
4 changes: 2 additions & 2 deletions kclvm/compiler/src/codegen/llvm/module.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ impl<'ctx> LLVMCodeGenContext<'ctx> {
};
}
// Pre define global variables with setter functions.
// self.predefine_global_setters(module);
self.predefine_global_setters(module);
}

pub fn predefine_global_types(&self, name: &str) {
Expand All @@ -59,7 +59,7 @@ impl<'ctx> LLVMCodeGenContext<'ctx> {

/// Predefine all global variables.
pub fn predefine_global_setters(&self, module: &'ctx ast::Module) {
// New a function block to the global setter constrcution process.
// New a function block to the global setter construction process.
let global_setter_block = self.append_block("");
self.br(global_setter_block);
self.builder.position_at_end(global_setter_block);
Expand Down
14 changes: 11 additions & 3 deletions kclvm/compiler/src/codegen/llvm/node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -317,7 +317,10 @@ impl<'ctx> TypedResultWalker<'ctx> for LLVMCodeGenContext<'ctx> {
PKG_INIT_FUNCTION_SUFFIX
);
let tpe = self.context.void_type();
let fn_type = tpe.fn_type(&[self.context_ptr_type().into()], false);
let fn_type = tpe.fn_type(
&[self.context_ptr_type().into(), self.scope_ptr_type().into()],
false,
);
let function = module.add_function(
// Function name
&module_name,
Expand Down Expand Up @@ -367,10 +370,14 @@ impl<'ctx> TypedResultWalker<'ctx> for LLVMCodeGenContext<'ctx> {
);
}
let tpe = self.context.void_type();
let fn_type = tpe.fn_type(&[self.context_ptr_type().into()], false);
let fn_type = tpe.fn_type(
&[self.context_ptr_type().into(), self.scope_ptr_type().into()],
false,
);
module.add_function(&name, fn_type, Some(Linkage::External))
};
let ctx = self.current_runtime_ctx_ptr();
let scope = self.current_scope_ptr();
let pkgpath_value = self.native_global_string_value(&name);
let is_imported = self
.build_call(
Expand All @@ -389,7 +396,8 @@ impl<'ctx> TypedResultWalker<'ctx> for LLVMCodeGenContext<'ctx> {
self.builder
.build_conditional_branch(is_not_imported, then_block, else_block);
self.builder.position_at_end(then_block);
self.builder.build_call(function, &[ctx.into()], "");
self.builder
.build_call(function, &[ctx.into(), scope.into()], "");
self.br(else_block);
self.builder.position_at_end(else_block);
}
Expand Down
15 changes: 10 additions & 5 deletions kclvm/runtime/src/_kcl_run.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ pub unsafe extern "C" fn _kcl_run(
) -> kclvm_size_t {
// Init runtime context with options
let ctx = Box::new(new_ctx_with_opts(opts, &c2str_vec(path_selector))).into_raw();
let scope = kclvm_scope_new();
let option_keys = std::slice::from_raw_parts(option_keys, option_len as usize);
let option_values = std::slice::from_raw_parts(option_values, option_len as usize);
for i in 0..(option_len as usize) {
Expand Down Expand Up @@ -130,9 +131,7 @@ pub unsafe extern "C" fn _kcl_run(
}
})
}));
// let scope = Box::into_raw(Box::new(LazyEvalScope::default()));
// let result = std::panic::catch_unwind(|| _kcl_run_in_closure(ctx, scope, kclvm_main_ptr));
let result = std::panic::catch_unwind(|| _kcl_run_in_closure(ctx, kclvm_main_ptr));
let result = std::panic::catch_unwind(|| _kcl_run_in_closure(ctx, scope, kclvm_main_ptr));
std::panic::set_hook(prev_hook);
KCL_RUNTIME_PANIC_RECORD.with(|record| {
let record = record.borrow();
Expand Down Expand Up @@ -162,20 +161,26 @@ pub unsafe extern "C" fn _kcl_run(
copy_str_to(&json_panic_info, err_buffer, err_buffer_len);
// Delete the context
kclvm_context_delete(ctx);
// Delete the scope
kclvm_scope_delete(scope);
result.is_err() as kclvm_size_t
}

unsafe fn _kcl_run_in_closure(
ctx: *mut Context,
scope: *mut LazyEvalScope,
kclvm_main_ptr: u64, // main.k => kclvm_main
) {
let kclvm_main = (&kclvm_main_ptr as *const u64) as *const ()
as *const extern "C" fn(ctx: *mut kclvm_context_t) -> *mut kclvm_value_ref_t;
as *const extern "C" fn(
ctx: *mut kclvm_context_t,
scope: *mut kclvm_eval_scope_t,
) -> *mut kclvm_value_ref_t;

unsafe {
if kclvm_main.is_null() {
panic!("kcl program main function not found");
}
(*kclvm_main)(ctx);
(*kclvm_main)(ctx, scope);
}
}
Binary file modified kclvm/runtime/src/_kclvm.bc
Binary file not shown.
2 changes: 1 addition & 1 deletion kclvm/runtime/src/_kclvm.h
Original file line number Diff line number Diff line change
Expand Up @@ -484,7 +484,7 @@ kclvm_value_ref_t* kclvm_schema_value_new(kclvm_context_t* ctx, kclvm_value_ref_

void kclvm_scope_add_setter(kclvm_context_t* _ctx, kclvm_eval_scope_t* scope, char* pkg, char* name, uint64_t* setter);

void kclvm_scope_free(kclvm_eval_scope_t* scope);
void kclvm_scope_delete(kclvm_eval_scope_t* scope);

kclvm_value_ref_t* kclvm_scope_get(kclvm_context_t* ctx, kclvm_eval_scope_t* scope, char* pkg, char* name, char* target, kclvm_value_ref_t* default);

Expand Down
2 changes: 1 addition & 1 deletion kclvm/runtime/src/_kclvm.ll
Original file line number Diff line number Diff line change
Expand Up @@ -432,7 +432,7 @@ declare %kclvm_value_ref_t* @kclvm_schema_value_new(%kclvm_context_t* %ctx, %kcl

declare void @kclvm_scope_add_setter(%kclvm_context_t* %_ctx, %kclvm_eval_scope_t* %scope, i8* %pkg, i8* %name, i64* %setter);

declare void @kclvm_scope_free(%kclvm_eval_scope_t* %scope);
declare void @kclvm_scope_delete(%kclvm_eval_scope_t* %scope);

declare %kclvm_value_ref_t* @kclvm_scope_get(%kclvm_context_t* %ctx, %kclvm_eval_scope_t* %scope, i8* %pkg, i8* %name, i8* %target, %kclvm_value_ref_t* %default);

Expand Down
2 changes: 1 addition & 1 deletion kclvm/runtime/src/_kclvm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,7 @@ pub enum ApiFunc {
kclvm_schema_value_check,
kclvm_schema_value_new,
kclvm_scope_add_setter,
kclvm_scope_free,
kclvm_scope_delete,
kclvm_scope_get,
kclvm_scope_new,
kclvm_scope_set,
Expand Down
2 changes: 1 addition & 1 deletion kclvm/runtime/src/_kclvm_addr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,7 @@ pub fn _kclvm_get_fn_ptr_by_name(name: &str) -> u64 {
"kclvm_schema_value_check" => crate::kclvm_schema_value_check as *const () as u64,
"kclvm_schema_value_new" => crate::kclvm_schema_value_new as *const () as u64,
"kclvm_scope_add_setter" => crate::kclvm_scope_add_setter as *const () as u64,
"kclvm_scope_free" => crate::kclvm_scope_free as *const () as u64,
"kclvm_scope_delete" => crate::kclvm_scope_delete as *const () as u64,
"kclvm_scope_get" => crate::kclvm_scope_get as *const () as u64,
"kclvm_scope_new" => crate::kclvm_scope_new as *const () as u64,
"kclvm_scope_set" => crate::kclvm_scope_set as *const () as u64,
Expand Down
6 changes: 3 additions & 3 deletions kclvm/runtime/src/_kclvm_api_spec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,9 @@
// api-spec(c): kclvm_eval_scope_t* kclvm_scope_new();
// api-spec(llvm): declare %kclvm_eval_scope_t* @kclvm_scope_new();

// api-spec: kclvm_scope_free
// api-spec(c): void kclvm_scope_free(kclvm_eval_scope_t* scope);
// api-spec(llvm): declare void @kclvm_scope_free(%kclvm_eval_scope_t* %scope);
// api-spec: kclvm_scope_delete
// api-spec(c): void kclvm_scope_delete(kclvm_eval_scope_t* scope);
// api-spec(llvm): declare void @kclvm_scope_delete(%kclvm_eval_scope_t* %scope);

// api-spec: kclvm_scope_add_setter
// api-spec(c): void kclvm_scope_add_setter(kclvm_context_t* _ctx, kclvm_eval_scope_t* scope, char* pkg, char* name, uint64_t* setter);
Expand Down
18 changes: 0 additions & 18 deletions kclvm/runtime/src/_kclvm_main_win.c

This file was deleted.

2 changes: 1 addition & 1 deletion kclvm/runtime/src/context/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ pub unsafe extern "C" fn kclvm_scope_new() -> *mut kclvm_eval_scope_t {

#[no_mangle]
#[runtime_fn]
pub unsafe extern "C" fn kclvm_scope_free(scope: *mut kclvm_eval_scope_t) {
pub unsafe extern "C" fn kclvm_scope_delete(scope: *mut kclvm_eval_scope_t) {
drop(Box::from_raw(scope));
}

Expand Down
4 changes: 3 additions & 1 deletion kclvm/tools/src/testing/suite.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,11 @@ use kclvm_driver::{get_kcl_files, get_pkg_list};
use kclvm_parser::{parse_file_force_errors, ParseSessionRef};
#[cfg(feature = "llvm")]
use kclvm_runner::build_program;
#[cfg(not(feature = "llvm"))]
use kclvm_runner::exec_program;
#[cfg(feature = "llvm")]
use kclvm_runner::runner::ProgramRunner;
use kclvm_runner::{exec_program, ExecProgramArgs};
use kclvm_runner::ExecProgramArgs;
use std::time::Instant;

/// File suffix for test files.
Expand Down
15 changes: 15 additions & 0 deletions test/grammar/schema/irrelevant_order/simple_10/main.k
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
schema Data:
name: str
version?: str

data1 = Data {
name = data2.name
}

data2 = Data {
name = "1"
version = version
}

# Global version
version = "v0.1.0"
6 changes: 6 additions & 0 deletions test/grammar/schema/irrelevant_order/simple_10/stdout.golden
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
data1:
name: '1'
data2:
name: '1'
version: v0.1.0
version: v0.1.0
2 changes: 2 additions & 0 deletions test/grammar/schema/irrelevant_order/simple_7/main.k
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
b = a
a = 1
2 changes: 2 additions & 0 deletions test/grammar/schema/irrelevant_order/simple_7/stdout.golden
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
b: 1
a: 1
3 changes: 3 additions & 0 deletions test/grammar/schema/irrelevant_order/simple_8/main.k
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
b = a + c
a = 1
c = a + 1
3 changes: 3 additions & 0 deletions test/grammar/schema/irrelevant_order/simple_8/stdout.golden
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
b: 3
a: 1
c: 2
Empty file.
3 changes: 3 additions & 0 deletions test/grammar/schema/irrelevant_order/simple_9/main.k
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import pkg

output = pkg.output
4 changes: 4 additions & 0 deletions test/grammar/schema/irrelevant_order/simple_9/pkg/base.k
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
schema MyApp:
name: str
versions: {str:str}
version = versions[name]
5 changes: 5 additions & 0 deletions test/grammar/schema/irrelevant_order/simple_9/pkg/input.k
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
output = MyApp{
name = name
versions = my_versions
}
name = "my_app"
3 changes: 3 additions & 0 deletions test/grammar/schema/irrelevant_order/simple_9/pkg/versions.k
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
my_versions = {
"my-app": "1.0.0"
}
4 changes: 4 additions & 0 deletions test/grammar/schema/irrelevant_order/simple_9/stdout.golden
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
output:
name: my_app
versions:
my-app: 1.0.0

0 comments on commit 5069c1e

Please sign in to comment.