Skip to content

Commit

Permalink
add merge_init_args function merge candid:args and candid:service met…
Browse files Browse the repository at this point in the history
…adata
  • Loading branch information
chenyan-dfinity committed Sep 8, 2023
1 parent dbee878 commit 888487d
Show file tree
Hide file tree
Showing 7 changed files with 98 additions and 31 deletions.
6 changes: 5 additions & 1 deletion rust/candid/src/parser/grammar.lalrpop
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::types::value::{IDLField, IDLValue, IDLArgs, VariantValue};
use crate::types::{TypeEnv, FuncMode};
use crate::utils::check_unique;
use super::types::{IDLType, PrimType, TypeField, FuncType, Binding, Dec, IDLProg, IDLTypes};
use super::types::{IDLType, PrimType, TypeField, FuncType, Binding, Dec, IDLProg, IDLTypes, IDLInitArgs};
use super::test::{Assert, Input, Test};
use super::token::{Token, error2, LexicalError, Span};
use crate::{Principal, types::Label};
Expand Down Expand Up @@ -272,6 +272,10 @@ pub IDLProg: IDLProg = {
<decs:SepBy<Def, ";">> <actor:MainActor?> => IDLProg { decs, actor }
}

pub IDLInitArgs: IDLInitArgs = {
<decs:SepBy<Def, ";">> <args:TupTyp> => IDLInitArgs { decs, args }
}

// Test file

Input: Input = {
Expand Down
13 changes: 13 additions & 0 deletions rust/candid/src/parser/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,13 +91,26 @@ pub struct IDLProg {
pub actor: Option<IDLType>,
}

#[derive(Debug)]
pub struct IDLInitArgs {
pub decs: Vec<Dec>,
pub args: Vec<IDLType>,
}

impl std::str::FromStr for IDLProg {
type Err = crate::Error;
fn from_str(str: &str) -> Result<Self> {
let lexer = super::token::Tokenizer::new(str);
Ok(super::grammar::IDLProgParser::new().parse(lexer)?)
}
}
impl std::str::FromStr for IDLInitArgs {
type Err = crate::Error;
fn from_str(str: &str) -> Result<Self> {
let lexer = super::token::Tokenizer::new(str);
Ok(super::grammar::IDLInitArgsParser::new().parse(lexer)?)
}
}

impl std::str::FromStr for IDLType {
type Err = crate::Error;
Expand Down
13 changes: 12 additions & 1 deletion rust/candid/src/parser/typing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -241,12 +241,23 @@ fn load_imports(
}

/// Type check IDLProg and adds bindings to type environment. Returns
/// a hash map for the serivce method signatures. This function ignores the imports.
/// the main actor if present. This function ignores the imports.
pub fn check_prog(te: &mut TypeEnv, prog: &IDLProg) -> Result<Option<Type>> {
let mut env = Env { te, pre: false };
check_decs(&mut env, &prog.decs)?;
check_actor(&env, &prog.actor)
}
/// Type check init args extracted from canister metadata candid:args.
pub fn check_init_args(te: &mut TypeEnv, main_env: &TypeEnv, prog: &IDLInitArgs) -> Result<Vec<Type>> {
let mut env = Env { te, pre: false };
check_decs(&mut env, &prog.decs)?;
env.te.merge(main_env)?;
let mut args = Vec::new();
for arg in prog.args.iter() {
args.push(check_type(&env, arg)?);
}
Ok(args)
}

fn check_file_(file: &Path, is_pretty: bool) -> Result<(TypeEnv, Option<Type>)> {
let base = if file.is_absolute() {
Expand Down
24 changes: 23 additions & 1 deletion rust/candid/src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ pub fn service_equal(left: CandidSource, right: CandidSource) -> Result<()> {
#[cfg_attr(docsrs, doc(cfg(feature = "parser")))]
#[cfg(feature = "parser")]
/// Take a did file and outputs the init args and the service type (without init args).
/// If the original did file contains imports, the output flatens the type definitions.
/// If the original did file contains imports, the output flattens the type definitions.
/// For now, the comments from the original did file is omitted.
pub fn instantiate_candid(candid: CandidSource) -> Result<(Vec<Type>, (TypeEnv, Type))> {
use crate::types::TypeInner;
Expand All @@ -95,6 +95,28 @@ pub fn instantiate_candid(candid: CandidSource) -> Result<(Vec<Type>, (TypeEnv,
})
}

/// Merge canister metadata candid:args and candid:service into a service constructor.
/// If candid:service already contains init args, returns the original did file.
#[cfg_attr(docsrs, doc(cfg(feature = "parser")))]
#[cfg(feature = "parser")]
pub fn merge_init_args(candid: &str, init: &str) -> Result<(TypeEnv, Type)> {
use crate::parser::{types::IDLInitArgs, typing::check_init_args};
use crate::types::TypeInner;
let candid = CandidSource::Text(candid);
let (env, serv) = candid.load()?;
let serv = serv.ok_or_else(|| Error::msg("the Candid interface has no main service type"))?;
match serv.as_ref() {
TypeInner::Class(_, _) => Ok((env, serv)),
TypeInner::Service(_) => {
let prog = init.parse::<IDLInitArgs>()?;
let mut env2 = TypeEnv::new();
let args = check_init_args(&mut env2, &env, &prog)?;
Ok((env2, TypeInner::Class(args, serv).into()))
}
_ => unreachable!(),
}
}

/// Encode sequence of Rust values into Candid message of type `candid::Result<Vec<u8>>`.
#[macro_export]
macro_rules! Encode {
Expand Down
60 changes: 33 additions & 27 deletions tools/ui/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 5 additions & 1 deletion tools/ui/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,8 @@ members = [

[profile.release]
lto = true
opt-level = 'z'
opt-level = 2

[patch.crates-io.candid]
path = "../../rust/candid"

7 changes: 7 additions & 0 deletions tools/ui/src/didjs/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,13 @@ fn binding(prog: String, lang: String) -> Option<String> {
Some(res)
}

#[ic_cdk::query]
fn merge_init_args(prog: String, init_args: String) -> Option<String> {
use candid::bindings;
let (env, actor) = candid::utils::merge_init_args(&prog, &init_args).ok()?;
Some(bindings::candid::compile(&env, &Some(actor)))
}

#[ic_cdk::query]
fn subtype(new: String, old: String) -> Result<(), String> {
let new = new.parse::<IDLProg>().unwrap();
Expand Down

0 comments on commit 888487d

Please sign in to comment.