Compare commits

...

3 Commits

4 changed files with 105 additions and 31 deletions

1
assets/styled.tml Normal file
View File

@ -0,0 +1 @@
("unstyled" bold "bold" (red "bold red") italic "bold italic")

View File

@ -124,7 +124,7 @@ impl<'a> AstBuilder<'a> {
let span = self.lexer.span();
if let TokenKind::Newline = token {
self.current_row_idx += 1;
self.current_row_start = span.start;
self.current_row_start = span.end;
} else if let TokenKind::Error = token {
let range = self.span_to_range(span);
break Err(self.with_source(ParseErrorKind::InvalidToken, range));
@ -190,23 +190,27 @@ impl<'a> AstBuilder<'a> {
}
pub fn parse_list_from(&mut self, mut token: Token) -> ParseResult<Vec<Value>> {
if let TokenKind::Symbol = token.kind {
let start = token.range.start.clone();
let id = self.token_to_string(token)?;
let body = self.parse_tag_body()?;
let end = self.idx_to_position(self.lexer.span().end);
return Ok(vec![Value {
inner: ValueKind::Tag(Tag { id, body }),
source: self.source.to_owned(),
range: start..end,
}]);
}
let mut vals = Vec::new();
while let Some(val) = self.parse_value_from(token)? {
vals.push(val);
token = self.next()?;
loop {
if let TokenKind::Symbol = token.kind {
let start = token.range.start.clone();
let id = self.token_to_string(token)?;
let body = self.parse_tag_body()?;
let end = self.idx_to_position(self.lexer.span().end);
let val = Value {
inner: ValueKind::Tag(Tag { id, body }),
source: self.source.to_owned(),
range: start..end,
};
vals.push(val);
break;
} else if let Some(val) = self.parse_value_from(token)? {
vals.push(val);
token = self.next()?;
} else {
break;
}
}
Ok(vals)
@ -284,7 +288,7 @@ impl<T: Debug + Display> Display for WithSource<T> {
let spaces: String = std::iter::repeat(" ").take(start).collect();
let carats: String = std::iter::repeat("^").take(end - start).collect();
writeln!(f, " |{}{}", spaces, carats)?;
writeln!(f, " | {}{}", spaces, carats)?;
}
Ok(())
@ -412,18 +416,18 @@ pub enum ParseErrorKind {
impl Display for ParseErrorKind {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "Error: ")?;
write!(f, "Parse error: ")?;
use ParseErrorKind::*;
match self {
InvalidToken => write!(f, "Invalid token"),
DuplicateArgument(name) => write!(f, "Duplicate {} argument", name),
UnmatchedParen => write!(f, "Unmatched parentheses"),
InvalidToken => write!(f, "invalid token"),
DuplicateArgument(name) => write!(f, "duplicate {} argument", name),
UnmatchedParen => write!(f, "unmatched parentheses"),
UnexpectedToken(kind, Some(expected)) => {
write!(f, "Unexpected {:?} token (expected {:?})", kind, expected)
write!(f, "unexpected {:?} token (expected {:?})", kind, expected)
}
UnexpectedToken(kind, None) => write!(f, "Unexpected token {:?}", kind),
UnexpectedEof => write!(f, "Unexpected end-of-file"),
UnexpectedToken(kind, None) => write!(f, "unexpected token {:?}", kind),
UnexpectedEof => write!(f, "unexpected end-of-file"),
}
}
}

View File

@ -12,18 +12,27 @@ use style::Stylesheet;
fn main() {
let src_path = std::env::args().nth(1).unwrap();
let src = std::fs::read_to_string(src_path).unwrap();
let lexer = ast::TokenKind::lexer(&src);
let tokens: Vec<_> = lexer.collect();
println!("{:?}", tokens);
let source = std::sync::Arc::new(ast::Source::from_string(src.clone()));
let mut ast_builder = ast::AstBuilder::new(&source);
match ast_builder.expect_value() {
Ok(body) => println!("{:#?}", body),
let body = match ast_builder.parse_tag_body() {
Ok(body) => body,
Err(e) => panic!("Parse error:\n{}", e),
}
};
println!("{:#?}", body);
let style = text::TextStyle::default();
let text = match text::StyledText::parse(&style, &body.children) {
Ok(text) => text,
Err(e) => panic!("Text parse error:\n{}", e),
};
println!("{:#?}", text);
let options = lexpr::parse::Options::new()
.with_string_syntax(lexpr::parse::StringSyntax::Elisp)

View File

@ -1,5 +1,9 @@
use std::str::FromStr;
use strum::EnumString;
use crate::ast::{self, WithSource};
#[derive(Clone, Debug, Hash, PartialEq, Eq, EnumString)]
#[strum(serialize_all = "kebab-case", ascii_case_insensitive)]
pub enum TextTagKind {
@ -99,7 +103,63 @@ impl TextStyle {
}
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
pub struct StyledText {
pub text: String,
pub struct StyledString {
pub string: String,
pub style: TextStyle,
}
#[derive(Clone, Debug, Default, Hash, PartialEq, Eq)]
pub struct StyledText {
pub strings: Vec<StyledString>,
}
impl StyledText {
pub fn concat(&mut self, mut other: Self) {
self.strings.append(&mut other.strings);
}
pub fn parse(style: &TextStyle, vals: &[ast::Value]) -> Result<Self, TextParseError> {
let mut text = Self::default();
for val in vals.iter() {
match &val.inner {
ast::ValueKind::String(string) => text.strings.push(StyledString {
string: string.clone(),
style: style.clone(),
}),
ast::ValueKind::List(items) => text.concat(Self::parse(style, items)?),
ast::ValueKind::Tag(tag) => text.concat(Self::parse_tag(style, tag)?),
_ => return Err(val.map(TextParseErrorKind::UnexpectedSymbol)),
}
}
Ok(text)
}
pub fn parse_tag(style: &TextStyle, tag: &ast::Tag) -> Result<Self, TextParseError> {
let kind = TextTagKind::from_str(&tag.id)
.map_err(|_| tag.id.map(TextParseErrorKind::InvalidTag))?;
let mut style = style.clone();
style.apply_tag(kind);
Self::parse(&style, &tag.body.children)
}
}
pub type TextParseError = WithSource<TextParseErrorKind>;
#[derive(Debug)]
pub enum TextParseErrorKind {
InvalidTag,
UnexpectedSymbol,
}
impl std::fmt::Display for TextParseErrorKind {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "Text parse error: ")?;
use TextParseErrorKind::*;
match self {
InvalidTag => write!(f, "invalid tag"),
UnexpectedSymbol => write!(f, "unexpected symbol"),
}
}
}