Skip to content

Commit bccac66

Browse files
committed
get ready for release 2.0.0b1 of python extension
1 parent c50d94f commit bccac66

File tree

10 files changed

+123
-79
lines changed

10 files changed

+123
-79
lines changed

.circleci/config.yml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,9 +49,10 @@ jobs:
4949
PYPROJ_VER=$(rg '^version = "(.+)"$' -o -r '$1' ${PYTHON_MODULE_DIR}/pyproject.toml)
5050
5151
[[ $CORE_CARGOTOML_VER == $LATEST_CHANGELOG_VER ]] || fail "Core Cargo.toml version (${CORE_CARGOTOML_VER}) doesn't match latest version in CHANGELOG (${CORE_LATEST_CHANGELOG_VER})"
52-
[[ $MODULE_CARGOTOML_VER == $PYPROJ_VER ]] || fail "Python Module Cargo.toml version (${MODULE_CARGOTOML_VER}) doesn't match pyproject.toml version (${PYPROJ_VER})"
5352
[[ $CORE_CARGOTOML_VER == $MODULE_CARGOTOML_VER ]] || fail "Core Cargo.toml version (${CORE_CARGOTOML_VER}) doesn't match module Cargo.toml version (${MODULE_CARGOTOML_VER})"
5453
54+
# [[ $MODULE_CARGOTOML_VER == $PYPROJ_VER ]] || fail "Python Module Cargo.toml version (${MODULE_CARGOTOML_VER}) doesn't match pyproject.toml version (${PYPROJ_VER})"
55+
5556
exit $status
5657
- run:
5758
name: Check code formatting
@@ -172,7 +173,7 @@ jobs:
172173
at: .
173174
- run:
174175
name: Install dependencies
175-
command: choco install wget
176+
command: choco install wget -y
176177
shell: bash.exe
177178
- run:
178179
name: Install wheel

src/diagnostics.rs

Lines changed: 3 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,6 @@ impl Ast {
3838
}
3939
}
4040

41-
const WARNING: DiagnosticSeverity = DiagnosticSeverity::WARNING;
42-
const ERROR: DiagnosticSeverity = DiagnosticSeverity::ERROR;
43-
4441
enum DiagSpan<'a> {
4542
#[allow(unused)]
4643
EntireDoc,
@@ -82,29 +79,21 @@ impl CvlElement {
8279
if !self.ast.defines_param(param) {
8380
//A @param is provided for a non-existent parameter
8481
let message = format!("no such parameter: {param}");
85-
add(message, DiagSpan::SingleTag(tag), ERROR);
82+
add(message, DiagSpan::SingleTag(tag), DiagnosticSeverity::ERROR);
8683
} else if self.doc[..i]
8784
.iter()
8885
.any(|tag| tag.param_name() == Some(param))
8986
{
9087
//Each parameter must be documented at most once
9188
let message = "parameter is already documented".to_string();
92-
add(message, DiagSpan::SingleTag(tag), ERROR);
89+
add(message, DiagSpan::SingleTag(tag), DiagnosticSeverity::ERROR);
9390
}
9491
}
9592

9693
for tag in &self.doc {
9794
if !self.ast.supports(&tag.kind) {
9895
let message = format!("this tag is unsupported for {} blocks", self.ast);
99-
add(message, DiagSpan::SingleTag(tag), ERROR);
100-
}
101-
}
102-
103-
for tag in &self.doc {
104-
if let TagKind::Unexpected(unexpected_tag) = &tag.kind {
105-
//Unrecognized tags appear anywhere
106-
let message = format!("@{unexpected_tag} is unrecognized");
107-
add(message, DiagSpan::SingleTag(tag), WARNING);
96+
add(message, DiagSpan::SingleTag(tag), DiagnosticSeverity::ERROR);
10897
}
10998
}
11099

src/lib.rs

Lines changed: 20 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ pub mod diagnostics;
22
pub mod parse;
33
pub mod util;
44

5+
use color_eyre::eyre::bail;
56
use serde::Serialize;
67
use std::fmt::{Debug, Display};
78
use std::sync::Arc;
@@ -22,8 +23,8 @@ impl Debug for CvlElement {
2223
f.debug_struct("CvlElement")
2324
.field("doc", &self.doc)
2425
.field("ast", &self.ast)
25-
.field("element_span", &self.element_span)
26-
.field("doc_span", &self.doc_span)
26+
// .field("element_span", &self.element_span)
27+
// .field("doc_span", &self.doc_span)
2728
.finish()
2829
}
2930
}
@@ -206,69 +207,40 @@ pub enum TagKind {
206207
Param,
207208
Return,
208209
Formula,
209-
Unexpected(String),
210210
}
211211

212-
impl Display for TagKind {
213-
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
214-
let s = match self {
212+
impl TagKind {
213+
pub(crate) fn as_str(&self) -> &str {
214+
match self {
215215
TagKind::Title => "title",
216216
TagKind::Notice => "notice",
217217
TagKind::Dev => "dev",
218218
TagKind::Param => "param",
219219
TagKind::Return => "return",
220220
TagKind::Formula => "formula",
221-
TagKind::Unexpected(s) => s.as_str(),
222-
};
223-
write!(f, "{s}")
221+
}
224222
}
225-
}
226223

227-
impl TagKind {
228224
pub(crate) fn len(&self) -> usize {
229-
let len_without_ampersat = match self {
230-
TagKind::Dev => 3,
231-
TagKind::Title | TagKind::Param => 5,
232-
TagKind::Notice | TagKind::Return => 6,
233-
TagKind::Formula => 7,
234-
TagKind::Unexpected(s) => s.len(),
235-
};
236-
225+
let len_without_ampersat = self.as_str().len();
237226
len_without_ampersat + 1
238227
}
239228
}
240229

241-
impl From<&str> for TagKind {
242-
fn from(mut s: &str) -> Self {
243-
if let Some(trimmed) = s.strip_prefix('@') {
244-
s = trimmed;
245-
}
246-
match s {
247-
"title" => TagKind::Title,
248-
"notice" => TagKind::Notice,
249-
"dev" => TagKind::Dev,
250-
"param" => TagKind::Param,
251-
"return" => TagKind::Return,
252-
"formula" => TagKind::Formula,
253-
_ => TagKind::Unexpected(s.to_string()),
254-
}
255-
}
256-
}
230+
impl TryFrom<&str> for TagKind {
231+
type Error = color_eyre::Report;
257232

258-
impl From<String> for TagKind {
259-
fn from(mut s: String) -> Self {
260-
if s.starts_with('@') {
261-
s.remove(0);
262-
}
233+
fn try_from(s: &str) -> Result<Self, Self::Error> {
234+
let s = s.strip_prefix('@').unwrap_or(s);
263235

264-
match s.as_str() {
265-
"title" => TagKind::Title,
266-
"notice" => TagKind::Notice,
267-
"dev" => TagKind::Dev,
268-
"param" => TagKind::Param,
269-
"return" => TagKind::Return,
270-
"formula" => TagKind::Formula,
271-
_ => TagKind::Unexpected(s),
236+
match s {
237+
"title" => Ok(TagKind::Title),
238+
"notice" => Ok(TagKind::Notice),
239+
"dev" => Ok(TagKind::Dev),
240+
"param" => Ok(TagKind::Param),
241+
"return" => Ok(TagKind::Return),
242+
"formula" => Ok(TagKind::Formula),
243+
_ => bail!("unrecognized tag: {s}"),
272244
}
273245
}
274246
}

src/parse/builder.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,10 @@ impl DocumentationTag {
4040
tags.push(builder.build_current());
4141
}
4242

43-
line.content = &line.content[new_tag.len() + 1..];
43+
if let Some(after_tag) = line.content.get(new_tag.len() + 1..) {
44+
line.content = after_tag;
45+
}
46+
4447
builder.kind = new_tag;
4548

4649
builder.span.start = line_span.start;
@@ -151,8 +154,7 @@ impl<'src> Builder<'src> {
151154
.find(|c: char| c.is_ascii_whitespace())
152155
.unwrap_or(content.len());
153156

154-
let tag = content[..tag_end].into();
155-
Some(tag)
157+
content[..tag_end].try_into().ok()
156158
} else {
157159
None
158160
}

src/parse/tests.rs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
mod cvl2;
22

3-
use std::iter::Iterator;
4-
53
use super::builder::Builder;
64
use super::Token;
75
use crate::CvlElement;
@@ -11,6 +9,7 @@ use color_eyre::eyre::{bail, Context};
119
use color_eyre::Report;
1210
use indoc::indoc;
1311
use itertools::Itertools;
12+
use std::iter::Iterator;
1413

1514
fn parse_exactly_one(src: &str) -> Result<CvlElement, Report> {
1615
let mut parsed = Builder::new(src).build().wrap_err("parsing failed")?;
@@ -101,7 +100,6 @@ fn doc_tag_kinds() {
101100
/// world world world
102101
/// @title A simulator for trees
103102
/// and for everything green
104-
/// @author Larry A. Gardner
105103
/// @notice You can use this contract for only the most basic simulation
106104
/// @dev All function calls are currently implemented without side effects
107105
rule trees { }
@@ -113,7 +111,6 @@ fn doc_tag_kinds() {
113111
let expected = [
114112
TagKind::Notice,
115113
TagKind::Title,
116-
TagKind::Unexpected(String::from("author")),
117114
TagKind::Notice,
118115
TagKind::Dev,
119116
];

src/parse/tests/cvl2.rs

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -500,7 +500,7 @@ fn invariant_span_is_correct3() {
500500
"#};
501501

502502
let parsed = Builder::new(src).build().unwrap();
503-
// dbg!(parsed);
503+
504504
let [invariant, freeform, rule] = parsed.as_slice() else {
505505
let len = parsed.len();
506506
panic!("expected exactly 3 elements but got {len}")
@@ -513,3 +513,36 @@ fn invariant_span_is_correct3() {
513513
};
514514
let Ast::Rule { .. } = rule.ast else { panic!() };
515515
}
516+
517+
/// as of version 2.0, we no longer parse unexpected tags.
518+
/// any substrings of the form `@foo` where `foo` is not one of the tags
519+
/// defined in [crate::TagKind], will concatenate to the description of the previous tag.
520+
#[test]
521+
fn unrecognized_tags() {
522+
let src = indoc! {"
523+
/// @illegal this tag does not exist
524+
/// @dev this tag does exist
525+
/// @another_illegal this tag does not exist
526+
/// @still_illegal whitespace should be trimmed
527+
/// @formula hello@withrevert(world)
528+
function foo(int bar) { }
529+
"};
530+
531+
let parsed = Builder::new(src)
532+
.build()
533+
.expect("illegal tags should still parse");
534+
let parsed = parsed.into_iter().exactly_one().unwrap();
535+
536+
let [tag1, tag2, tag3] = parsed.doc.as_slice() else {
537+
panic!("should parse to exactly 3 tags")
538+
};
539+
540+
assert_matches!(tag1.kind, TagKind::Notice);
541+
assert_eq!(tag1.description, "@illegal this tag does not exist");
542+
543+
assert_matches!(tag2.kind, TagKind::Dev);
544+
assert_eq!(tag2.description, "this tag does exist\n@another_illegal this tag does not exist\n@still_illegal whitespace should be trimmed");
545+
546+
assert_matches!(tag3.kind, TagKind::Formula);
547+
assert_eq!(tag3.description, "hello@withrevert(world)"); // @withrevert should not parse to a new tag
548+
}

src/python_wrapper/cvldoc_parser.pyi

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,14 @@ class AstKind(Enum):
2626
HookCreate = 15
2727
HookOpcode = 16
2828

29+
class TagKind(Enum):
30+
Title = 0
31+
Notice = 1
32+
Dev = 2
33+
Param = 3
34+
Return = 4
35+
Formula = 5
36+
2937
class Span:
3038
start: int
3139
end: int

src/python_wrapper/pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ build-backend = "maturin"
44

55
[project]
66
name = "cvldoc_parser"
7-
version = "2.0.0"
7+
version = "2.0.0b1"
88
requires-python = ">=3.7"
99
classifiers = [
1010
"Programming Language :: Rust",

src/python_wrapper/src/lib.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use pyo3::prelude::*;
66
use std::fs::read_to_string;
77
use std::io::ErrorKind;
88
use std::path::{Path, PathBuf};
9-
use wrapper_structs::{AstKindPy, AstPy, CvlElementPy, DocumentationTagPy, SpanPy};
9+
use wrapper_structs::{AstKindPy, AstPy, CvlElementPy, DocumentationTagPy, SpanPy, TagKindPy};
1010

1111
fn file_contents(path: &Path) -> PyResult<String> {
1212
read_to_string(path).map_err(|e| handle_io_error(path, e))
@@ -54,6 +54,7 @@ fn cvldoc_parser(_py: Python, module: &PyModule) -> PyResult<()> {
5454
module.add_class::<CvlElementPy>()?;
5555
module.add_class::<AstPy>()?;
5656
module.add_class::<AstKindPy>()?;
57+
module.add_class::<TagKindPy>()?;
5758
module.add_class::<SpanPy>()?;
5859
module.add_class::<DocumentationTagPy>()?;
5960

0 commit comments

Comments
 (0)