Skip to content
Closed
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
6 changes: 5 additions & 1 deletion rust/candid_parser/src/grammar.lalrpop
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ extern {
":" => Token::Colon,
"->" => Token::Arrow,
"line_comment" => Token::LineComment(<Vec<String>>),
"block_comment" => Token::BlockComment(<Vec<String>>),
"\n" => Token::Newline,
}
}
Expand Down Expand Up @@ -314,8 +315,11 @@ Name: String = {
Text => <>,
}


// Prioritize the last comment
Comment: Comment = {
"line_comment" => Comment { lines: <> },
<lc:"line_comment"> <bc:"block_comment"?> => Comment { lines: bc.unwrap_or(lc) },
<bc:"block_comment"> <lc:"line_comment"?> => Comment { lines: lc.unwrap_or(bc) },
}

// Also allows trailing separator
Expand Down
69 changes: 50 additions & 19 deletions rust/candid_parser/src/token.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,16 @@ use logos::{Lexer, Logos};
#[derive(Logos, Debug, Clone, PartialEq, Eq, Ord, PartialOrd)]
#[logos(skip r"[ \t\r]+")]
#[logos(skip r"([ \t]*//[^\n]*\n)+\n")] // ignore line comments that are followed by an empty line
#[logos(skip r"[ \t]*/\*([^(\*/)]*)\*/\n\n")] // ignore block comments that are followed by an empty line
pub enum Token {
#[token("/*")]
StartComment,
// catch line comments at any indentation level, thanks to the `[ \t]*` prefix
#[regex(r"([ \t]*//[^\n]*\n)+", parse_comment_lines)]
LineComment(Vec<String>),
// catch block comments at any indentation level, thanks to the `[ \t]*` prefix
#[regex(r"[ \t]*/\*([^(\*/)]*)\*/\n", parse_block_comment_lines)]
BlockComment(Vec<String>),
#[token("=")]
Equals,
#[token("(")]
Expand Down Expand Up @@ -131,6 +135,20 @@ fn parse_comment_lines(lex: &mut Lexer<Token>) -> Vec<String> {
.collect()
}

fn parse_block_comment_lines(lex: &mut Lexer<Token>) -> Vec<String> {
lex.slice()
.lines()
.map(|s| {
s.trim()
.trim_start_matches("/*")
.trim_end_matches("*/")
.trim()
.to_string()
})
.filter(|s| !s.is_empty())
.collect()
}

pub struct Tokenizer<'input> {
lex: Lexer<'input, Token>,
}
Expand Down Expand Up @@ -217,31 +235,21 @@ impl Iterator for Tokenizer<'_> {
self.next()
}
Ok(Token::LineComment(mut lines)) => {
let span = self.lex.span();
let source = self.lex.source();

// Check the char before the span: if it's NOT a newline, it means that
// the comment is at the end of a line and therefore it must be ignored.
// If it's at the start of the source (prev_char_index == 0), we don't have to check anything.
let prev_char_index = span.start.saturating_sub(1);
if prev_char_index > 0 {
let is_end_of_line_comment = source
.chars()
.nth(prev_char_index)
.map(|c| c != '\n')
.unwrap_or(false);

if is_end_of_line_comment {
lines.remove(0);
}
}

let span = skip_isolated_comments(&self.lex, &mut lines);
// Ignore the comment if it's empty
if lines.is_empty() {
return self.next();
}
Some(Ok((span.start, Token::LineComment(lines), span.end)))
}
Ok(Token::BlockComment(mut lines)) => {
let span = skip_isolated_comments(&self.lex, &mut lines);
// Ignore the comment if it's empty
if lines.is_empty() {
return self.next();
}
Some(Ok((span.start, Token::BlockComment(lines), span.end)))
}
Ok(Token::StartString) => {
let mut result = String::new();
let mut lex = self.lex.to_owned().morph::<Text>();
Expand Down Expand Up @@ -322,3 +330,26 @@ impl Iterator for Tokenizer<'_> {
}
}
}

fn skip_isolated_comments(lex: &Lexer<Token>, comment_lines: &mut Vec<String>) -> Span {
let span = lex.span();
let source = lex.source();

// Check the char before the span: if it's NOT a newline or space, it means that
// the comment is at the end of a line and therefore it must be ignored.
// If it's at the start of the source (prev_char_index == 0), we don't have to check anything.
let prev_char_index = span.start.saturating_sub(1);
if prev_char_index > 0 {
let is_end_of_line_comment = source
.chars()
.nth(prev_char_index)
.map(|c| c != '\n' && c != ' ')
.unwrap_or(false);

if is_end_of_line_comment {
comment_lines.remove(0);
}
}

span
}
4 changes: 3 additions & 1 deletion rust/candid_parser/tests/assets/actor.did
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ type f = func (int8) -> (int8);
type g = f;
type h = func (f) -> (f);
type o = opt o;
// This is a service comment
/*
This is a service block comment
*/
service :
{
f : (nat) -> (h);
Expand Down
35 changes: 34 additions & 1 deletion rust/candid_parser/tests/assets/example.did
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,33 @@ type my_type = principal;

// This is an ignored comment

/*
This is a type block comment
*/
type List = opt record {
/*
This is a field block comment
*/
head: int;
// This is a field comment
tail: List;
}; // This comment is ignored
type f = func (List, func (int32) -> (int64)) -> (opt List, res); // This comment is ignored
// This is another type comment
type broker = service {
/* This is a service method block comment */
find : (name: text) ->
(service {up:() -> (); current:() -> (nat32)}); // This comment is ignored
};
type nested = record { nat; nat; record {nat;int;}; record { nat; 0x2a:nat; nat8; }; 42:nat; 40:nat; variant{ A; 0x2a; B; C }; };
type res = variant { Ok: record{int;nat}; Err: record{ error: text } }; // This comment is ignored
type res = variant {
/*
This is a block comment for variant Ok
*/
Ok: record{int;nat}; /* This comment is ignored */
/* This comment is a block comment for variant Err */
Err: record{ error: text }; /* This comment is ignored */
}; // This comment is ignored
type nested_res = variant { // This comment is ignored
// This is a variant comment
Ok : variant { Ok; Err }; // This comment is ignored
Expand All @@ -32,6 +46,17 @@ type nested_res = variant { // This comment is ignored

// This is another ignored comment

/*
This is an ignored block comment
*/

/* This is another ignored block comment */

/*
This is a block comment
that spans multiple lines
*/

// This is a service comment
// that spans multiple lines for services
service server : {
Expand All @@ -41,7 +66,15 @@ service server : {

// This is a method comment
g1 : (my_type, List, opt List, nested) -> (int, broker, nested_res) query; // This comment is ignored
/*
This is a block comment for a method
*/
h : (vec opt text, variant { A: nat; B: opt text }, opt List) -> (record { id: nat; 0x2a: record {} }); // This comment is ignored
/*
This is a block comment for a method
that spans multiple lines,
even with wrong indentation
*/
i : f;// This comment is ignored
// This is another method comment
// that spans multiple lines for methods
Expand Down
2 changes: 1 addition & 1 deletion rust/candid_parser/tests/assets/ok/actor.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ export type g = f;
export type h = ActorMethod<[[Principal, string]], [Principal, string]>;
export type o = [] | [o];
/**
* This is a service comment
* This is a service block comment
*/
export interface _SERVICE {
'f' : ActorMethod<[bigint], [Principal, string]>,
Expand Down
2 changes: 1 addition & 1 deletion rust/candid_parser/tests/assets/ok/actor.did
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@ type f = func (int8) -> (int8);
type g = f;
type h = func (f) -> (f);
type o = opt o;
// This is a service comment
// This is a service block comment
service : { f : (nat) -> (h); g : f; h : g; o : (o) -> (o) }
2 changes: 1 addition & 1 deletion rust/candid_parser/tests/assets/ok/actor.mo
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ module {
public type g = f;
public type h = shared f -> async f;
public type o = ?o;
/// This is a service comment
/// This is a service block comment
public type Self = actor {
f : shared Nat -> async h;
g : f;
Expand Down
4 changes: 2 additions & 2 deletions rust/candid_parser/tests/assets/ok/actor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ pub type G = F;
#[derive(CandidType, Deserialize)]
pub struct O(pub Option<Box<O>>);

/// This is a service comment
/// This is a service block comment
pub struct Service(pub Principal);
impl Service {
pub async fn f(&self, arg0: &candid::Nat) -> Result<(H,)> {
Expand All @@ -28,6 +28,6 @@ impl Service {
}
/// Canister ID: `aaaaa-aa`
pub const CANISTER_ID : Principal = Principal::from_slice(&[]);
/// This is a service comment
/// This is a service block comment
pub const service : Service = Service(CANISTER_ID);

4 changes: 4 additions & 0 deletions rust/candid_parser/tests/assets/ok/comment.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,9 @@ export type a = { 'a' : null } |
* This is a type comment
*/
export type b = [bigint, bigint];
/**
* gjkf
* jgfkg
*/
export type id = number;

2 changes: 2 additions & 0 deletions rust/candid_parser/tests/assets/ok/comment.did
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
type a = variant { a; b : b };
// This is a type comment
type b = record { int; nat };
// gjkf
// jgfkg
type id = nat8;

2 changes: 2 additions & 0 deletions rust/candid_parser/tests/assets/ok/comment.mo
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ module {
public type a = { #a; #b : b };
/// This is a type comment
public type b = (Int, Nat);
/// gjkf
/// jgfkg
public type id = Nat8;

}
2 changes: 2 additions & 0 deletions rust/candid_parser/tests/assets/ok/comment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ pub enum A { #[serde(rename="a")] A, #[serde(rename="b")] B(Box<B>) }
/// This is a type comment
#[derive(CandidType, Deserialize)]
pub struct B (pub candid::Int,pub candid::Nat,);
/// gjkf
/// jgfkg
pub type Id = u8;


35 changes: 32 additions & 3 deletions rust/candid_parser/tests/assets/ok/example.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,14 @@ import type { IDL } from '@dfinity/candid';

export type A = B;
export type B = [] | [A];
/**
* This is a type block comment
*/
export type List = [] | [
{
/**
* This is a field block comment
*/
'head' : bigint,
/**
* This is a field comment
Expand All @@ -22,7 +28,12 @@ export type b = [bigint, bigint];
/**
* This is another type comment
*/
export interface broker { 'find' : ActorMethod<[string], Principal> }
export interface broker {
/**
* This is a service method block comment
*/
'find' : ActorMethod<[string], Principal>,
}
export type f = ActorMethod<[List, [Principal, string]], [[] | [List], res]>;
export type list = [] | [node];
/**
Expand Down Expand Up @@ -57,8 +68,18 @@ export type nested_res = {
{ 'Err' : [bigint] }
};
export interface node { 'head' : bigint, 'tail' : list }
export type res = { 'Ok' : [bigint, bigint] } |
{ 'Err' : { 'error' : string } };
export type res = {
/**
* This is a block comment for variant Ok
*/
'Ok' : [bigint, bigint]
} |
{
/**
* This comment is a block comment for variant Err
*/
'Err' : { 'error' : string }
};
export interface s { 'f' : t, 'g' : ActorMethod<[list], [B, tree, stream]> }
export type stream = [] | [{ 'head' : bigint, 'next' : [Principal, string] }];
export type t = ActorMethod<[Principal], undefined>;
Expand All @@ -85,6 +106,9 @@ export interface _SERVICE {
[my_type, List, [] | [List], nested],
[bigint, Principal, nested_res]
>,
/**
* This is a block comment for a method
*/
'h' : ActorMethod<
[
Array<[] | [string]>,
Expand All @@ -94,6 +118,11 @@ export interface _SERVICE {
],
{ _42_ : {}, 'id' : bigint }
>,
/**
* This is a block comment for a method
* that spans multiple lines,
* even with wrong indentation
*/
'i' : f,
/**
* This is another method comment
Expand Down
Loading
Loading