소개

본인는 텍스트 파싱같은거 제대로 배워본적이 없는데

무언가의 파서를 작성하고 나니까 코드가 엉망이었음

serde랑 syn비슷한 파서 라이브러리가 있으면 어떨까 싶었다

과정 Parsable

먼저 스트림으로부터 파싱을 하는 트레잇 Parsable을 먼저 만들었음

스트림을 읽고 자신을 리턴하거나(파싱 성공)

파싱 실패를 띄우고 이유를 붙일 수 있음(파싱 실패)

파싱 실패의 경우 어떤 위치에서 A나 B가 있을껄로 예상되었는데 다른게 있었다 같은식으로

토큰

“단순한 토큰”

토큰은 zero-sized인 struct로 구현됨 위에서 설명한 Parsable을 구현함

어떤 이유로 스페이스,탭, 엔터, 등도 토큰으로 취급

스트림의 현재 위치에서 자신의 값을 읽을 수 있으면 파싱 성공

없으면 파싱 실패임

token!(Dash, "-");

같은 식으로 구현을 추가할 수 있도록 할 예정

Option\<T\> impl<T, U: Parsable<T>> Parsable<T> for Option<U>

파싱에 실패하지 않음

T가 파싱에 성공할 경우 Some(T)실패할 경우 None을 리턴함

Vec<T> impl<T, U: Parsable<T>> Parsable<T> for Vec<U>

Option과 마찬가지로 파싱에 실패하지 않음

스트림을 읽으면서 T가 파싱 실패할때까지 파싱을 시도하고

파싱에 성공한 T들을 리턴함

struct

serde의 그것과 비슷

derive매크로로 struct에 Parsable을 구현할 수 있음

필드는 모두 Parsable이여야 함

필드의 순서대로 파싱을 시도할것임

모두 파싱을 성공하면 자신을 리턴

하나라도 실패하면 파싱 실패함

enum

위에 표기된 variant순서대로 성공할때까지 파싱을 시도함

모두 실패하면 파싱 실패함

그렇기 때문에 좀더 복잡한 문법을 위에 적어놔야 함

예를 들자면 1234.567 과 같은 텍스트가 있다고 치자

enum Value { Integer(Integer), Float(Float) }

과 같이 표기한다면 4까지만 읽고 Value::Integer를 리턴할 것이다

enum Value { Float(Float) Integer(Integer) }

과 같이 표기한다면 7까지 읽고 Value::Float를 리턴할 것이다



json파싱 예시

use autoparse_general::*; use autoparse_derive::*; #[derive(Clone, Debug, Writable, Parsable)] #[autoparse_for(char)] pub struct JsonKeyValue { pub key: MayNotSpaced<Literal>, pub colon: MaySpaced<token::Colon>, pub value: JsonValue } #[derive(Clone, Debug, Writable, Parsable)] #[autoparse_for(char)] pub struct JsonObject { pub inner: token::Braced<Punchuated<JsonKeyValue, token::Comma>> } #[derive(Clone, Debug, Writable, Parsable)] #[autoparse_for(char)] pub struct JsonArray { pub inner: token::Bracketed<Punchuated<JsonValue, token::Comma>> } #[derive(Clone, Debug, Writable, Parsable)] #[autoparse_for(char)] pub enum JsonValue { Object(JsonObject), Array(JsonArray), Str(Literal), Numeric(Signed) } use autoparse::*; pub fn main() { let json = std::fs::read_to_string("test.json").unwrap(); let collected: Vec<char> = json.chars().collect(); let mut stream = SimpleParseStream::new(&collected); println!("{:?}", JsonValue::try_parse(&mut stream)); }

생각없이 만들어서 코드 정리가 좀 필요할듯