diff --git a/base/src/pos.rs b/base/src/pos.rs index f16ee994ee..a8628975d4 100644 --- a/base/src/pos.rs +++ b/base/src/pos.rs @@ -205,6 +205,16 @@ pub fn spanned(span: Span, value: T) -> Spanned { } } +pub fn spanned2(start: Location, end: Location, value: T) -> Spanned { + Spanned { + span: Span { + start: start, + end: end, + }, + value: value, + } +} + #[derive(Clone, Debug)] pub struct Located { pub location: Location, diff --git a/check/tests/completion.rs b/check/tests/completion.rs index 98c95701ba..4105956a9d 100644 --- a/check/tests/completion.rs +++ b/check/tests/completion.rs @@ -4,7 +4,6 @@ extern crate gluon_base as base; extern crate gluon_parser as parser; extern crate gluon_check as check; -use base::ast; use base::pos::{BytePos, CharPos, Location}; use base::types::{Type, TcType}; use check::completion; @@ -197,7 +196,7 @@ fn suggest_identifier_when_prefix() { let result = suggest(r#" let test = 1 let tes = "" -let aaa = "" +let aaa = test te "#, Location { diff --git a/check/tests/pass.rs b/check/tests/pass.rs index a48899e247..fcadaa3844 100644 --- a/check/tests/pass.rs +++ b/check/tests/pass.rs @@ -773,7 +773,7 @@ test 1 } _ => panic!(), }; - let test_id = match *bind.name { + let test_id = match bind.name.value { Pattern::Identifier(ref id) => id, _ => panic!(), }; diff --git a/parser/src/lib.rs b/parser/src/lib.rs index 56011b08e9..cc32fff85b 100644 --- a/parser/src/lib.rs +++ b/parser/src/lib.rs @@ -17,7 +17,7 @@ use std::rc::Rc; use base::ast; use base::ast::*; use base::error::Errors; -use base::pos::{self, Location, Span}; +use base::pos::{self, Location, Located, Span}; use base::types::{Type, Generic, Alias, Field, Kind, TypeVariable}; use base::symbol::{Name, Symbol, SymbolModule}; @@ -30,7 +30,25 @@ use combine_language::{Assoc, Fixity, expression_parser}; use lexer::{Lexer, Delimiter, Token, IdentType}; -pub type Error = ParseError>; +pub type Error = ParseError; + +// Dummy type for ParseError which has the correct associated types +#[derive(Clone)] +pub struct StreamType(()); +impl StreamOnce for StreamType { + type Item = Token; + type Range = Token; + type Position = Location; + + fn uncons(&mut self) -> Result, ::lexer::Error> { + unimplemented!() + } + + fn position(&self) -> Self::Position { + unimplemented!() + } +} + /// Parser passes the environment to each parser function type LanguageParser<'b, I: 'b, F: 'b, T> = EnvParser<&'b ParserEnv, I, T>; @@ -58,14 +76,14 @@ impl<'a, 's, 'l, Id> StreamOnce for Wrapper<'a, 's, 'l, Id> { type Item = Token; type Range = Token; - type Position = Location; + type Position = Span; fn uncons(&mut self) -> Result, ::lexer::Error> { self.stream.uncons() } fn position(&self) -> Self::Position { - self.stream.position().start + self.stream.position() } } @@ -107,7 +125,7 @@ fn as_trait(p: &mut P) -> &mut Parser ParserEnv - where I: Stream, Range = Token, Position = Location>, + where I: Stream, Range = Token, Position = Span>, F: IdentEnv, Id: AstId + Clone + PartialEq + fmt::Debug, I::Range: fmt::Debug @@ -387,9 +405,9 @@ impl<'s, I, Id, F> ParserEnv let arg_expr1 = self.parser(ParserEnv::::parse_arg); let arg_expr2 = self.parser(ParserEnv::::parse_arg); (arg_expr1, many(arg_expr2)) - .map(|(f, args): (SpannedExpr, Vec<_>)| { - if args.len() > 0 { - pos::spanned(f.span, Expr::Call(Box::new(f), args)) + .map(|(f, args): (SpannedExpr, Vec>)| { + if let Some(end) = args.last().map(|last| last.span.end) { + pos::spanned2(f.span.start, end, Expr::Call(Box::new(f), args)) } else { f } @@ -400,15 +418,8 @@ impl<'s, I, Id, F> ParserEnv /// Parses an expression which could be an argument to a function fn parse_arg(&self, input: I) -> ParseResult, I> { debug!("Expr start: {:?}", input.clone().uncons()); - let position = input.position(); - let loc = |expr| { - pos::spanned(Span { - start: position, - // ARGH - TODO - end: position, - }, - expr) - }; + let span = input.position(); + let loc = |expr| pos::spanned(span, expr); // To prevent stack overflows we push all binding groups (which are commonly deeply nested) // to a stack and construct the expressions afterwards @@ -456,20 +467,13 @@ impl<'s, I, Id, F> ParserEnv } fn rest_expr(&self, input: I) -> ParseResult, I> { - let position = input.position(); - let loc = |expr| { - pos::spanned(Span { - start: position, - // ARGH - TODO - end: position, - }, - expr) - }; + let span = input.position(); + let loc = |expr| pos::spanned(span, expr); choice::<[&mut Parser>; 12], - _>([&mut parser(|input| self.if_else(input)).map(&loc), - &mut self.parser(ParserEnv::::case_of).map(&loc), - &mut self.parser(ParserEnv::::lambda).map(&loc), + _>([&mut parser(|input| self.if_else(input)), + &mut self.parser(ParserEnv::::case_of), + &mut self.parser(ParserEnv::::lambda), &mut self.integer() .map(|i| loc(Expr::Literal(LiteralEnum::Integer(i)))), &mut self.byte() @@ -504,14 +508,18 @@ impl<'s, I, Id, F> ParserEnv .and(self.parser(Self::fields)) .map(|(expr, fields): (_, Vec<_>)| { debug!("Parsed expr {:?}", expr); - fields.into_iter().fold(expr, - |expr, field| loc(Expr::FieldAccess(Box::new(expr), field))) + fields.into_iter().fold(expr, |expr, field: Located<_>| { + pos::spanned2(span.start, + field.location, + Expr::FieldAccess(Box::new(expr), field.value)) + }) }) .parse_state(input) } - fn fields(&self, input: I) -> ParseResult, I> { + // The Location is the end of the field + fn fields(&self, input: I) -> ParseResult>, I> { let mut fields = Vec::new(); let mut input = Consumed::Empty(input); loop { @@ -519,9 +527,10 @@ impl<'s, I, Id, F> ParserEnv Ok((_, input)) => input, Err(_) => return Ok((fields, input)), }; + let end = input.clone().into_inner().position().end; input = match input.clone().combine(|input| self.ident().parse_lazy(input)) { Ok((field, input)) => { - fields.push(field); + fields.push(pos::located(end, field)); input } Err(err) => { @@ -531,7 +540,7 @@ impl<'s, I, Id, F> ParserEnv self.errors .borrow_mut() .error(static_error(&mut *make_ident, err.into_inner())); - fields.push(make_ident.from_str("")); + fields.push(pos::located(end, make_ident.from_str(""))); return Ok((fields, input)); } }; @@ -573,19 +582,22 @@ impl<'s, I, Id, F> ParserEnv .parse_state(input) } - fn lambda(&self, input: I) -> ParseResult, I> { + fn lambda(&self, input: I) -> ParseResult, I> { + let start = input.position().start; (token(Token::Lambda), many(self.ident()), token(Token::RightArrow), self.expr()) .map(|(_, args, _, expr)| { - Expr::Lambda(Lambda { - id: self.empty_id.clone(), - arguments: args, - body: Box::new(expr), - }) + pos::spanned2(start, + expr.span.end, + Expr::Lambda(Lambda { + id: self.empty_id.clone(), + arguments: args, + body: Box::new(expr), + })) }) .parse_state(input) } - fn case_of(&self, input: I) -> ParseResult, I> { + fn case_of(&self, input: I) -> ParseResult, I> { let alt = (token(Token::Pipe), self.pattern(), token(Token::RightArrow), self.expr()) .map(|(_, p, _, e)| { Alternative { @@ -593,8 +605,13 @@ impl<'s, I, Id, F> ParserEnv expression: e, } }); - (token(Token::Match), self.expr(), token(Token::With), many1(alt)) - .map(|(_, e, _, alts)| Expr::Match(Box::new(e), alts)) + let start = input.position().start; + (token(Token::Match), self.expr(), token(Token::With), many1::, _>(alt)) + .map(|(_, e, _, alts)| { + pos::spanned2(start, + alts.last().expect("No alternatives").expression.span.end, + Expr::Match(Box::new(e), alts)) + }) .parse_state(input) } @@ -604,12 +621,7 @@ impl<'s, I, Id, F> ParserEnv fn parse_pattern(&self, input: I) -> ParseResult, I> { self.record_parser(self.ident_u(), self.ident_u(), |record| { - let position = input.position(); - let span = Span { - start: position, - // ARGH - TODO - end: position, - }; + let span = input.position(); self.parser(ParserEnv::::parse_ident2) .then(|(id, typ)| { @@ -648,14 +660,21 @@ impl<'s, I, Id, F> ParserEnv }) } - fn if_else(&self, input: I) -> ParseResult, I> { + fn if_else(&self, input: I) -> ParseResult, I> { + let start = input.position().start; (token(Token::If), self.expr(), token(Token::Then), self.expr(), token(Token::Else), self.expr()) - .map(|(_, b, _, t, _, f)| Expr::IfElse(Box::new(b), Box::new(t), Some(Box::new(f)))) + .map(|(_, b, _, t, _, f)| { + pos::spanned(Span { + start: start, + end: f.span.end, + }, + Expr::IfElse(Box::new(b), Box::new(t), Some(Box::new(f)))) + }) .parse_state(input) } @@ -816,14 +835,14 @@ pub fn parse_expr<'a, 's, Id> fn static_error(make_ident: &mut IdentEnv, err: ParseError) -> Error where Id: Clone + fmt::Debug + PartialEq, - I: Stream, Range = Token, Position = Location> + I: Stream, Range = Token, Position = Span> { let errors = err.errors .into_iter() .map(|t| static_error_(make_ident, t)) .collect(); ParseError { - position: err.position, + position: err.position.start, errors: errors, } } diff --git a/parser/tests/basic.rs b/parser/tests/basic.rs index b6e6e29352..caabe4e16a 100644 --- a/parser/tests/basic.rs +++ b/parser/tests/basic.rs @@ -165,7 +165,9 @@ fn parse(input: &str) -> Result, (Option } fn parse_new(input: &str) -> SpannedExpr { - parse(input).unwrap_or_else(|(_, err)| panic!("{:?}", err)) + // Replace windows line endings so that byte positins match up on multiline expressions + let input = input.replace("\r\n", "\n"); + parse(&input).unwrap_or_else(|(_, err)| panic!("{:?}", err)) } #[test] @@ -415,7 +417,7 @@ fn span_identifier() { assert_eq!(e.span, Span { start: loc(1, 1, 0), - end: loc(1, 5, 0), + end: loc(1, 5, 4), }); } @@ -428,7 +430,21 @@ fn span_integer() { assert_eq!(e.span, Span { start: loc(1, 1, 0), - end: loc(1, 5, 0), + end: loc(1, 5, 4), + }); +} + +// FIXME The span of string literals includes the spaces after them +#[test] +#[ignore] +fn span_string_literal() { + let _ = ::env_logger::init(); + + let e = parse_new(r#" "test" "#); + assert_eq!(e.span, + Span { + start: loc(1, 2, 1), + end: loc(1, 8, 7), }); } @@ -436,11 +452,11 @@ fn span_integer() { fn span_call() { let _ = ::env_logger::init(); - let e = parse_new(r#" f 123 "asd" "#); + let e = parse_new(r#" f 123 "asd""#); assert_eq!(e.span, Span { start: loc(1, 2, 1), - end: loc(1, 13, 7), // ??? + end: loc(1, 13, 12), }); } @@ -456,7 +472,7 @@ match False with assert_eq!(e.span, Span { start: loc(2, 1, 1), - end: loc(4, 18, 53), + end: loc(5, 1, 56), }); } @@ -473,7 +489,7 @@ else assert_eq!(e.span, Span { start: loc(2, 1, 1), - end: loc(5, 11, 29), + end: loc(6, 1, 36), }); } @@ -485,10 +501,31 @@ fn span_byte() { assert_eq!(e.span, Span { start: loc(1, 1, 0), - end: loc(1, 5, 0), + end: loc(1, 5, 4), }); } +#[test] +fn span_field_access() { + let _ = ::env_logger::init(); + let expr = parse_new("record.x"); + assert_eq!(expr.span, + Span { + start: loc(1, 1, 0), + end: loc(1, 9, 8), + }); + match expr.value { + Expr::FieldAccess(ref e, _) => { + assert_eq!(e.span, + Span { + start: loc(1, 1, 0), + end: loc(1, 7, 6), + }); + } + _ => panic!(), + } +} + #[test] fn comment_on_let() { let _ = ::env_logger::init();