Initial draft of DSL semantics complete.
This latest refactor adds "extractor macros" in place of the very-confusing-even-to-the-DSL-author reverse-rules-as-extractors concept. It was beautifully symmetric but also just too mind-bending to be practical. It also adds argument polarity to external extractors. This is inspired by Prolog's similar notion (see e.g. the "+x" vs. "-x" argument notation in library documentation) where the unification-based semantics allow for bidirectional flow through arguments. We don't want polymorphism or dynamism w.r.t. directions/polarities here; the polarities are static; but it is useful to be able to feed values *into* an extractor (aside from the one value being extracted). Semantically this still correlates to a term-rewriting/value-equivalence world since we can still translate all of this to a list of equality constraints. To make that work, this change also adds expressions into patterns, specifically only for extractor "input" args. This required quite a bit of internal refactoring but is only a small addition to the language semantics. I plan to build out the little instruction-selector sketch further but the one that is here (in `test3.isle`) is starting to get interesting already with the current DSL semantics.
This commit is contained in:
@@ -53,6 +53,12 @@ impl<'a> Parser<'a> {
|
||||
fn is_rparen(&self) -> bool {
|
||||
self.is(|tok| *tok == Token::RParen)
|
||||
}
|
||||
fn is_at(&self) -> bool {
|
||||
self.is(|tok| *tok == Token::At)
|
||||
}
|
||||
fn is_lt(&self) -> bool {
|
||||
self.is(|tok| *tok == Token::Lt)
|
||||
}
|
||||
fn is_sym(&self) -> bool {
|
||||
self.is(|tok| tok.is_sym())
|
||||
}
|
||||
@@ -72,6 +78,12 @@ impl<'a> Parser<'a> {
|
||||
fn rparen(&mut self) -> ParseResult<()> {
|
||||
self.take(|tok| *tok == Token::RParen).map(|_| ())
|
||||
}
|
||||
fn at(&mut self) -> ParseResult<()> {
|
||||
self.take(|tok| *tok == Token::At).map(|_| ())
|
||||
}
|
||||
fn lt(&mut self) -> ParseResult<()> {
|
||||
self.take(|tok| *tok == Token::Lt).map(|_| ())
|
||||
}
|
||||
|
||||
fn symbol(&mut self) -> ParseResult<String> {
|
||||
match self.take(|tok| tok.is_sym())? {
|
||||
@@ -103,10 +115,10 @@ impl<'a> Parser<'a> {
|
||||
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()?),
|
||||
"rule" => Def::Rule(self.parse_rule()?),
|
||||
"extractor" => Def::Extractor(self.parse_etor()?),
|
||||
"extern" => Def::Extern(self.parse_extern()?),
|
||||
s => {
|
||||
return Err(self.error(pos.unwrap(), format!("Unexpected identifier: {}", s)));
|
||||
}
|
||||
@@ -231,32 +243,72 @@ impl<'a> Parser<'a> {
|
||||
})
|
||||
}
|
||||
|
||||
fn parse_ctor(&mut self) -> ParseResult<Extern> {
|
||||
fn parse_extern(&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(),
|
||||
})
|
||||
if self.is_sym_str("constructor") {
|
||||
self.symbol()?;
|
||||
let term = self.parse_ident()?;
|
||||
let func = self.parse_ident()?;
|
||||
Ok(Extern::Constructor {
|
||||
term,
|
||||
func,
|
||||
pos: pos.unwrap(),
|
||||
})
|
||||
} else if self.is_sym_str("extractor") {
|
||||
self.symbol()?;
|
||||
let term = self.parse_ident()?;
|
||||
let func = self.parse_ident()?;
|
||||
let arg_polarity = if self.is_lparen() {
|
||||
let mut pol = vec![];
|
||||
self.lparen()?;
|
||||
while !self.is_rparen() {
|
||||
if self.is_sym_str("in") {
|
||||
self.symbol()?;
|
||||
pol.push(ArgPolarity::Input);
|
||||
} else if self.is_sym_str("out") {
|
||||
self.symbol()?;
|
||||
pol.push(ArgPolarity::Output);
|
||||
} else {
|
||||
return Err(
|
||||
self.error(pos.unwrap(), "Invalid argument polarity".to_string())
|
||||
);
|
||||
}
|
||||
}
|
||||
self.rparen()?;
|
||||
Some(pol)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
Ok(Extern::Extractor {
|
||||
term,
|
||||
func,
|
||||
pos: pos.unwrap(),
|
||||
arg_polarity,
|
||||
})
|
||||
} else {
|
||||
Err(self.error(
|
||||
pos.unwrap(),
|
||||
"Invalid extern: must be (extern constructor ...) or (extern extractor ...)"
|
||||
.to_string(),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_etor(&mut self) -> ParseResult<Extern> {
|
||||
fn parse_etor(&mut self) -> ParseResult<Extractor> {
|
||||
let pos = self.pos();
|
||||
let infallible = if self.is_sym_str("infallible") {
|
||||
self.symbol()?;
|
||||
true
|
||||
} else {
|
||||
false
|
||||
};
|
||||
self.lparen()?;
|
||||
let term = self.parse_ident()?;
|
||||
let func = self.parse_ident()?;
|
||||
Ok(Extern::Extractor {
|
||||
let mut args = vec![];
|
||||
while !self.is_rparen() {
|
||||
args.push(self.parse_ident()?);
|
||||
}
|
||||
self.rparen()?;
|
||||
let template = self.parse_pattern()?;
|
||||
Ok(Extractor {
|
||||
term,
|
||||
func,
|
||||
args,
|
||||
template,
|
||||
pos: pos.unwrap(),
|
||||
infallible,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -292,8 +344,8 @@ impl<'a> Parser<'a> {
|
||||
Ok(Pattern::Var { var })
|
||||
} else {
|
||||
let var = self.str_to_ident(pos.unwrap(), &s)?;
|
||||
if self.is_sym_str("@") {
|
||||
self.symbol()?;
|
||||
if self.is_at() {
|
||||
self.at()?;
|
||||
let subpat = Box::new(self.parse_pattern()?);
|
||||
Ok(Pattern::BindPattern { var, subpat })
|
||||
} else {
|
||||
@@ -317,7 +369,7 @@ impl<'a> Parser<'a> {
|
||||
let sym = self.parse_ident()?;
|
||||
let mut args = vec![];
|
||||
while !self.is_rparen() {
|
||||
args.push(self.parse_pattern()?);
|
||||
args.push(self.parse_pattern_term_arg()?);
|
||||
}
|
||||
self.rparen()?;
|
||||
Ok(Pattern::Term { sym, args })
|
||||
@@ -327,6 +379,15 @@ impl<'a> Parser<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_pattern_term_arg(&mut self) -> ParseResult<TermArgPattern> {
|
||||
if self.is_lt() {
|
||||
self.lt()?;
|
||||
Ok(TermArgPattern::Expr(self.parse_expr()?))
|
||||
} else {
|
||||
Ok(TermArgPattern::Pattern(self.parse_pattern()?))
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_expr(&mut self) -> ParseResult<Expr> {
|
||||
let pos = self.pos();
|
||||
if self.is_lparen() {
|
||||
|
||||
Reference in New Issue
Block a user