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}