erl_parse/cst/
ty.rs

1use erl_tokenize::tokens::{AtomToken, SymbolToken, VariableToken};
2use erl_tokenize::values::{Keyword, Symbol};
3use erl_tokenize::{LexicalToken, Position, PositionRange};
4use trackable::error::ErrorKindExt;
5
6use super::commons::parts::{BinaryOp, UnaryOp};
7use super::types;
8use super::Literal;
9use crate::traits::{Parse, TokenRead};
10use crate::{ErrorKind, Parser, Result};
11
12#[derive(Debug, Clone)]
13pub enum Type {
14    Literal(Literal),
15    Variable(VariableToken),
16    Annotated(Box<types::Annotated>),
17    Tuple(Box<types::Tuple>),
18    Map(Box<types::Map>),
19    Record(Box<types::Record>),
20    List(Box<types::List>),
21    Bits(Box<types::Bits>),
22    Parenthesized(Box<types::Parenthesized>),
23    TypeCall(Box<types::TypeCall>),
24    UnaryOpCall(Box<types::UnaryOpCall>),
25    BinaryOpCall(Box<types::BinaryOpCall>),
26    Fun(Box<types::Fun>),
27    Range(Box<types::Range>),
28    Union(Box<types::Union>),
29}
30impl Parse for Type {
31    fn parse_non_left_recor<T>(parser: &mut Parser<T>) -> Result<Self>
32    where
33        T: TokenRead,
34    {
35        let kind = track!(parser.peek(|parser| HeadKind::guess(parser)))?;
36        let ty = match kind {
37            HeadKind::Literal => Type::Literal(track!(parser.parse())?),
38            HeadKind::Variable => Type::Variable(track!(parser.parse())?),
39            HeadKind::Annotated => Type::Annotated(track!(parser.parse())?),
40            HeadKind::List => Type::List(track!(parser.parse())?),
41            HeadKind::Bits => Type::Bits(track!(parser.parse())?),
42            HeadKind::Tuple => Type::Tuple(track!(parser.parse())?),
43            HeadKind::Map => Type::Map(track!(parser.parse())?),
44            HeadKind::Record => Type::Record(track!(parser.parse())?),
45            HeadKind::TypeCall => Type::TypeCall(track!(parser.parse())?),
46            HeadKind::UnaryOpCall => Type::UnaryOpCall(track!(parser.parse())?),
47            HeadKind::Parenthesized => Type::Parenthesized(track!(parser.parse())?),
48            HeadKind::Fun => Type::Fun(track!(parser.parse())?),
49        };
50        Ok(ty)
51    }
52    fn parse<T>(parser: &mut Parser<T>) -> Result<Self>
53    where
54        T: TokenRead,
55    {
56        let head = track!(Type::parse_non_left_recor(parser))?;
57        let tail_kind = track!(parser.peek(|parser| TailKind::guess(parser)))?;
58        match tail_kind {
59            TailKind::BinaryOpCall => Ok(Type::BinaryOpCall(track!(parser.parse_tail(head))?)),
60            TailKind::Union => Ok(Type::Union(track!(parser.parse_tail(head))?)),
61            TailKind::Range => Ok(Type::Range(track!(parser.parse_tail(head))?)),
62            TailKind::None => Ok(head),
63        }
64    }
65}
66impl PositionRange for Type {
67    fn start_position(&self) -> Position {
68        match *self {
69            Type::Literal(ref x) => x.start_position(),
70            Type::Variable(ref x) => x.start_position(),
71            Type::Annotated(ref x) => x.start_position(),
72            Type::List(ref x) => x.start_position(),
73            Type::Bits(ref x) => x.start_position(),
74            Type::Tuple(ref x) => x.start_position(),
75            Type::Map(ref x) => x.start_position(),
76            Type::Record(ref x) => x.start_position(),
77            Type::Fun(ref x) => x.start_position(),
78            Type::Parenthesized(ref x) => x.start_position(),
79            Type::TypeCall(ref x) => x.start_position(),
80            Type::UnaryOpCall(ref x) => x.start_position(),
81            Type::BinaryOpCall(ref x) => x.start_position(),
82            Type::Range(ref x) => x.start_position(),
83            Type::Union(ref x) => x.start_position(),
84        }
85    }
86    fn end_position(&self) -> Position {
87        match *self {
88            Type::Literal(ref x) => x.end_position(),
89            Type::Variable(ref x) => x.end_position(),
90            Type::Annotated(ref x) => x.end_position(),
91            Type::List(ref x) => x.end_position(),
92            Type::Bits(ref x) => x.end_position(),
93            Type::Tuple(ref x) => x.end_position(),
94            Type::Map(ref x) => x.end_position(),
95            Type::Record(ref x) => x.end_position(),
96            Type::Fun(ref x) => x.end_position(),
97            Type::Parenthesized(ref x) => x.end_position(),
98            Type::TypeCall(ref x) => x.end_position(),
99            Type::UnaryOpCall(ref x) => x.end_position(),
100            Type::BinaryOpCall(ref x) => x.end_position(),
101            Type::Range(ref x) => x.end_position(),
102            Type::Union(ref x) => x.end_position(),
103        }
104    }
105}
106
107#[derive(Debug)]
108enum HeadKind {
109    Literal,
110    Variable,
111    Annotated,
112    Tuple,
113    Map,
114    Record,
115    List,
116    Bits,
117    Fun,
118    TypeCall,
119    UnaryOpCall,
120    Parenthesized,
121}
122impl HeadKind {
123    fn guess<T: TokenRead>(parser: &mut Parser<T>) -> Result<Self> {
124        Ok(match track!(parser.parse())? {
125            LexicalToken::Symbol(t) => match t.value() {
126                Symbol::OpenBrace => HeadKind::Tuple,
127                Symbol::DoubleLeftAngle => HeadKind::Bits,
128                Symbol::OpenParen => HeadKind::Parenthesized,
129                Symbol::OpenSquare => HeadKind::List,
130                Symbol::Sharp => {
131                    if parser.parse::<AtomToken>().is_ok() {
132                        HeadKind::Record
133                    } else {
134                        HeadKind::Map
135                    }
136                }
137                _ => track!(UnaryOp::from_token(t.into())
138                    .map(|_| HeadKind::UnaryOpCall)
139                    .map_err(|e| ErrorKind::UnexpectedToken(e).error()))?,
140            },
141            LexicalToken::Keyword(t) => {
142                if t.value() == Keyword::Fun {
143                    HeadKind::Fun
144                } else {
145                    track!(UnaryOp::from_token(t.into())
146                        .map(|_| HeadKind::UnaryOpCall)
147                        .map_err(|e| ErrorKind::UnexpectedToken(e).error()))?
148                }
149            }
150            LexicalToken::Variable(_) => {
151                let token = parser.parse::<SymbolToken>();
152                match token.ok().map(|t| t.value()) {
153                    Some(Symbol::DoubleColon) => HeadKind::Annotated,
154                    _ => HeadKind::Variable,
155                }
156            }
157            LexicalToken::Atom(_) => {
158                let token = parser.parse::<SymbolToken>();
159                match token.ok().map(|t| t.value()) {
160                    Some(Symbol::OpenParen) | Some(Symbol::Colon) => HeadKind::TypeCall,
161                    _ => HeadKind::Literal,
162                }
163            }
164            _ => HeadKind::Literal,
165        })
166    }
167}
168
169#[derive(Debug)]
170enum TailKind {
171    BinaryOpCall,
172    Union,
173    Range,
174    None,
175}
176impl TailKind {
177    fn guess<T: TokenRead>(parser: &mut Parser<T>) -> Result<Self> {
178        let is_eos = track!(parser.eos())?;
179        if is_eos {
180            return Ok(TailKind::None);
181        }
182        let token = track!(parser.parse::<LexicalToken>())?;
183        Ok(match token.as_symbol_token().map(SymbolToken::value) {
184            Some(Symbol::VerticalBar) => TailKind::Union,
185            Some(Symbol::DoubleDot) => TailKind::Range,
186            _ => {
187                if BinaryOp::from_token(token).is_ok() {
188                    TailKind::BinaryOpCall
189                } else {
190                    TailKind::None
191                }
192            }
193        })
194    }
195}