From b1d118cd3d5de465a35b41fcd2a96231f8fbdb34 Mon Sep 17 00:00:00 2001 From: ilbertt Date: Tue, 17 Jun 2025 14:40:47 +0200 Subject: [PATCH 1/7] refactor: move `IDL*` types into the candid crate, under the `parser` feature flag --- rust/candid/Cargo.toml | 3 +- rust/candid/src/types/mod.rs | 2 + .../types.rs => candid/src/types/parser.rs} | 46 +++---------------- rust/candid_parser/src/bindings/javascript.rs | 3 +- rust/candid_parser/src/bindings/motoko.rs | 4 +- rust/candid_parser/src/error.rs | 17 ++++++- rust/candid_parser/src/grammar.lalrpop | 2 +- rust/candid_parser/src/lib.rs | 36 +++++++++++---- rust/candid_parser/src/test.rs | 2 +- rust/candid_parser/src/typing.rs | 20 ++++---- rust/candid_parser/src/utils.rs | 18 ++++---- rust/candid_parser/tests/parse_type.rs | 8 ++-- rust/candid_parser/tests/parse_value.rs | 5 +- rust/candid_parser/tests/value.rs | 4 +- tools/didc/src/main.rs | 17 ++++--- 15 files changed, 100 insertions(+), 87 deletions(-) rename rust/{candid_parser/src/types.rs => candid/src/types/parser.rs} (65%) diff --git a/rust/candid/Cargo.toml b/rust/candid/Cargo.toml index d6bb9140a..0223703a4 100644 --- a/rust/candid/Cargo.toml +++ b/rust/candid/Cargo.toml @@ -45,8 +45,9 @@ candid_parser = { path = "../candid_parser" } bignum = ["dep:num-bigint", "dep:num-traits"] printer = ["dep:pretty"] value = ["bignum", "printer"] +parser = [] default = ["serde_bytes", "printer", "bignum"] -all = ["default", "value", "ic_principal/arbitrary"] +all = ["default", "value", "ic_principal/arbitrary", "parser"] [[test]] name = "types" diff --git a/rust/candid/src/types/mod.rs b/rust/candid/src/types/mod.rs index 72b385c90..6bad935ba 100644 --- a/rust/candid/src/types/mod.rs +++ b/rust/candid/src/types/mod.rs @@ -8,6 +8,8 @@ use serde::ser::Error; mod impls; pub mod internal; +#[cfg(feature = "parser")] +pub mod parser; pub mod subtype; pub mod type_env; #[cfg_attr(docsrs, doc(cfg(feature = "value")))] diff --git a/rust/candid_parser/src/types.rs b/rust/candid/src/types/parser.rs similarity index 65% rename from rust/candid_parser/src/types.rs rename to rust/candid/src/types/parser.rs index 91ed6efdb..1f943ea2d 100644 --- a/rust/candid_parser/src/types.rs +++ b/rust/candid/src/types/parser.rs @@ -1,7 +1,6 @@ -use crate::Result; -use candid::types::{FuncMode, Label}; +use crate::types::{FuncMode, Label}; -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialEq, Eq)] pub enum IDLType { PrimT(PrimType), VarT(String), @@ -60,14 +59,14 @@ pub enum PrimType { Empty, }} -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialEq, Eq)] pub struct FuncType { pub modes: Vec, pub args: Vec, pub rets: Vec, } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialEq, Eq)] pub struct IDLArgType { pub typ: IDLType, pub name: Option, @@ -91,7 +90,7 @@ impl IDLArgType { } } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialEq, Eq)] pub struct TypeField { pub label: Label, pub typ: IDLType, @@ -104,13 +103,13 @@ pub enum Dec { ImportServ(String), } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialEq, Eq)] pub struct Binding { pub id: String, pub typ: IDLType, } -#[derive(Debug)] +#[derive(Debug, Default)] pub struct IDLProg { pub decs: Vec, pub actor: Option, @@ -121,34 +120,3 @@ pub struct IDLInitArgs { pub decs: Vec, pub args: Vec, } - -impl std::str::FromStr for IDLProg { - type Err = crate::Error; - fn from_str(str: &str) -> Result { - 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 { - let lexer = super::token::Tokenizer::new(str); - Ok(super::grammar::IDLInitArgsParser::new().parse(lexer)?) - } -} - -impl std::str::FromStr for IDLType { - type Err = crate::Error; - fn from_str(str: &str) -> Result { - let lexer = super::token::Tokenizer::new(str); - Ok(super::grammar::TypParser::new().parse(lexer)?) - } -} - -impl std::str::FromStr for IDLTypes { - type Err = crate::Error; - fn from_str(str: &str) -> Result { - let lexer = super::token::Tokenizer::new(str); - Ok(super::grammar::TypsParser::new().parse(lexer)?) - } -} diff --git a/rust/candid_parser/src/bindings/javascript.rs b/rust/candid_parser/src/bindings/javascript.rs index c0db60de6..b21d5f501 100644 --- a/rust/candid_parser/src/bindings/javascript.rs +++ b/rust/candid_parser/src/bindings/javascript.rs @@ -370,6 +370,7 @@ pub mod test { use super::value; use crate::test::{HostAssert, HostTest, Test}; use candid::pretty::utils::*; + use candid::types::parser::IDLProg; use candid::TypeEnv; use pretty::RcDoc; @@ -405,7 +406,7 @@ import { Principal } from './principal'; let mut env = TypeEnv::new(); crate::check_prog( &mut env, - &crate::IDLProg { + &IDLProg { decs: test.defs, actor: None, }, diff --git a/rust/candid_parser/src/bindings/motoko.rs b/rust/candid_parser/src/bindings/motoko.rs index f7ceb949a..29dac5dba 100644 --- a/rust/candid_parser/src/bindings/motoko.rs +++ b/rust/candid_parser/src/bindings/motoko.rs @@ -3,8 +3,8 @@ use candid::pretty::candid::is_valid_as_id; use candid::pretty::utils::*; -use candid::types::{ArgType, FuncMode}; -use candid::types::{Field, Function, Label, SharedLabel, Type, TypeEnv, TypeInner}; +use candid::types::{ArgType, Field, FuncMode, Function, Label, SharedLabel, Type, TypeInner}; +use candid::TypeEnv; use pretty::RcDoc; // The definition of tuple is language specific. diff --git a/rust/candid_parser/src/error.rs b/rust/candid_parser/src/error.rs index 75b46e3e8..5445fcd0d 100644 --- a/rust/candid_parser/src/error.rs +++ b/rust/candid_parser/src/error.rs @@ -1,10 +1,11 @@ //! When serializing or deserializing Candid goes wrong. +use candid::types::parser::{IDLProg, IDLTypes}; use codespan_reporting::diagnostic::Label; use std::io; use thiserror::Error; -use crate::token; +use crate::{parse_idl_prog, parse_idl_types, token}; use codespan_reporting::{ diagnostic::Diagnostic, files::{Error as ReportError, SimpleFile}, @@ -115,6 +116,20 @@ where }) } +pub fn pretty_parse_idl_prog(name: &str, str: &str) -> Result { + parse_idl_prog(str).or_else(|e| { + pretty_diagnose(name, str, &e)?; + Err(e) + }) +} + +pub fn pretty_parse_idl_types(name: &str, str: &str) -> Result { + parse_idl_types(str).or_else(|e| { + pretty_diagnose(name, str, &e)?; + Err(e) + }) +} + /// Wrap the parser error and pretty print the error message. /// ``` /// use candid_parser::{pretty_wrap, parse_idl_args}; diff --git a/rust/candid_parser/src/grammar.lalrpop b/rust/candid_parser/src/grammar.lalrpop index 3a3f3bb05..316c22de7 100644 --- a/rust/candid_parser/src/grammar.lalrpop +++ b/rust/candid_parser/src/grammar.lalrpop @@ -1,7 +1,7 @@ -use super::types::{IDLType, PrimType, TypeField, FuncType, Binding, Dec, IDLProg, IDLTypes, IDLInitArgs, IDLArgType}; use super::test::{Assert, Input, Test}; use super::token::{Token, error, error2, LexicalError, Span}; use candid::{Principal, types::Label}; +use candid::types::parser::{IDLType, PrimType, TypeField, FuncType, Binding, Dec, IDLProg, IDLTypes, IDLInitArgs, IDLArgType}; use candid::types::value::{IDLField, IDLValue, IDLArgs, VariantValue}; use candid::types::{TypeEnv, FuncMode}; use candid::utils::check_unique; diff --git a/rust/candid_parser/src/lib.rs b/rust/candid_parser/src/lib.rs index ca850bcdf..73fdd34e2 100644 --- a/rust/candid_parser/src/lib.rs +++ b/rust/candid_parser/src/lib.rs @@ -47,7 +47,7 @@ //! ``` //! # fn f() -> anyhow::Result<()> { //! use candid::{TypeEnv, types::{Type, TypeInner}}; -//! use candid_parser::{IDLProg, check_prog}; +//! use candid_parser::{check_prog, parse_idl_prog}; //! let did_file = r#" //! type List = opt record { head: int; tail: List }; //! type byte = nat8; @@ -58,7 +58,7 @@ //! "#; //! //! // Parse did file into an AST -//! let ast: IDLProg = did_file.parse()?; +//! let ast = parse_idl_prog(did_file)?; //! //! // Type checking a given .did file //! // let (env, opt_actor) = check_file("a.did")?; @@ -86,7 +86,7 @@ //! use candid::{IDLArgs, types::value::IDLValue}; //! use candid_parser::parse_idl_args; //! # use candid::TypeEnv; -//! # use candid_parser::{IDLProg, check_prog}; +//! # use candid_parser::{check_prog, parse_idl_prog}; //! # let did_file = r#" //! # type List = opt record { head: int; tail: List }; //! # type byte = nat8; @@ -95,7 +95,7 @@ //! # g : (List) -> (int) query; //! # } //! # "#; -//! # let ast = did_file.parse::()?; +//! # let ast = parse_idl_prog(did_file)?; //! # let mut env = TypeEnv::new(); //! # let actor = check_prog(&mut env, &ast)?.unwrap(); //! // Get method type f : (byte, int, nat, int8) -> (List) @@ -119,15 +119,15 @@ #![cfg_attr(docsrs, feature(doc_cfg))] pub mod error; -pub use error::{pretty_parse, pretty_wrap, Error, Result}; +pub use error::{ + pretty_parse, pretty_parse_idl_prog, pretty_parse_idl_types, pretty_wrap, Error, Result, +}; pub mod bindings; pub mod grammar; pub mod token; -pub mod types; -pub mod utils; -pub use types::IDLProg; pub mod typing; +pub mod utils; pub use typing::{check_file, check_prog, pretty_check_file}; pub use candid; @@ -142,6 +142,26 @@ pub mod configs; pub mod random; pub mod test; +pub fn parse_idl_prog(str: &str) -> Result { + let lexer = token::Tokenizer::new(str); + Ok(grammar::IDLProgParser::new().parse(lexer)?) +} + +pub fn parse_idl_init_args(str: &str) -> Result { + let lexer = token::Tokenizer::new(str); + Ok(grammar::IDLInitArgsParser::new().parse(lexer)?) +} + +pub fn parse_idl_type(str: &str) -> Result { + let lexer = token::Tokenizer::new(str); + Ok(grammar::TypParser::new().parse(lexer)?) +} + +pub fn parse_idl_types(str: &str) -> Result { + let lexer = token::Tokenizer::new(str); + Ok(grammar::TypsParser::new().parse(lexer)?) +} + pub fn parse_idl_args(s: &str) -> crate::Result { let lexer = token::Tokenizer::new(s); Ok(grammar::ArgsParser::new().parse(lexer)?) diff --git a/rust/candid_parser/src/test.rs b/rust/candid_parser/src/test.rs index 563b756a7..e75da188a 100644 --- a/rust/candid_parser/src/test.rs +++ b/rust/candid_parser/src/test.rs @@ -1,6 +1,6 @@ -use super::types::{Dec, IDLProg, IDLType}; use super::typing::check_prog; use crate::{Error, Result}; +use candid::types::parser::{Dec, IDLProg, IDLType}; use candid::types::value::IDLArgs; use candid::types::{Type, TypeEnv}; use candid::DecoderConfig; diff --git a/rust/candid_parser/src/typing.rs b/rust/candid_parser/src/typing.rs index 3cc20367f..5b5a45a47 100644 --- a/rust/candid_parser/src/typing.rs +++ b/rust/candid_parser/src/typing.rs @@ -1,6 +1,8 @@ -use super::types::*; -use crate::{pretty_parse, Error, Result}; -use candid::types::{ArgType, Field, Function, Type, TypeEnv, TypeInner}; +use crate::{parse_idl_prog, pretty_parse_idl_prog, Error, Result}; +use candid::types::{ + parser::{Binding, Dec, IDLArgType, IDLInitArgs, IDLProg, IDLType, PrimType, TypeField}, + ArgType, Field, Function, Type, TypeEnv, TypeInner, +}; use candid::utils::check_unique; use std::collections::{BTreeMap, BTreeSet}; use std::path::{Path, PathBuf}; @@ -11,7 +13,7 @@ pub struct Env<'a> { } /// Convert candid AST to internal Type -pub fn ast_to_type(env: &TypeEnv, ast: &super::types::IDLType) -> Result { +pub fn ast_to_type(env: &TypeEnv, ast: &IDLType) -> Result { let env = Env { te: &mut env.clone(), pre: false, @@ -237,9 +239,9 @@ fn load_imports( let code = std::fs::read_to_string(&path) .map_err(|_| Error::msg(format!("Cannot import {file:?}")))?; let code = if is_pretty { - pretty_parse::(path.to_str().unwrap(), &code)? + pretty_parse_idl_prog(path.to_str().unwrap(), &code)? } else { - code.parse::()? + parse_idl_prog(&code)? }; let base = path.parent().unwrap(); load_imports(is_pretty, base, visited, &code, list)?; @@ -324,9 +326,9 @@ fn check_file_(file: &Path, is_pretty: bool) -> Result<(TypeEnv, Option)> let prog = std::fs::read_to_string(file).map_err(|_| Error::msg(format!("Cannot open {file:?}")))?; let prog = if is_pretty { - pretty_parse::(file.to_str().unwrap(), &prog)? + pretty_parse_idl_prog(file.to_str().unwrap(), &prog)? } else { - prog.parse::()? + parse_idl_prog(&prog)? }; let mut visited = BTreeMap::new(); let mut imports = Vec::new(); @@ -346,7 +348,7 @@ fn check_file_(file: &Path, is_pretty: bool) -> Result<(TypeEnv, Option)> let mut actor: Option = None; for (include_serv, path, name) in imports.iter() { let code = std::fs::read_to_string(path)?; - let code = code.parse::()?; + let code = parse_idl_prog(&code)?; check_decs(&mut env, &code.decs)?; if *include_serv { let t = check_actor(&env, &code.actor)?; diff --git a/rust/candid_parser/src/utils.rs b/rust/candid_parser/src/utils.rs index 1552d67e2..5074a87ee 100644 --- a/rust/candid_parser/src/utils.rs +++ b/rust/candid_parser/src/utils.rs @@ -1,6 +1,8 @@ -use crate::{check_prog, pretty_check_file, pretty_parse, Error, Result}; -use candid::types::TypeInner; -use candid::{types::Type, TypeEnv}; +use crate::{check_prog, pretty_check_file, pretty_parse_idl_prog, Error, Result}; +use candid::{ + types::{Type, TypeInner}, + TypeEnv, +}; use std::path::Path; pub enum CandidSource<'a> { @@ -13,7 +15,7 @@ impl CandidSource<'_> { Ok(match self { CandidSource::File(path) => pretty_check_file(path)?, CandidSource::Text(str) => { - let ast = pretty_parse("", str)?; + let ast = pretty_parse_idl_prog("", str)?; let mut env = TypeEnv::new(); let actor = check_prog(&mut env, &ast)?; (env, actor) @@ -83,7 +85,7 @@ pub fn get_metadata(env: &TypeEnv, serv: &Option) -> Option { /// Merge canister metadata candid:args and candid:service into a service constructor. /// If candid:service already contains init args, returns the original did file. pub fn merge_init_args(candid: &str, init: &str) -> Result<(TypeEnv, Type)> { - use crate::{types::IDLInitArgs, typing::check_init_args}; + use crate::{parse_idl_init_args, typing::check_init_args}; use candid::types::TypeInner; let candid = CandidSource::Text(candid); let (env, serv) = candid.load()?; @@ -92,7 +94,7 @@ pub fn merge_init_args(candid: &str, init: &str) -> Result<(TypeEnv, Type)> { match serv.as_ref() { TypeInner::Class(_, _) => Ok((env, serv)), TypeInner::Service(_) => { - let prog = init.parse::()?; + let prog = parse_idl_init_args(init)?; let mut env2 = TypeEnv::new(); let args = check_init_args(&mut env2, &env, &prog)?; Ok((env2, TypeInner::Class(args, serv).into())) @@ -104,9 +106,9 @@ pub fn merge_init_args(candid: &str, init: &str) -> Result<(TypeEnv, Type)> { /// Note that this only checks structural equality, not equivalence. For recursive types, it may reject /// an unrolled type. pub fn check_rust_type(candid_args: &str) -> Result<()> { - use crate::{types::IDLInitArgs, typing::check_init_args}; + use crate::{parse_idl_init_args, typing::check_init_args}; use candid::types::{internal::TypeContainer, subtype::equal, TypeEnv}; - let parsed = candid_args.parse::()?; + let parsed = parse_idl_init_args(candid_args)?; let mut env = TypeEnv::new(); let args = check_init_args(&mut env, &TypeEnv::new(), &parsed)?; let mut rust_env = TypeContainer::new(); diff --git a/rust/candid_parser/tests/parse_type.rs b/rust/candid_parser/tests/parse_type.rs index ad9569404..3129c4afd 100644 --- a/rust/candid_parser/tests/parse_type.rs +++ b/rust/candid_parser/tests/parse_type.rs @@ -2,14 +2,14 @@ use candid::pretty::candid::compile; use candid::types::TypeEnv; use candid_parser::bindings::{javascript, motoko, rust, typescript}; use candid_parser::configs::Configs; -use candid_parser::types::IDLProg; +use candid_parser::parse_idl_prog; use candid_parser::typing::{check_file, check_prog}; use goldenfile::Mint; use std::io::Write; use std::path::Path; #[test] -fn parse_idl_prog() { +fn test_parse_idl_prog() { let prog = r#" import "test.did"; type my_type = principal; @@ -28,7 +28,7 @@ service server : { i : f; } "#; - prog.parse::().unwrap(); + parse_idl_prog(prog).unwrap(); } #[test_generator::test_resources("rust/candid_parser/tests/assets/*.did")] @@ -45,7 +45,7 @@ fn compiler_test(resource: &str) { let mut output = mint.new_goldenfile(filename.with_extension("did")).unwrap(); let content = compile(&env, &actor); // Type check output - let ast = content.parse::().unwrap(); + let ast = parse_idl_prog(&content).unwrap(); check_prog(&mut TypeEnv::new(), &ast).unwrap(); writeln!(output, "{content}").unwrap(); } diff --git a/rust/candid_parser/tests/parse_value.rs b/rust/candid_parser/tests/parse_value.rs index 65c23769b..c93f5d587 100644 --- a/rust/candid_parser/tests/parse_value.rs +++ b/rust/candid_parser/tests/parse_value.rs @@ -1,7 +1,7 @@ use candid::types::value::{IDLArgs, IDLField, IDLValue, VariantValue}; use candid::types::{Label, Type, TypeEnv, TypeInner}; use candid::{record, variant, CandidType, Nat}; -use candid_parser::parse_idl_args; +use candid_parser::{parse_idl_args, parse_idl_type}; fn parse_args(input: &str) -> IDLArgs { parse_idl_args(input).unwrap() @@ -12,9 +12,8 @@ fn parse_args_err(input: &str) -> candid_parser::Result { } fn parse_type(input: &str) -> Type { - use candid_parser::types::IDLType; let env = TypeEnv::new(); - let ast = input.parse::().unwrap(); + let ast = parse_idl_type(input).unwrap(); candid_parser::typing::ast_to_type(&env, &ast).unwrap() } diff --git a/rust/candid_parser/tests/value.rs b/rust/candid_parser/tests/value.rs index e23a579a4..aa6e0a281 100644 --- a/rust/candid_parser/tests/value.rs +++ b/rust/candid_parser/tests/value.rs @@ -1,7 +1,7 @@ use candid::types::value::{IDLArgs, IDLField, IDLValue, VariantValue}; use candid::types::{Label, TypeEnv}; use candid::{decode_args, decode_one, Decode}; -use candid_parser::{parse_idl_args, types::IDLProg, typing::check_prog}; +use candid_parser::{parse_idl_args, parse_idl_prog, typing::check_prog}; #[test] fn test_parser() { @@ -31,7 +31,7 @@ service : { f : f; } "#; - let ast = candid.parse::().unwrap(); + let ast = parse_idl_prog(candid).unwrap(); let mut env = TypeEnv::new(); let actor = check_prog(&mut env, &ast).unwrap().unwrap(); let method = env.get_method(&actor, "f").unwrap(); diff --git a/tools/didc/src/main.rs b/tools/didc/src/main.rs index 26e0836ab..0447dc31e 100644 --- a/tools/didc/src/main.rs +++ b/tools/didc/src/main.rs @@ -1,11 +1,12 @@ use anyhow::{bail, Result}; -use candid_parser::candid::types::{subtype, Type}; +use candid_parser::candid::types::{ + parser::{IDLType, IDLTypes}, + subtype, Type, +}; use candid_parser::{ - configs::Configs, - parse_idl_args, parse_idl_value, pretty_check_file, pretty_parse, pretty_wrap, - types::{IDLType, IDLTypes}, - typing::ast_to_type, - Error, IDLArgs, IDLValue, TypeEnv, + configs::Configs, parse_idl_args, parse_idl_type, parse_idl_value, pretty_check_file, + pretty_parse, pretty_parse_idl_types, pretty_wrap, typing::ast_to_type, Error, IDLArgs, + IDLValue, TypeEnv, }; use clap::Parser; use console::style; @@ -98,7 +99,9 @@ enum Command { Subtype { #[clap(short, long)] defs: Option, + #[clap(value_parser = parse_idl_type)] ty1: IDLType, + #[clap(value_parser = parse_idl_type)] ty2: IDLType, }, } @@ -160,7 +163,7 @@ fn parse_args(str: &str) -> Result { pretty_wrap("candid arguments", str, parse_idl_args) } fn parse_types(str: &str) -> Result { - pretty_parse("type annotations", str) + pretty_parse_idl_types("type annotations", str) } fn load_config(input: &Option) -> Result { match input { From 6f0fd7805526cb048b555b171ad682772eb7b11e Mon Sep 17 00:00:00 2001 From: ilbertt Date: Tue, 17 Jun 2025 16:37:12 +0200 Subject: [PATCH 2/7] chore: update changelog and docs --- Changelog.md | 33 ++++++++++++++++++++++++++++++++- rust/candid_parser/src/error.rs | 1 + 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/Changelog.md b/Changelog.md index e901a0513..78e8c4646 100644 --- a/Changelog.md +++ b/Changelog.md @@ -6,11 +6,42 @@ ### Candid * Breaking changes: - + `pp_args` and `pp_init_args` noew require a `&[ArgType]` parameter. The `pp_rets` function has been added, with the signature of the old `pp_args`. + + `pp_args` and `pp_init_args` now require a `&[ArgType]` parameter. The `pp_rets` function has been added, with the signature of the old `pp_args`. + +* Non-breaking changes: + + The following structs have been moved from the `candid_parser` crate to the `candid::types::parser` module, under the `parser` feature flag: + - `IDLType` + - `IDLTypes` + - `PrimType` + - `FuncType` + - `IDLArgType` + - `TypeField` + - `Dec` + - `Binding` + - `IDLProg` + - `IDLInitArgs` ### candid_parser * Breaking changes: + + The following structs have been moved to the `candid` crate: + - `IDLType` + - `IDLTypes` + - `PrimType` + - `FuncType` + - `IDLArgType` + - `TypeField` + - `Dec` + - `Binding` + - `IDLProg` + - `IDLInitArgs` + As a consequence, the `FromStr` trait is no longer implemented for the following types: + - `IDLProg` + - `IDLInitArgs` + - `IDLType` + - `IDLTypes` + You must now use the `parse_idl_prog`, `parse_idl_init_args`, `parse_idl_type` and `parse_idl_types` functions to parse these types, respectively. + + `pretty_parse` doesn't work anymore with the `IDLProg` and `IDLTypes` types. Use `pretty_parse_idl_prog` and `pretty_parse_idl_types` instead. + The `args` field in both `FuncType` and `IDLInitArgs` now have type `Vec`. * Non-breaking changes: diff --git a/rust/candid_parser/src/error.rs b/rust/candid_parser/src/error.rs index 5445fcd0d..b4e3b4dfe 100644 --- a/rust/candid_parser/src/error.rs +++ b/rust/candid_parser/src/error.rs @@ -106,6 +106,7 @@ impl From for Error { } } +/// Does not work for parsing [IDLProg] and [IDLTypes], use [pretty_parse_idl_prog] and [pretty_parse_idl_types] instead. pub fn pretty_parse(name: &str, str: &str) -> Result where T: std::str::FromStr, From a9aee1ca97281d5d3abe8b0f2a6d26564a181305 Mon Sep 17 00:00:00 2001 From: ilbertt Date: Tue, 17 Jun 2025 16:47:16 +0200 Subject: [PATCH 3/7] refactor: map pretty error --- rust/candid_parser/src/error.rs | 25 +++++++++---------------- 1 file changed, 9 insertions(+), 16 deletions(-) diff --git a/rust/candid_parser/src/error.rs b/rust/candid_parser/src/error.rs index b4e3b4dfe..7b35942e9 100644 --- a/rust/candid_parser/src/error.rs +++ b/rust/candid_parser/src/error.rs @@ -111,24 +111,15 @@ pub fn pretty_parse(name: &str, str: &str) -> Result where T: std::str::FromStr, { - str.parse::().or_else(|e| { - pretty_diagnose(name, str, &e)?; - Err(e) - }) + str.parse::().or_else(|e| pretty_print_err(name, str, e)) } pub fn pretty_parse_idl_prog(name: &str, str: &str) -> Result { - parse_idl_prog(str).or_else(|e| { - pretty_diagnose(name, str, &e)?; - Err(e) - }) + parse_idl_prog(str).or_else(|e| pretty_print_err(name, str, e)) } pub fn pretty_parse_idl_types(name: &str, str: &str) -> Result { - parse_idl_types(str).or_else(|e| { - pretty_diagnose(name, str, &e)?; - Err(e) - }) + parse_idl_types(str).or_else(|e| pretty_print_err(name, str, e)) } /// Wrap the parser error and pretty print the error message. @@ -138,10 +129,12 @@ pub fn pretty_parse_idl_types(name: &str, str: &str) -> Result { /// # Ok::<(), candid_parser::Error>(()) /// ``` pub fn pretty_wrap(name: &str, str: &str, f: impl FnOnce(&str) -> Result) -> Result { - f(str).or_else(|e| { - pretty_diagnose(name, str, &e)?; - Err(e) - }) + f(str).or_else(|e| pretty_print_err(name, str, e)) +} + +fn pretty_print_err(name: &str, source: &str, e: Error) -> Result { + pretty_diagnose(name, source, &e)?; + Err(e) } pub fn pretty_diagnose(file_name: &str, source: &str, e: &Error) -> Result<()> { From 74f84c9f30568f8d08b84be0ecc2eb34b4ef5df3 Mon Sep 17 00:00:00 2001 From: ilbertt Date: Wed, 18 Jun 2025 09:24:24 +0200 Subject: [PATCH 4/7] refactor: rename parser to syntax --- rust/candid/Cargo.toml | 4 ++-- rust/candid/src/types/mod.rs | 4 ++-- rust/candid/src/types/{parser.rs => syntax.rs} | 0 rust/candid_parser/src/bindings/javascript.rs | 2 +- rust/candid_parser/src/error.rs | 2 +- rust/candid_parser/src/grammar.lalrpop | 2 +- rust/candid_parser/src/lib.rs | 8 ++++---- rust/candid_parser/src/test.rs | 2 +- rust/candid_parser/src/typing.rs | 2 +- tools/didc/src/main.rs | 5 +++-- 10 files changed, 16 insertions(+), 15 deletions(-) rename rust/candid/src/types/{parser.rs => syntax.rs} (100%) diff --git a/rust/candid/Cargo.toml b/rust/candid/Cargo.toml index 0223703a4..88c405446 100644 --- a/rust/candid/Cargo.toml +++ b/rust/candid/Cargo.toml @@ -45,9 +45,9 @@ candid_parser = { path = "../candid_parser" } bignum = ["dep:num-bigint", "dep:num-traits"] printer = ["dep:pretty"] value = ["bignum", "printer"] -parser = [] +syntax = [] default = ["serde_bytes", "printer", "bignum"] -all = ["default", "value", "ic_principal/arbitrary", "parser"] +all = ["default", "value", "ic_principal/arbitrary", "syntax"] [[test]] name = "types" diff --git a/rust/candid/src/types/mod.rs b/rust/candid/src/types/mod.rs index 6bad935ba..92df03eb0 100644 --- a/rust/candid/src/types/mod.rs +++ b/rust/candid/src/types/mod.rs @@ -8,9 +8,9 @@ use serde::ser::Error; mod impls; pub mod internal; -#[cfg(feature = "parser")] -pub mod parser; pub mod subtype; +#[cfg(feature = "syntax")] +pub mod syntax; pub mod type_env; #[cfg_attr(docsrs, doc(cfg(feature = "value")))] #[cfg(feature = "value")] diff --git a/rust/candid/src/types/parser.rs b/rust/candid/src/types/syntax.rs similarity index 100% rename from rust/candid/src/types/parser.rs rename to rust/candid/src/types/syntax.rs diff --git a/rust/candid_parser/src/bindings/javascript.rs b/rust/candid_parser/src/bindings/javascript.rs index b21d5f501..11b54cd96 100644 --- a/rust/candid_parser/src/bindings/javascript.rs +++ b/rust/candid_parser/src/bindings/javascript.rs @@ -370,7 +370,7 @@ pub mod test { use super::value; use crate::test::{HostAssert, HostTest, Test}; use candid::pretty::utils::*; - use candid::types::parser::IDLProg; + use candid::types::syntax::IDLProg; use candid::TypeEnv; use pretty::RcDoc; diff --git a/rust/candid_parser/src/error.rs b/rust/candid_parser/src/error.rs index 7b35942e9..8ebd53cf3 100644 --- a/rust/candid_parser/src/error.rs +++ b/rust/candid_parser/src/error.rs @@ -1,6 +1,6 @@ //! When serializing or deserializing Candid goes wrong. -use candid::types::parser::{IDLProg, IDLTypes}; +use candid::types::syntax::{IDLProg, IDLTypes}; use codespan_reporting::diagnostic::Label; use std::io; use thiserror::Error; diff --git a/rust/candid_parser/src/grammar.lalrpop b/rust/candid_parser/src/grammar.lalrpop index 316c22de7..28abc6394 100644 --- a/rust/candid_parser/src/grammar.lalrpop +++ b/rust/candid_parser/src/grammar.lalrpop @@ -1,7 +1,7 @@ use super::test::{Assert, Input, Test}; use super::token::{Token, error, error2, LexicalError, Span}; use candid::{Principal, types::Label}; -use candid::types::parser::{IDLType, PrimType, TypeField, FuncType, Binding, Dec, IDLProg, IDLTypes, IDLInitArgs, IDLArgType}; +use candid::types::syntax::{IDLType, PrimType, TypeField, FuncType, Binding, Dec, IDLProg, IDLTypes, IDLInitArgs, IDLArgType}; use candid::types::value::{IDLField, IDLValue, IDLArgs, VariantValue}; use candid::types::{TypeEnv, FuncMode}; use candid::utils::check_unique; diff --git a/rust/candid_parser/src/lib.rs b/rust/candid_parser/src/lib.rs index 73fdd34e2..4086ac3c8 100644 --- a/rust/candid_parser/src/lib.rs +++ b/rust/candid_parser/src/lib.rs @@ -142,22 +142,22 @@ pub mod configs; pub mod random; pub mod test; -pub fn parse_idl_prog(str: &str) -> Result { +pub fn parse_idl_prog(str: &str) -> Result { let lexer = token::Tokenizer::new(str); Ok(grammar::IDLProgParser::new().parse(lexer)?) } -pub fn parse_idl_init_args(str: &str) -> Result { +pub fn parse_idl_init_args(str: &str) -> Result { let lexer = token::Tokenizer::new(str); Ok(grammar::IDLInitArgsParser::new().parse(lexer)?) } -pub fn parse_idl_type(str: &str) -> Result { +pub fn parse_idl_type(str: &str) -> Result { let lexer = token::Tokenizer::new(str); Ok(grammar::TypParser::new().parse(lexer)?) } -pub fn parse_idl_types(str: &str) -> Result { +pub fn parse_idl_types(str: &str) -> Result { let lexer = token::Tokenizer::new(str); Ok(grammar::TypsParser::new().parse(lexer)?) } diff --git a/rust/candid_parser/src/test.rs b/rust/candid_parser/src/test.rs index e75da188a..9f3dbd970 100644 --- a/rust/candid_parser/src/test.rs +++ b/rust/candid_parser/src/test.rs @@ -1,6 +1,6 @@ use super::typing::check_prog; use crate::{Error, Result}; -use candid::types::parser::{Dec, IDLProg, IDLType}; +use candid::types::syntax::{Dec, IDLProg, IDLType}; use candid::types::value::IDLArgs; use candid::types::{Type, TypeEnv}; use candid::DecoderConfig; diff --git a/rust/candid_parser/src/typing.rs b/rust/candid_parser/src/typing.rs index 5b5a45a47..a4a7d7daf 100644 --- a/rust/candid_parser/src/typing.rs +++ b/rust/candid_parser/src/typing.rs @@ -1,6 +1,6 @@ use crate::{parse_idl_prog, pretty_parse_idl_prog, Error, Result}; use candid::types::{ - parser::{Binding, Dec, IDLArgType, IDLInitArgs, IDLProg, IDLType, PrimType, TypeField}, + syntax::{Binding, Dec, IDLArgType, IDLInitArgs, IDLProg, IDLType, PrimType, TypeField}, ArgType, Field, Function, Type, TypeEnv, TypeInner, }; use candid::utils::check_unique; diff --git a/tools/didc/src/main.rs b/tools/didc/src/main.rs index 0447dc31e..49d16928e 100644 --- a/tools/didc/src/main.rs +++ b/tools/didc/src/main.rs @@ -1,7 +1,8 @@ use anyhow::{bail, Result}; use candid_parser::candid::types::{ - parser::{IDLType, IDLTypes}, - subtype, Type, + subtype, + syntax::{IDLType, IDLTypes}, + Type, }; use candid_parser::{ configs::Configs, parse_idl_args, parse_idl_type, parse_idl_value, pretty_check_file, From 3144ce6dcacf78ab31c8da083694fe9abbc4c43b Mon Sep 17 00:00:00 2001 From: ilbertt Date: Fri, 20 Jun 2025 18:41:45 +0200 Subject: [PATCH 5/7] refactor: remove "syntax" feature --- rust/candid/Cargo.toml | 3 +-- rust/candid/src/types/mod.rs | 1 - 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/rust/candid/Cargo.toml b/rust/candid/Cargo.toml index 88c405446..d6bb9140a 100644 --- a/rust/candid/Cargo.toml +++ b/rust/candid/Cargo.toml @@ -45,9 +45,8 @@ candid_parser = { path = "../candid_parser" } bignum = ["dep:num-bigint", "dep:num-traits"] printer = ["dep:pretty"] value = ["bignum", "printer"] -syntax = [] default = ["serde_bytes", "printer", "bignum"] -all = ["default", "value", "ic_principal/arbitrary", "syntax"] +all = ["default", "value", "ic_principal/arbitrary"] [[test]] name = "types" diff --git a/rust/candid/src/types/mod.rs b/rust/candid/src/types/mod.rs index 92df03eb0..93852a7e7 100644 --- a/rust/candid/src/types/mod.rs +++ b/rust/candid/src/types/mod.rs @@ -9,7 +9,6 @@ use serde::ser::Error; mod impls; pub mod internal; pub mod subtype; -#[cfg(feature = "syntax")] pub mod syntax; pub mod type_env; #[cfg_attr(docsrs, doc(cfg(feature = "value")))] From f097c4cebcbf06b368ef6730d5fd2e7cead62674 Mon Sep 17 00:00:00 2001 From: ilbertt Date: Fri, 20 Jun 2025 18:44:54 +0200 Subject: [PATCH 6/7] chore: update changelog --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 78e8c4646..a7ae547b4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,7 +9,7 @@ + `pp_args` and `pp_init_args` now require a `&[ArgType]` parameter. The `pp_rets` function has been added, with the signature of the old `pp_args`. * Non-breaking changes: - + The following structs have been moved from the `candid_parser` crate to the `candid::types::parser` module, under the `parser` feature flag: + + The following structs have been moved from the `candid_parser` crate to the `candid::types::syntax` module: - `IDLType` - `IDLTypes` - `PrimType` From b93c4d8c8682d30928c0f4c47f9de4414568f4f9 Mon Sep 17 00:00:00 2001 From: ilbertt Date: Wed, 25 Jun 2025 16:30:02 +0200 Subject: [PATCH 7/7] style: remove unused import --- tools/didc/src/main.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tools/didc/src/main.rs b/tools/didc/src/main.rs index 872c84e5c..89959ddd9 100644 --- a/tools/didc/src/main.rs +++ b/tools/didc/src/main.rs @@ -6,8 +6,7 @@ use candid_parser::candid::types::{ }; use candid_parser::{ configs::Configs, parse_idl_args, parse_idl_type, parse_idl_value, pretty_check_file, - pretty_parse, pretty_parse_idl_types, pretty_wrap, typing::ast_to_type, Error, IDLArgs, - IDLValue, TypeEnv, + pretty_parse_idl_types, pretty_wrap, typing::ast_to_type, Error, IDLArgs, IDLValue, TypeEnv, }; use clap::Parser; use console::style;