mod validation;
mod syntax_node;
mod ptr;
+mod syntax_error;
+mod syntax_text;
pub use rowan::{SmolStr, TextRange, TextUnit};
pub use crate::{
ast::AstNode,
syntax_kinds::SyntaxKind,
- syntax_node::{Direction, SyntaxError, SyntaxNode, WalkEvent, Location, TreeArc},
+ syntax_error::{SyntaxError, SyntaxErrorKind, Location},
+ syntax_text::SyntaxText,
+ syntax_node::{Direction, SyntaxNode, WalkEvent, TreeArc},
ptr::{SyntaxNodePtr, AstPtr},
parsing::{tokenize, Token},
};
mod grammar;
use crate::{
+ SyntaxError,
parsing::builder::GreenBuilder,
- syntax_node::{GreenNode, SyntaxError},
+ syntax_node::GreenNode,
};
pub use self::lexer::{tokenize, Token};
use crate::{
parsing::parser_impl::Sink,
- syntax_node::{GreenNode, RaTypes, SyntaxError},
- SmolStr, SyntaxKind,
+ syntax_node::{GreenNode, RaTypes},
+ SmolStr, SyntaxKind, SyntaxError,
};
+
use rowan::GreenNodeBuilder;
pub(crate) struct GreenBuilder {
use crate::{
SmolStr,
- syntax_node::syntax_error::{ParseError, SyntaxError},
+ syntax_error::{ParseError, SyntaxError},
parsing::{
- lexer::Token,
- parser_api::Parser,
- parser_impl::{
- event::{Event, EventProcessor},
- input::{InputPosition, ParserInput},
+ lexer::Token,
+ parser_api::Parser,
+ parser_impl::{
+ event::{Event, EventProcessor},
+ input::{InputPosition, ParserInput},
+ },
},
-}};
+};
use crate::SyntaxKind::{self, EOF, TOMBSTONE};
SmolStr,
SyntaxKind::{self, *},
TextRange, TextUnit,
- syntax_node::syntax_error::{
+ syntax_error::{
ParseError,
SyntaxError,
SyntaxErrorKind,
use crate::{
SyntaxKind::*, TextRange, TextUnit,
algo,
- syntax_node::{GreenNode, SyntaxError, SyntaxNode},
+ syntax_node::{GreenNode, SyntaxNode},
+ syntax_error::SyntaxError,
parsing::{
grammar,
parser_impl,
--- /dev/null
+use std::fmt;
+
+use crate::{TextRange, TextUnit};
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct SyntaxError {
+ kind: SyntaxErrorKind,
+ location: Location,
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub enum Location {
+ Offset(TextUnit),
+ Range(TextRange),
+}
+
+impl Into<Location> for TextUnit {
+ fn into(self) -> Location {
+ Location::Offset(self)
+ }
+}
+
+impl Into<Location> for TextRange {
+ fn into(self) -> Location {
+ Location::Range(self)
+ }
+}
+
+impl SyntaxError {
+ pub fn new<L: Into<Location>>(kind: SyntaxErrorKind, loc: L) -> SyntaxError {
+ SyntaxError { kind, location: loc.into() }
+ }
+
+ pub fn kind(&self) -> SyntaxErrorKind {
+ self.kind.clone()
+ }
+
+ pub fn location(&self) -> Location {
+ self.location.clone()
+ }
+
+ pub fn offset(&self) -> TextUnit {
+ match self.location {
+ Location::Offset(offset) => offset,
+ Location::Range(range) => range.start(),
+ }
+ }
+
+ pub fn add_offset(mut self, plus_offset: TextUnit) -> SyntaxError {
+ self.location = match self.location {
+ Location::Range(range) => Location::Range(range + plus_offset),
+ Location::Offset(offset) => Location::Offset(offset + plus_offset),
+ };
+
+ self
+ }
+}
+
+impl fmt::Display for SyntaxError {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ self.kind.fmt(f)
+ }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub enum SyntaxErrorKind {
+ ParseError(ParseError),
+ UnescapedCodepoint,
+ EmptyChar,
+ UnclosedChar,
+ OverlongChar,
+ EmptyByte,
+ UnclosedByte,
+ OverlongByte,
+ ByteOutOfRange,
+ UnescapedByte,
+ EmptyByteEscape,
+ InvalidByteEscape,
+ TooShortByteCodeEscape,
+ MalformedByteCodeEscape,
+ UnicodeEscapeForbidden,
+ EmptyAsciiEscape,
+ InvalidAsciiEscape,
+ TooShortAsciiCodeEscape,
+ AsciiCodeEscapeOutOfRange,
+ MalformedAsciiCodeEscape,
+ UnclosedUnicodeEscape,
+ MalformedUnicodeEscape,
+ EmptyUnicodeEcape,
+ OverlongUnicodeEscape,
+ UnicodeEscapeOutOfRange,
+ UnclosedString,
+ InvalidSuffix,
+ InvalidBlockAttr,
+ InvalidMatchInnerAttr,
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct ParseError(pub String);
+
+impl fmt::Display for SyntaxErrorKind {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ use self::SyntaxErrorKind::*;
+ match self {
+ UnescapedCodepoint => write!(f, "This codepoint should always be escaped"),
+ EmptyAsciiEscape => write!(f, "Empty escape sequence"),
+ InvalidAsciiEscape => write!(f, "Invalid escape sequence"),
+ EmptyChar => write!(f, "Empty char literal"),
+ UnclosedChar => write!(f, "Unclosed char literal"),
+ OverlongChar => write!(f, "Char literal should be one character long"),
+ EmptyByte => write!(f, "Empty byte literal"),
+ UnclosedByte => write!(f, "Unclosed byte literal"),
+ OverlongByte => write!(f, "Byte literal should be one character long"),
+ ByteOutOfRange => write!(f, "Byte should be a valid ASCII character"),
+ UnescapedByte => write!(f, "This byte should always be escaped"),
+ EmptyByteEscape => write!(f, "Empty escape sequence"),
+ InvalidByteEscape => write!(f, "Invalid escape sequence"),
+ TooShortByteCodeEscape => write!(f, "Escape sequence should have two digits"),
+ MalformedByteCodeEscape => write!(f, "Escape sequence should be a hexadecimal number"),
+ UnicodeEscapeForbidden => {
+ write!(f, "Unicode escapes are not allowed in byte literals or byte strings")
+ }
+ TooShortAsciiCodeEscape => write!(f, "Escape sequence should have two digits"),
+ AsciiCodeEscapeOutOfRange => {
+ write!(f, "Escape sequence should be between \\x00 and \\x7F")
+ }
+ MalformedAsciiCodeEscape => write!(f, "Escape sequence should be a hexadecimal number"),
+ UnclosedUnicodeEscape => write!(f, "Missing `}}`"),
+ MalformedUnicodeEscape => write!(f, "Malformed unicode escape sequence"),
+ EmptyUnicodeEcape => write!(f, "Empty unicode escape sequence"),
+ OverlongUnicodeEscape => {
+ write!(f, "Unicode escape sequence should have at most 6 digits")
+ }
+ UnicodeEscapeOutOfRange => write!(f, "Unicode escape code should be at most 0x10FFFF"),
+ UnclosedString => write!(f, "Unclosed string literal"),
+ InvalidSuffix => write!(f, "Invalid literal suffix"),
+ InvalidBlockAttr => {
+ write!(f, "A block in this position cannot accept inner attributes")
+ }
+ InvalidMatchInnerAttr => {
+ write!(f, "Inner attributes are only allowed directly after the opening brace of the match expression")
+ }
+ ParseError(msg) => write!(f, "{}", msg.0),
+ }
+ }
+}
-pub mod syntax_error;
-mod syntax_text;
-
use std::{fmt, borrow::Borrow};
-use self::syntax_text::SyntaxText;
-use crate::{SmolStr, SyntaxKind, TextRange};
use rowan::{Types, TransparentNewType};
-pub use self::syntax_error::{SyntaxError, SyntaxErrorKind, Location};
+use crate::{
+ SmolStr, SyntaxKind, TextRange, SyntaxText,
+ syntax_error::SyntaxError,
+};
+
pub use rowan::WalkEvent;
#[derive(Debug, Clone, Copy)]
+++ /dev/null
-use std::fmt;
-
-use crate::{TextRange, TextUnit};
-
-#[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct SyntaxError {
- kind: SyntaxErrorKind,
- location: Location,
-}
-
-#[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub enum Location {
- Offset(TextUnit),
- Range(TextRange),
-}
-
-impl Into<Location> for TextUnit {
- fn into(self) -> Location {
- Location::Offset(self)
- }
-}
-
-impl Into<Location> for TextRange {
- fn into(self) -> Location {
- Location::Range(self)
- }
-}
-
-impl SyntaxError {
- pub fn new<L: Into<Location>>(kind: SyntaxErrorKind, loc: L) -> SyntaxError {
- SyntaxError { kind, location: loc.into() }
- }
-
- pub fn kind(&self) -> SyntaxErrorKind {
- self.kind.clone()
- }
-
- pub fn location(&self) -> Location {
- self.location.clone()
- }
-
- pub fn offset(&self) -> TextUnit {
- match self.location {
- Location::Offset(offset) => offset,
- Location::Range(range) => range.start(),
- }
- }
-
- pub fn add_offset(mut self, plus_offset: TextUnit) -> SyntaxError {
- self.location = match self.location {
- Location::Range(range) => Location::Range(range + plus_offset),
- Location::Offset(offset) => Location::Offset(offset + plus_offset),
- };
-
- self
- }
-}
-
-impl fmt::Display for SyntaxError {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- self.kind.fmt(f)
- }
-}
-
-#[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub enum SyntaxErrorKind {
- ParseError(ParseError),
- UnescapedCodepoint,
- EmptyChar,
- UnclosedChar,
- OverlongChar,
- EmptyByte,
- UnclosedByte,
- OverlongByte,
- ByteOutOfRange,
- UnescapedByte,
- EmptyByteEscape,
- InvalidByteEscape,
- TooShortByteCodeEscape,
- MalformedByteCodeEscape,
- UnicodeEscapeForbidden,
- EmptyAsciiEscape,
- InvalidAsciiEscape,
- TooShortAsciiCodeEscape,
- AsciiCodeEscapeOutOfRange,
- MalformedAsciiCodeEscape,
- UnclosedUnicodeEscape,
- MalformedUnicodeEscape,
- EmptyUnicodeEcape,
- OverlongUnicodeEscape,
- UnicodeEscapeOutOfRange,
- UnclosedString,
- InvalidSuffix,
- InvalidBlockAttr,
- InvalidMatchInnerAttr,
-}
-
-#[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct ParseError(pub String);
-
-impl fmt::Display for SyntaxErrorKind {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- use self::SyntaxErrorKind::*;
- match self {
- UnescapedCodepoint => write!(f, "This codepoint should always be escaped"),
- EmptyAsciiEscape => write!(f, "Empty escape sequence"),
- InvalidAsciiEscape => write!(f, "Invalid escape sequence"),
- EmptyChar => write!(f, "Empty char literal"),
- UnclosedChar => write!(f, "Unclosed char literal"),
- OverlongChar => write!(f, "Char literal should be one character long"),
- EmptyByte => write!(f, "Empty byte literal"),
- UnclosedByte => write!(f, "Unclosed byte literal"),
- OverlongByte => write!(f, "Byte literal should be one character long"),
- ByteOutOfRange => write!(f, "Byte should be a valid ASCII character"),
- UnescapedByte => write!(f, "This byte should always be escaped"),
- EmptyByteEscape => write!(f, "Empty escape sequence"),
- InvalidByteEscape => write!(f, "Invalid escape sequence"),
- TooShortByteCodeEscape => write!(f, "Escape sequence should have two digits"),
- MalformedByteCodeEscape => write!(f, "Escape sequence should be a hexadecimal number"),
- UnicodeEscapeForbidden => {
- write!(f, "Unicode escapes are not allowed in byte literals or byte strings")
- }
- TooShortAsciiCodeEscape => write!(f, "Escape sequence should have two digits"),
- AsciiCodeEscapeOutOfRange => {
- write!(f, "Escape sequence should be between \\x00 and \\x7F")
- }
- MalformedAsciiCodeEscape => write!(f, "Escape sequence should be a hexadecimal number"),
- UnclosedUnicodeEscape => write!(f, "Missing `}}`"),
- MalformedUnicodeEscape => write!(f, "Malformed unicode escape sequence"),
- EmptyUnicodeEcape => write!(f, "Empty unicode escape sequence"),
- OverlongUnicodeEscape => {
- write!(f, "Unicode escape sequence should have at most 6 digits")
- }
- UnicodeEscapeOutOfRange => write!(f, "Unicode escape code should be at most 0x10FFFF"),
- UnclosedString => write!(f, "Unclosed string literal"),
- InvalidSuffix => write!(f, "Invalid literal suffix"),
- InvalidBlockAttr => {
- write!(f, "A block in this position cannot accept inner attributes")
- }
- InvalidMatchInnerAttr => {
- write!(f, "Inner attributes are only allowed directly after the opening brace of the match expression")
- }
- ParseError(msg) => write!(f, "{}", msg.0),
- }
- }
-}
+++ /dev/null
-use std::{fmt, ops};
-
-use crate::{SyntaxNode, TextRange, TextUnit};
-
-#[derive(Clone)]
-pub struct SyntaxText<'a> {
- node: &'a SyntaxNode,
- range: TextRange,
-}
-
-impl<'a> SyntaxText<'a> {
- pub(crate) fn new(node: &'a SyntaxNode) -> SyntaxText<'a> {
- SyntaxText { node, range: node.range() }
- }
-
- pub fn chunks(&self) -> impl Iterator<Item = &'a str> {
- let range = self.range;
- self.node.descendants().filter_map(move |node| {
- let text = node.leaf_text()?;
- let range = range.intersection(&node.range())?;
- let range = range - node.range().start();
- Some(&text[range])
- })
- }
-
- pub fn push_to(&self, buf: &mut String) {
- self.chunks().for_each(|it| buf.push_str(it));
- }
-
- pub fn to_string(&self) -> String {
- self.chunks().collect()
- }
-
- pub fn contains(&self, c: char) -> bool {
- self.chunks().any(|it| it.contains(c))
- }
-
- pub fn find(&self, c: char) -> Option<TextUnit> {
- let mut acc: TextUnit = 0.into();
- for chunk in self.chunks() {
- if let Some(pos) = chunk.find(c) {
- let pos: TextUnit = (pos as u32).into();
- return Some(acc + pos);
- }
- acc += TextUnit::of_str(chunk);
- }
- None
- }
-
- pub fn len(&self) -> TextUnit {
- self.range.len()
- }
-
- pub fn slice(&self, range: impl SyntaxTextSlice) -> SyntaxText<'a> {
- let range = range.restrict(self.range).unwrap_or_else(|| {
- panic!("invalid slice, range: {:?}, slice: {:?}", self.range, range)
- });
- SyntaxText { node: self.node, range }
- }
-
- pub fn char_at(&self, offset: impl Into<TextUnit>) -> Option<char> {
- let mut start: TextUnit = 0.into();
- let offset = offset.into();
- for chunk in self.chunks() {
- let end = start + TextUnit::of_str(chunk);
- if start <= offset && offset < end {
- let off: usize = u32::from(offset - start) as usize;
- return Some(chunk[off..].chars().next().unwrap());
- }
- start = end;
- }
- None
- }
-}
-
-impl<'a> fmt::Debug for SyntaxText<'a> {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- fmt::Debug::fmt(&self.to_string(), f)
- }
-}
-
-impl<'a> fmt::Display for SyntaxText<'a> {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- fmt::Display::fmt(&self.to_string(), f)
- }
-}
-
-pub trait SyntaxTextSlice: fmt::Debug {
- fn restrict(&self, range: TextRange) -> Option<TextRange>;
-}
-
-impl SyntaxTextSlice for TextRange {
- fn restrict(&self, range: TextRange) -> Option<TextRange> {
- self.intersection(&range)
- }
-}
-
-impl SyntaxTextSlice for ops::RangeTo<TextUnit> {
- fn restrict(&self, range: TextRange) -> Option<TextRange> {
- if !range.contains_inclusive(self.end) {
- return None;
- }
- Some(TextRange::from_to(range.start(), self.end))
- }
-}
-
-impl SyntaxTextSlice for ops::RangeFrom<TextUnit> {
- fn restrict(&self, range: TextRange) -> Option<TextRange> {
- if !range.contains_inclusive(self.start) {
- return None;
- }
- Some(TextRange::from_to(self.start, range.end()))
- }
-}
-
-impl SyntaxTextSlice for ops::Range<TextUnit> {
- fn restrict(&self, range: TextRange) -> Option<TextRange> {
- TextRange::from_to(self.start, self.end).restrict(range)
- }
-}
-
-impl From<SyntaxText<'_>> for String {
- fn from(text: SyntaxText) -> String {
- text.to_string()
- }
-}
-
-impl PartialEq<str> for SyntaxText<'_> {
- fn eq(&self, mut rhs: &str) -> bool {
- for chunk in self.chunks() {
- if !rhs.starts_with(chunk) {
- return false;
- }
- rhs = &rhs[chunk.len()..];
- }
- rhs.is_empty()
- }
-}
-
-impl PartialEq<&'_ str> for SyntaxText<'_> {
- fn eq(&self, rhs: &&str) -> bool {
- self == *rhs
- }
-}
--- /dev/null
+use std::{fmt, ops};
+
+use crate::{SyntaxNode, TextRange, TextUnit};
+
+#[derive(Clone)]
+pub struct SyntaxText<'a> {
+ node: &'a SyntaxNode,
+ range: TextRange,
+}
+
+impl<'a> SyntaxText<'a> {
+ pub(crate) fn new(node: &'a SyntaxNode) -> SyntaxText<'a> {
+ SyntaxText { node, range: node.range() }
+ }
+
+ pub fn chunks(&self) -> impl Iterator<Item = &'a str> {
+ let range = self.range;
+ self.node.descendants().filter_map(move |node| {
+ let text = node.leaf_text()?;
+ let range = range.intersection(&node.range())?;
+ let range = range - node.range().start();
+ Some(&text[range])
+ })
+ }
+
+ pub fn push_to(&self, buf: &mut String) {
+ self.chunks().for_each(|it| buf.push_str(it));
+ }
+
+ pub fn to_string(&self) -> String {
+ self.chunks().collect()
+ }
+
+ pub fn contains(&self, c: char) -> bool {
+ self.chunks().any(|it| it.contains(c))
+ }
+
+ pub fn find(&self, c: char) -> Option<TextUnit> {
+ let mut acc: TextUnit = 0.into();
+ for chunk in self.chunks() {
+ if let Some(pos) = chunk.find(c) {
+ let pos: TextUnit = (pos as u32).into();
+ return Some(acc + pos);
+ }
+ acc += TextUnit::of_str(chunk);
+ }
+ None
+ }
+
+ pub fn len(&self) -> TextUnit {
+ self.range.len()
+ }
+
+ pub fn slice(&self, range: impl SyntaxTextSlice) -> SyntaxText<'a> {
+ let range = range.restrict(self.range).unwrap_or_else(|| {
+ panic!("invalid slice, range: {:?}, slice: {:?}", self.range, range)
+ });
+ SyntaxText { node: self.node, range }
+ }
+
+ pub fn char_at(&self, offset: impl Into<TextUnit>) -> Option<char> {
+ let mut start: TextUnit = 0.into();
+ let offset = offset.into();
+ for chunk in self.chunks() {
+ let end = start + TextUnit::of_str(chunk);
+ if start <= offset && offset < end {
+ let off: usize = u32::from(offset - start) as usize;
+ return Some(chunk[off..].chars().next().unwrap());
+ }
+ start = end;
+ }
+ None
+ }
+}
+
+impl<'a> fmt::Debug for SyntaxText<'a> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ fmt::Debug::fmt(&self.to_string(), f)
+ }
+}
+
+impl<'a> fmt::Display for SyntaxText<'a> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ fmt::Display::fmt(&self.to_string(), f)
+ }
+}
+
+pub trait SyntaxTextSlice: fmt::Debug {
+ fn restrict(&self, range: TextRange) -> Option<TextRange>;
+}
+
+impl SyntaxTextSlice for TextRange {
+ fn restrict(&self, range: TextRange) -> Option<TextRange> {
+ self.intersection(&range)
+ }
+}
+
+impl SyntaxTextSlice for ops::RangeTo<TextUnit> {
+ fn restrict(&self, range: TextRange) -> Option<TextRange> {
+ if !range.contains_inclusive(self.end) {
+ return None;
+ }
+ Some(TextRange::from_to(range.start(), self.end))
+ }
+}
+
+impl SyntaxTextSlice for ops::RangeFrom<TextUnit> {
+ fn restrict(&self, range: TextRange) -> Option<TextRange> {
+ if !range.contains_inclusive(self.start) {
+ return None;
+ }
+ Some(TextRange::from_to(self.start, range.end()))
+ }
+}
+
+impl SyntaxTextSlice for ops::Range<TextUnit> {
+ fn restrict(&self, range: TextRange) -> Option<TextRange> {
+ TextRange::from_to(self.start, self.end).restrict(range)
+ }
+}
+
+impl From<SyntaxText<'_>> for String {
+ fn from(text: SyntaxText) -> String {
+ text.to_string()
+ }
+}
+
+impl PartialEq<str> for SyntaxText<'_> {
+ fn eq(&self, mut rhs: &str) -> bool {
+ for chunk in self.chunks() {
+ if !rhs.starts_with(chunk) {
+ return false;
+ }
+ rhs = &rhs[chunk.len()..];
+ }
+ rhs.is_empty()
+ }
+}
+
+impl PartialEq<&'_ str> for SyntaxText<'_> {
+ fn eq(&self, rhs: &&str) -> bool {
+ self == *rhs
+ }
+}
mod block;
use crate::{
- SourceFile, syntax_node::SyntaxError, AstNode,
+ SourceFile, SyntaxError, AstNode,
ast,
algo::visit::{visitor_ctx, VisitorCtx},
};
use crate::{SyntaxKind::*,
ast::{self, AttrsOwner, AstNode},
- syntax_node::{
- SyntaxError,
- SyntaxErrorKind::*,
- },
+ SyntaxError,
+ SyntaxErrorKind::*,
};
pub(crate) fn validate_block_node(node: &ast::Block, errors: &mut Vec<SyntaxError>) {
string_lexing::{self, StringComponentKind},
TextRange,
validation::char,
- syntax_node::{
- SyntaxError,
- SyntaxErrorKind::*,
- },
+ SyntaxError,
+ SyntaxErrorKind::*,
};
pub(super) fn validate_byte_node(node: &ast::Byte, errors: &mut Vec<SyntaxError>) {
use crate::{
ast::{self, AstNode, AstToken},
string_lexing::{self, StringComponentKind},
- syntax_node::{
- SyntaxError,
- SyntaxErrorKind::*,
- },
+ SyntaxError,
+ SyntaxErrorKind::*,
};
use super::byte;
ast::{self, AstNode, AstToken},
string_lexing::{self, StringComponentKind},
TextRange,
- syntax_node::{
- SyntaxError,
- SyntaxErrorKind::*,
- },
+ SyntaxError,
+ SyntaxErrorKind::*,
};
pub(super) fn validate_char_node(node: &ast::Char, errors: &mut Vec<SyntaxError>) {
use crate::{
ast::{self, AstNode, AstToken},
string_lexing,
- syntax_node::{
- SyntaxError,
- SyntaxErrorKind::*,
- },
+ SyntaxError,
+ SyntaxErrorKind::*,
};
use super::char;