Initial public commit of ISLE prototype DSL compiler.

This commit is contained in:
Chris Fallin
2021-06-29 17:00:43 -07:00
parent f2939111d9
commit 84b7612b98
13 changed files with 3201 additions and 0 deletions

View File

@@ -0,0 +1,429 @@
//! Parser for ISLE language.
use crate::ast::*;
use crate::error::*;
use crate::lexer::{Lexer, Pos, Token};
#[derive(Clone, Debug)]
pub struct Parser<'a> {
filename: &'a str,
lexer: Lexer<'a>,
}
pub type ParseResult<T> = std::result::Result<T, ParseError>;
impl<'a> Parser<'a> {
pub fn new(filename: &'a str, s: &'a str) -> Parser<'a> {
Parser {
filename,
lexer: Lexer::new(s),
}
}
pub fn error(&self, pos: Pos, msg: String) -> ParseError {
ParseError {
filename: self.filename.to_string(),
pos,
msg,
}
}
fn take<F: Fn(Token) -> bool>(&mut self, f: F) -> ParseResult<Token<'a>> {
if let Some((pos, peek)) = self.lexer.peek() {
if !f(peek) {
return Err(self.error(pos, format!("Unexpected token {:?}", peek)));
}
self.lexer.next();
Ok(peek)
} else {
Err(self.error(self.lexer.pos(), "Unexpected EOF".to_string()))
}
}
fn is<F: Fn(Token) -> bool>(&self, f: F) -> bool {
if let Some((_, peek)) = self.lexer.peek() {
f(peek)
} else {
false
}
}
fn pos(&self) -> Option<Pos> {
self.lexer.peek().map(|(pos, _)| pos)
}
fn is_lparen(&self) -> bool {
self.is(|tok| tok == Token::LParen)
}
fn is_rparen(&self) -> bool {
self.is(|tok| tok == Token::RParen)
}
fn is_sym(&self) -> bool {
self.is(|tok| tok.is_sym())
}
fn is_int(&self) -> bool {
self.is(|tok| tok.is_int())
}
fn is_sym_str(&self, s: &str) -> bool {
self.is(|tok| tok == Token::Symbol(s))
}
fn lparen(&mut self) -> ParseResult<()> {
self.take(|tok| tok == Token::LParen).map(|_| ())
}
fn rparen(&mut self) -> ParseResult<()> {
self.take(|tok| tok == Token::RParen).map(|_| ())
}
fn symbol(&mut self) -> ParseResult<&'a str> {
match self.take(|tok| tok.is_sym())? {
Token::Symbol(s) => Ok(s),
_ => unreachable!(),
}
}
fn int(&mut self) -> ParseResult<i64> {
match self.take(|tok| tok.is_int())? {
Token::Int(i) => Ok(i),
_ => unreachable!(),
}
}
pub fn parse_defs(&mut self) -> ParseResult<Defs> {
let mut defs = vec![];
while !self.lexer.eof() {
defs.push(self.parse_def()?);
}
Ok(Defs {
defs,
filename: self.filename.to_string(),
})
}
fn parse_def(&mut self) -> ParseResult<Def> {
self.lparen()?;
let pos = self.pos();
let def = match self.symbol()? {
"type" => Def::Type(self.parse_type()?),
"rule" => Def::Rule(self.parse_rule()?),
"decl" => Def::Decl(self.parse_decl()?),
"constructor" => Def::Extern(self.parse_ctor()?),
"extractor" => Def::Extern(self.parse_etor()?),
s => {
return Err(self.error(pos.unwrap(), format!("Unexpected identifier: {}", s)));
}
};
self.rparen()?;
Ok(def)
}
fn str_to_ident(&self, pos: Pos, s: &str) -> ParseResult<Ident> {
let first = s.chars().next().unwrap();
if !first.is_alphabetic() && first != '_' {
return Err(self.error(
pos,
format!("Identifier '{}' does not start with letter or _", s),
));
}
if s.chars()
.skip(1)
.any(|c| !c.is_alphanumeric() && c != '_' && c != '.')
{
return Err(self.error(
pos,
format!(
"Identifier '{}' contains invalid character (not a-z, A-Z, 0-9, _, .)",
s
),
));
}
Ok(Ident(s.to_string()))
}
fn parse_ident(&mut self) -> ParseResult<Ident> {
let pos = self.pos();
let s = self.symbol()?;
self.str_to_ident(pos.unwrap(), s)
}
fn parse_type(&mut self) -> ParseResult<Type> {
let pos = self.pos();
let name = self.parse_ident()?;
let mut is_extern = false;
if self.is_sym_str("extern") {
self.symbol()?;
is_extern = true;
}
let ty = self.parse_typevalue()?;
Ok(Type {
name,
is_extern,
ty,
pos: pos.unwrap(),
})
}
fn parse_typevalue(&mut self) -> ParseResult<TypeValue> {
let pos = self.pos();
self.lparen()?;
if self.is_sym_str("primitive") {
self.symbol()?;
let primitive_ident = self.parse_ident()?;
self.rparen()?;
Ok(TypeValue::Primitive(primitive_ident))
} else if self.is_sym_str("enum") {
self.symbol()?;
let mut variants = vec![];
while !self.is_rparen() {
let variant = self.parse_type_variant()?;
variants.push(variant);
}
self.rparen()?;
Ok(TypeValue::Enum(variants))
} else {
Err(self.error(pos.unwrap(), "Unknown type definition".to_string()))
}
}
fn parse_type_variant(&mut self) -> ParseResult<Variant> {
self.lparen()?;
let name = self.parse_ident()?;
let mut fields = vec![];
while !self.is_rparen() {
fields.push(self.parse_type_field()?);
}
self.rparen()?;
Ok(Variant { name, fields })
}
fn parse_type_field(&mut self) -> ParseResult<Field> {
self.lparen()?;
let name = self.parse_ident()?;
let ty = self.parse_ident()?;
self.rparen()?;
Ok(Field { name, ty })
}
fn parse_decl(&mut self) -> ParseResult<Decl> {
let pos = self.pos();
let term = self.parse_ident()?;
self.lparen()?;
let mut arg_tys = vec![];
while !self.is_rparen() {
arg_tys.push(self.parse_ident()?);
}
self.rparen()?;
let ret_ty = self.parse_ident()?;
Ok(Decl {
term,
arg_tys,
ret_ty,
pos: pos.unwrap(),
})
}
fn parse_ctor(&mut self) -> ParseResult<Extern> {
let pos = self.pos();
let term = self.parse_ident()?;
let func = self.parse_ident()?;
Ok(Extern::Constructor {
term,
func,
pos: pos.unwrap(),
})
}
fn parse_etor(&mut self) -> ParseResult<Extern> {
let pos = self.pos();
let term = self.parse_ident()?;
let func = self.parse_ident()?;
Ok(Extern::Extractor {
term,
func,
pos: pos.unwrap(),
})
}
fn parse_rule(&mut self) -> ParseResult<Rule> {
let pos = self.pos();
let prio = if self.is_int() {
Some(self.int()?)
} else {
None
};
let pattern = self.parse_pattern()?;
let expr = self.parse_expr()?;
Ok(Rule {
pattern,
expr,
pos: pos.unwrap(),
prio,
})
}
fn parse_pattern(&mut self) -> ParseResult<Pattern> {
let pos = self.pos();
if self.is_int() {
Ok(Pattern::ConstInt { val: self.int()? })
} else if self.is_sym_str("_") {
self.symbol()?;
Ok(Pattern::Wildcard)
} else if self.is_sym() {
let s = self.symbol()?;
if s.starts_with("=") {
let s = &s[1..];
let var = self.str_to_ident(pos.unwrap(), s)?;
Ok(Pattern::Var { var })
} else {
let var = self.str_to_ident(pos.unwrap(), s)?;
if self.is_sym_str("@") {
self.symbol()?;
let subpat = Box::new(self.parse_pattern()?);
Ok(Pattern::BindPattern { var, subpat })
} else {
Ok(Pattern::BindPattern {
var,
subpat: Box::new(Pattern::Wildcard),
})
}
}
} else if self.is_lparen() {
self.lparen()?;
let sym = self.parse_ident()?;
let mut args = vec![];
while !self.is_rparen() {
args.push(self.parse_pattern()?);
}
self.rparen()?;
Ok(Pattern::Term { sym, args })
} else {
Err(self.error(pos.unwrap(), "Unexpected pattern".into()))
}
}
fn parse_expr(&mut self) -> ParseResult<Expr> {
let pos = self.pos();
if self.is_lparen() {
self.lparen()?;
if self.is_sym_str("let") {
self.symbol()?;
self.lparen()?;
let mut defs = vec![];
while !self.is_rparen() {
let def = self.parse_letdef()?;
defs.push(def);
}
self.rparen()?;
let body = Box::new(self.parse_expr()?);
self.rparen()?;
Ok(Expr::Let { defs, body })
} else {
let sym = self.parse_ident()?;
let mut args = vec![];
while !self.is_rparen() {
args.push(self.parse_expr()?);
}
self.rparen()?;
Ok(Expr::Term { sym, args })
}
} else if self.is_sym() {
let name = self.parse_ident()?;
Ok(Expr::Var { name })
} else if self.is_int() {
let val = self.int()?;
Ok(Expr::ConstInt { val })
} else {
Err(self.error(pos.unwrap(), "Invalid expression".into()))
}
}
fn parse_letdef(&mut self) -> ParseResult<LetDef> {
self.lparen()?;
let var = self.parse_ident()?;
let ty = self.parse_ident()?;
let val = Box::new(self.parse_expr()?);
self.rparen()?;
Ok(LetDef { var, ty, val })
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn parse_type() {
let text = r"
;; comment
(type Inst extern (enum
(Alu (a Reg) (b Reg) (dest Reg))
(Load (a Reg) (dest Reg))))
(type u32 (primitive u32))
";
let defs = Parser::new("(none)", text)
.parse_defs()
.expect("should parse");
assert_eq!(
defs,
Defs {
filename: "(none)".to_string(),
defs: vec![
Def::Type(Type {
name: Ident("Inst".to_string()),
is_extern: true,
ty: TypeValue::Enum(vec![
Variant {
name: Ident("Alu".to_string()),
fields: vec![
Field {
name: Ident("a".to_string()),
ty: Ident("Reg".to_string()),
},
Field {
name: Ident("b".to_string()),
ty: Ident("Reg".to_string()),
},
Field {
name: Ident("dest".to_string()),
ty: Ident("Reg".to_string()),
},
],
},
Variant {
name: Ident("Load".to_string()),
fields: vec![
Field {
name: Ident("a".to_string()),
ty: Ident("Reg".to_string()),
},
Field {
name: Ident("dest".to_string()),
ty: Ident("Reg".to_string()),
},
],
}
]),
pos: Pos {
offset: 42,
line: 4,
col: 18,
},
}),
Def::Type(Type {
name: Ident("u32".to_string()),
is_extern: false,
ty: TypeValue::Primitive(Ident("u32".to_string())),
pos: Pos {
offset: 167,
line: 7,
col: 18,
},
}),
]
}
);
}
}