Skip to content

Commit 4731839

Browse files
committed
feat: Accept multiple lines on incomplete repl input
Closes #830
1 parent 25b22f8 commit 4731839

File tree

8 files changed

+163
-59
lines changed

8 files changed

+163
-59
lines changed

Cargo.lock

Lines changed: 8 additions & 7 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

parser/src/grammar.lalrpop

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use crate::base::{
1212
};
1313

1414
use crate::{ReplLine, Variant, new_ident};
15-
use crate::token::{Token, StringLiteral};
15+
use crate::token::{Token, BorrowedToken, StringLiteral};
1616
use crate::ordered_float::NotNan;
1717

1818
use crate::{Error, ErrorEnv, FieldExpr, MutIdentEnv, TempVecs, TempVecStart, Slice};
@@ -31,11 +31,11 @@ extern {
3131
type Location = BytePos;
3232
type Error = Spanned<Error, BytePos>;
3333

34-
enum Token<'input> {
34+
enum BorrowedToken<'input> {
3535
"shebang line" => Token::ShebangLine(<&'input str>),
3636
"identifier" => Token::Identifier(<&'input str>),
3737
"operator" => Token::Operator(<&'input str>),
38-
"string literal" => Token::StringLiteral(<StringLiteral<'input>>),
38+
"string literal" => Token::StringLiteral(<StringLiteral<&'input str>>),
3939
"char literal" => Token::CharLiteral(<char>),
4040
"int literal" => Token::IntLiteral(<i64>),
4141
"byte literal" => Token::ByteLiteral(<u8>),
@@ -259,7 +259,7 @@ AtomicKind: ArcKind = {
259259
l.into(),
260260
r.into(),
261261
Error::UnexpectedToken(
262-
"identifier".to_string(),
262+
Token::Identifier(id.into()),
263263
["_", "Row", "Type"].iter().map(|s| s.to_string()).collect())),
264264
}),
265265
}

parser/src/layout.rs

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use crate::base::pos::{self, BytePos, Column, Line, Location, Span, Spanned};
22

3-
use crate::token::{self, SpannedToken, Token};
3+
use crate::token::{self, BorrowedToken, SpannedToken, Token};
44

55
quick_error! {
66
#[derive(Debug, Eq, PartialEq, Hash, Clone)]
@@ -136,7 +136,7 @@ where
136136
}
137137
}
138138

139-
fn continue_block(&mut self, context: Context, token: &Token) -> Result<bool> {
139+
fn continue_block(&mut self, context: Context, token: &BorrowedToken) -> Result<bool> {
140140
let in_rec = self.indent_levels.stack.len() >= 2
141141
&& self.indent_levels.stack[self.indent_levels.stack.len() - 2].context == Context::Rec;
142142

@@ -145,7 +145,11 @@ where
145145
|| (*token != Token::Rec && self.scan_continue_block(context, token)?)))
146146
}
147147

148-
fn scan_continue_block(&mut self, context: Context, first_token: &Token) -> Result<bool> {
148+
fn scan_continue_block(
149+
&mut self,
150+
context: Context,
151+
first_token: &BorrowedToken,
152+
) -> Result<bool> {
149153
let expected_token = match context {
150154
Context::Let => Token::Let,
151155
Context::Type => Token::Type,
@@ -218,7 +222,7 @@ where
218222
fn layout_token(
219223
&mut self,
220224
token: SpannedToken<'input>,
221-
layout_token: Token<'input>,
225+
layout_token: BorrowedToken<'input>,
222226
) -> SpannedToken<'input> {
223227
let span = token.span;
224228
self.unprocessed_tokens.push(token);
@@ -600,7 +604,7 @@ where
600604
}
601605
}
602606

603-
fn token_closes_context(token: &Token, context: Context) -> bool {
607+
fn token_closes_context(token: &BorrowedToken, context: Context) -> bool {
604608
match (token, context) {
605609
(&Token::Else, Context::If)
606610
| (&Token::RBrace, Context::Brace)
@@ -620,7 +624,7 @@ impl<'input, Tokens> Iterator for Layout<'input, Tokens>
620624
where
621625
Tokens: Iterator<Item = token::Result<SpannedToken<'input>>>,
622626
{
623-
type Item = Result<(BytePos, Token<'input>, BytePos)>;
627+
type Item = Result<(BytePos, BorrowedToken<'input>, BytePos)>;
624628

625629
fn next(&mut self) -> Option<Self::Item> {
626630
match self.layout_next_token() {

parser/src/lib.rs

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@ use itertools::Either;
2727

2828
use crate::base::{
2929
ast::{
30-
self, AstType, Do, Expr, IdentEnv, PatternField, RootExpr, SpannedExpr,
31-
SpannedPattern, TypedIdent, ValueBinding,
30+
self, AstType, Do, Expr, IdentEnv, PatternField, RootExpr, SpannedExpr, SpannedPattern,
31+
TypedIdent, ValueBinding,
3232
},
3333
error::{AsDiagnostic, Errors},
3434
fnv::FnvMap,
@@ -42,11 +42,12 @@ use crate::base::{
4242
use crate::{
4343
infix::{Fixity, OpMeta, OpTable, Reparser},
4444
layout::Layout,
45-
token::{Token, Tokenizer},
45+
token::{BorrowedToken, Tokenizer},
4646
};
4747

4848
pub use crate::{
4949
infix::Error as InfixError, layout::Error as LayoutError, token::Error as TokenizeError,
50+
token::Token,
5051
};
5152

5253
lalrpop_mod!(
@@ -68,7 +69,7 @@ fn new_ident<Id>(type_cache: &TypeCache<Id, ArcType<Id>>, name: Id) -> TypedIden
6869
}
6970

7071
type LalrpopError<'input> =
71-
lalrpop_util::ParseError<BytePos, Token<'input>, Spanned<Error, BytePos>>;
72+
lalrpop_util::ParseError<BytePos, BorrowedToken<'input>, Spanned<Error, BytePos>>;
7273

7374
/// Shrink hidden spans to fit the visible expressions and flatten singleton blocks.
7475
fn shrink_hidden_spans<Id>(mut expr: SpannedExpr<Id>) -> SpannedExpr<Id> {
@@ -156,13 +157,13 @@ quick_error! {
156157
InvalidToken {
157158
display("Invalid token")
158159
}
159-
UnexpectedToken(token: String, expected: Vec<String>) {
160+
UnexpectedToken(token: Token<String>, expected: Vec<String>) {
160161
display("Unexpected token: {}{}", token, Expected(&expected))
161162
}
162163
UnexpectedEof(expected: Vec<String>) {
163164
display("Unexpected end of file{}", Expected(&expected))
164165
}
165-
ExtraToken(token: String) {
166+
ExtraToken(token: Token<String>) {
166167
display("Extra token: {}", token)
167168
}
168169
Infix(err: InfixError) {
@@ -206,7 +207,7 @@ impl Error {
206207
pos::spanned2(
207208
lpos,
208209
rpos,
209-
Error::UnexpectedToken(token.to_string(), expected),
210+
Error::UnexpectedToken(token.map(|s| s.into()), expected),
210211
)
211212
}
212213
UnrecognizedEOF {
@@ -226,7 +227,7 @@ impl Error {
226227
}
227228
ExtraToken {
228229
token: (lpos, token, rpos),
229-
} => pos::spanned2(lpos, rpos, Error::ExtraToken(token.to_string())),
230+
} => pos::spanned2(lpos, rpos, Error::ExtraToken(token.map(|s| s.into()))),
230231
User { error } => error,
231232
}
232233
}

parser/src/token.rs

Lines changed: 81 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -16,17 +16,17 @@ use crate::{
1616
};
1717

1818
#[derive(Clone, Eq, PartialEq, Hash, Debug)]
19-
pub enum Token<'input> {
20-
ShebangLine(&'input str),
21-
Identifier(&'input str),
22-
Operator(&'input str),
19+
pub enum Token<S> {
20+
ShebangLine(S),
21+
Identifier(S),
22+
Operator(S),
2323

24-
StringLiteral(StringLiteral<'input>),
24+
StringLiteral(StringLiteral<S>),
2525
CharLiteral(char),
2626
IntLiteral(i64),
2727
ByteLiteral(u8),
2828
FloatLiteral(NotNan<f64>),
29-
DocComment(Comment<&'input str>),
29+
DocComment(Comment<S>),
3030

3131
Rec,
3232
Else,
@@ -68,7 +68,10 @@ pub enum Token<'input> {
6868
EOF, // Required for the layout algorithm
6969
}
7070

71-
impl<'input> fmt::Display for Token<'input> {
71+
impl<S> fmt::Display for Token<S>
72+
where
73+
S: fmt::Display,
74+
{
7275
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
7376
use self::Token::*;
7477

@@ -127,13 +130,76 @@ impl<'input> fmt::Display for Token<'input> {
127130
}
128131
}
129132

133+
impl<S> Token<S> {
134+
pub(crate) fn map<R>(self, f: impl FnOnce(S) -> R) -> Token<R> {
135+
use self::Token::*;
136+
match self {
137+
ShebangLine(s) => ShebangLine(f(s)),
138+
Identifier(s) => Identifier(f(s)),
139+
Operator(s) => Operator(f(s)),
140+
StringLiteral(s) => StringLiteral(match s {
141+
self::StringLiteral::Escaped(s) => self::StringLiteral::Escaped(f(s)),
142+
self::StringLiteral::Raw(s) => self::StringLiteral::Raw(f(s)),
143+
}),
144+
CharLiteral(x) => CharLiteral(x),
145+
IntLiteral(x) => IntLiteral(x),
146+
ByteLiteral(x) => ByteLiteral(x),
147+
FloatLiteral(x) => FloatLiteral(x),
148+
DocComment(Comment { typ, content }) => DocComment(Comment {
149+
typ,
150+
content: f(content),
151+
}),
152+
153+
Rec => Rec,
154+
Else => Else,
155+
Forall => Forall,
156+
If => If,
157+
In => In,
158+
Let => Let,
159+
Do => Do,
160+
Seq => Seq,
161+
Match => Match,
162+
Then => Then,
163+
Type => Type,
164+
With => With,
165+
166+
LBrace => LBrace,
167+
LBracket => LBracket,
168+
LParen => LParen,
169+
170+
RBrace => RBrace,
171+
RBracket => RBracket,
172+
RParen => RParen,
173+
174+
At => At,
175+
Colon => Colon,
176+
Comma => Comma,
177+
Dot => Dot,
178+
DotDot => DotDot,
179+
Equals => Equals,
180+
Lambda => Lambda,
181+
Pipe => Pipe,
182+
RArrow => RArrow,
183+
Question => Question,
184+
185+
OpenBlock => OpenBlock,
186+
CloseBlock => CloseBlock,
187+
Semi => Semi,
188+
189+
AttributeOpen => AttributeOpen,
190+
191+
EOF => EOF,
192+
}
193+
}
194+
}
195+
130196
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
131-
pub enum StringLiteral<'input> {
132-
Escaped(&'input str),
133-
Raw(&'input str),
197+
pub enum StringLiteral<S> {
198+
Escaped(S),
199+
Raw(S),
134200
}
135201

136-
impl StringLiteral<'_> {
202+
impl StringLiteral<&'_ str> {
137203
pub fn unescape(&self) -> String {
138204
match self {
139205
StringLiteral::Escaped(s) => unescape_string_literal(s),
@@ -164,7 +230,8 @@ fn unescape_string_literal(mut s: &str) -> String {
164230
string
165231
}
166232

167-
pub type SpannedToken<'input> = Spanned<Token<'input>, Location>;
233+
pub type BorrowedToken<'input> = Token<&'input str>;
234+
pub type SpannedToken<'input> = Spanned<Token<&'input str>, Location>;
168235

169236
pub type SpError = Spanned<Error, Location>;
170237
pub type Result<T, E = SpError> = std::result::Result<T, E>;
@@ -396,7 +463,7 @@ impl<'input> Tokenizer<'input> {
396463
// FIXME: whitespace alignment
397464
let doc = Token::DocComment(Comment {
398465
typ: CommentType::Block,
399-
content: &comment[3..].trim(),
466+
content: comment[3..].trim(),
400467
});
401468
return Ok(Some(pos::spanned2(start, end, doc)));
402469
} else {
@@ -786,7 +853,7 @@ mod test {
786853
}))
787854
}
788855

789-
fn test(input: &str, expected: Vec<(&str, Token)>) {
856+
fn test(input: &str, expected: Vec<(&str, BorrowedToken<'_>)>) {
790857
use crate::base::source::Source;
791858

792859
let mut tokenizer = tokenizer(input);

0 commit comments

Comments
 (0)