2022-02-11 15:58:10 -08:00
|
|
|
use crate::obj::prelude::{Float, Int, Str};
|
2022-02-11 14:50:09 -08:00
|
|
|
use crate::syn::ast::*;
|
2022-02-11 15:58:10 -08:00
|
|
|
use crate::syn::span::*;
|
2022-02-11 14:50:09 -08:00
|
|
|
use pest::{error::Error, iterators::Pair, Parser};
|
2022-02-11 15:58:10 -08:00
|
|
|
use std::rc::Rc;
|
2022-02-11 14:50:09 -08:00
|
|
|
|
|
|
|
|
#[derive(pest_derive::Parser)]
|
|
|
|
|
#[grammar = "syn/parser.pest"]
|
|
|
|
|
pub struct SybilParser;
|
|
|
|
|
|
|
|
|
|
pub type Result<T, E = Error<Rule>> = std::result::Result<T, E>;
|
|
|
|
|
|
2022-02-11 15:58:10 -08:00
|
|
|
fn unescape_string(text: &str) -> Str {
|
|
|
|
|
let mut string = String::with_capacity(text.len() - 2);
|
|
|
|
|
let mut chars = text.chars().skip(1).take(text.len() - 2);
|
|
|
|
|
while let Some(c) = chars.next() {
|
|
|
|
|
if c == '\\' {
|
|
|
|
|
let c = match chars
|
|
|
|
|
.next()
|
|
|
|
|
.expect("reached end of string literal before escape")
|
|
|
|
|
{
|
|
|
|
|
'"' => '"',
|
|
|
|
|
'\'' => '\'',
|
|
|
|
|
'\\' => '\\',
|
|
|
|
|
'n' => '\n',
|
|
|
|
|
'r' => '\r',
|
|
|
|
|
't' => '\t',
|
|
|
|
|
u => panic!(
|
|
|
|
|
"unexpected character escape that made it through the lexer: {:?}",
|
|
|
|
|
u
|
|
|
|
|
),
|
|
|
|
|
};
|
|
|
|
|
string.push(c);
|
|
|
|
|
} else {
|
|
|
|
|
string.push(c);
|
|
|
|
|
}
|
2022-02-11 14:50:09 -08:00
|
|
|
}
|
2022-02-11 15:58:10 -08:00
|
|
|
string
|
2022-02-11 14:50:09 -08:00
|
|
|
}
|
|
|
|
|
|
2022-02-11 15:58:10 -08:00
|
|
|
fn parse_atom(source: &Rc<String>, pair: Pair<Rule>) -> Result<SpAtom> {
|
|
|
|
|
let pair_span = pair.as_span();
|
|
|
|
|
let atom = match pair.as_rule() {
|
|
|
|
|
Rule::float => {
|
|
|
|
|
let float = pair.as_str().parse::<Float>().unwrap();
|
|
|
|
|
Atom::Float(float)
|
2022-02-11 14:50:09 -08:00
|
|
|
}
|
2022-02-11 15:58:10 -08:00
|
|
|
Rule::int => {
|
|
|
|
|
let int = pair.as_str().parse::<Int>().unwrap();
|
|
|
|
|
Atom::Int(int)
|
2022-02-11 14:50:09 -08:00
|
|
|
}
|
2022-02-11 15:58:10 -08:00
|
|
|
Rule::assign => {
|
|
|
|
|
let word = pair.into_inner().next().unwrap().as_str().to_string();
|
|
|
|
|
Atom::Assign(word)
|
2022-02-11 14:50:09 -08:00
|
|
|
}
|
2022-02-11 15:58:10 -08:00
|
|
|
Rule::word => {
|
|
|
|
|
let word = pair.as_str().to_string();
|
|
|
|
|
Atom::Word(word)
|
|
|
|
|
}
|
|
|
|
|
Rule::str => {
|
|
|
|
|
let string = pair.as_str();
|
|
|
|
|
Atom::Str(unescape_string(string))
|
|
|
|
|
}
|
|
|
|
|
Rule::apply => Atom::Apply,
|
|
|
|
|
rule => unreachable!("{:?}", rule),
|
|
|
|
|
};
|
|
|
|
|
let span = Span {
|
|
|
|
|
source: Rc::clone(source),
|
|
|
|
|
start: pair_span.start(),
|
|
|
|
|
end: pair_span.end(),
|
|
|
|
|
};
|
|
|
|
|
Ok(SpAtom::new(span, atom))
|
2022-02-11 14:50:09 -08:00
|
|
|
}
|
|
|
|
|
|
2022-02-11 15:58:10 -08:00
|
|
|
fn parse_expr(source: &Rc<String>, pair: Pair<Rule>) -> Result<SpExpr> {
|
|
|
|
|
let pair_span = pair.as_span();
|
|
|
|
|
let expr = match pair.as_rule() {
|
|
|
|
|
Rule::atom => Expr::Atom(parse_atom(source, pair.into_inner().next().unwrap())?),
|
|
|
|
|
Rule::quote => Expr::Quote(
|
|
|
|
|
pair.into_inner()
|
|
|
|
|
.map(|pair| parse_stmt(source, pair.into_inner().next().unwrap()))
|
|
|
|
|
.collect::<Result<Vec<_>>>()?,
|
|
|
|
|
),
|
|
|
|
|
rule => unreachable!("{:?}", rule),
|
|
|
|
|
};
|
|
|
|
|
let span = Span {
|
|
|
|
|
source: Rc::clone(source),
|
|
|
|
|
start: pair_span.start(),
|
|
|
|
|
end: pair_span.end(),
|
|
|
|
|
};
|
|
|
|
|
Ok(SpExpr::new(span, expr))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn parse_stmt(source: &Rc<String>, pair: Pair<Rule>) -> Result<SpStmt> {
|
|
|
|
|
let pair_span = pair.as_span();
|
|
|
|
|
let stmt = match pair.as_rule() {
|
|
|
|
|
Rule::expr => Stmt::Expr(parse_expr(source, pair.into_inner().next().unwrap())?),
|
|
|
|
|
rule => unreachable!("{:?}", rule),
|
|
|
|
|
};
|
|
|
|
|
let span = Span {
|
|
|
|
|
source: Rc::clone(&source),
|
|
|
|
|
start: pair_span.start(),
|
|
|
|
|
end: pair_span.end(),
|
|
|
|
|
};
|
|
|
|
|
Ok(SpStmt::new(span, stmt))
|
2022-02-11 14:50:09 -08:00
|
|
|
}
|
|
|
|
|
|
2022-02-11 15:58:10 -08:00
|
|
|
pub fn parse_file(source: impl ToString, text: &str) -> Result<Vec<SpStmt>> {
|
2022-02-11 14:50:09 -08:00
|
|
|
let input = SybilParser::parse(Rule::file, text)?.next().unwrap();
|
2022-02-11 15:58:10 -08:00
|
|
|
let source = Rc::new(source.to_string());
|
2022-02-11 14:50:09 -08:00
|
|
|
let mut stmts = Vec::new();
|
|
|
|
|
for pair in input.into_inner() {
|
2022-02-11 15:58:10 -08:00
|
|
|
match pair.as_rule() {
|
|
|
|
|
Rule::EOI => {}
|
|
|
|
|
Rule::stmt => {
|
|
|
|
|
let pair = pair.into_inner().next().unwrap();
|
|
|
|
|
stmts.push(parse_stmt(&source, pair)?);
|
|
|
|
|
}
|
|
|
|
|
rule => unreachable!("{:?}", rule),
|
|
|
|
|
}
|
2022-02-11 14:50:09 -08:00
|
|
|
}
|
|
|
|
|
Ok(stmts)
|
|
|
|
|
}
|