doughlang: Expressions in patterns
ast: - Document operators - Parameterize Pat with Annotation - Consolidate Path and Lit into "Value" (Expr) - Consolidate NamedRecord/Namedtuple into PatOp::TypePrefixed - Allow Pat<Pat,*> patterns - Additional helper functions on Expr and Pat lexer: - Support inner-doc comment syntax `//!` - Cleans up `///` or `//!` prefix parser: - Make Parse::Prec `Default` - Allow expression elision after `..`/`..=` - Fix Parser::consume not updating elide_do state - Add token splitting, to make `&&Expr` and `&&Pat` easier - error: Embed Pat precedence in ParseError
This commit is contained in:
@@ -130,7 +130,7 @@ impl<'a> Visit<'a> for CountNodes {
|
||||
item.children(self)
|
||||
}
|
||||
|
||||
fn visit_pat(&mut self, item: &'a Pat) -> Result<(), Self::Error> {
|
||||
fn visit_pat<A: Annotation>(&mut self, item: &'a Pat<A>) -> Result<(), Self::Error> {
|
||||
self.patterns += 1;
|
||||
item.children(self)
|
||||
}
|
||||
|
||||
@@ -54,6 +54,8 @@ impl ToLisp {
|
||||
PatOp::Slice => "slice",
|
||||
PatOp::ArRep => "ar-rep",
|
||||
PatOp::Typed => "typed",
|
||||
PatOp::TypePrefixed => "type-prefixed",
|
||||
PatOp::Generic => "generic-in",
|
||||
PatOp::Fn => "fn",
|
||||
PatOp::Alt => "alt",
|
||||
}
|
||||
@@ -196,28 +198,13 @@ impl<'a> Visit<'a> for ToLisp {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn visit_pat(&mut self, item: &'a Pat) -> Result<(), Self::Error> {
|
||||
fn visit_pat<A: Annotation>(&mut self, item: &'a Pat<A>) -> Result<(), Self::Error> {
|
||||
match item {
|
||||
Pat::Ignore => print!("(ignore)"),
|
||||
Pat::Never => print!("(never)"),
|
||||
Pat::MetId(id) => print!("(replace {id})"),
|
||||
Pat::Name(name) => print!("{name}"),
|
||||
Pat::Path(path) => path.visit_in(self)?,
|
||||
Pat::NamedRecord(path, pat) => {
|
||||
print!("(struct-pat ");
|
||||
path.visit_in(self)?;
|
||||
print!(" ");
|
||||
pat.visit_in(self)?;
|
||||
print!(")")
|
||||
}
|
||||
Pat::NamedTuple(path, pat) => {
|
||||
print!("(named ");
|
||||
path.visit_in(self)?;
|
||||
print!(" ");
|
||||
pat.visit_in(self)?;
|
||||
print!(")")
|
||||
}
|
||||
Pat::Lit(literal) => literal.visit_in(self)?,
|
||||
Pat::Value(literal) => literal.visit_in(self)?,
|
||||
Pat::Op(pat_op, pats) => {
|
||||
print!("({}", self.pat_op(*pat_op));
|
||||
for pat in pats {
|
||||
|
||||
140
examples/weight.rs
Normal file
140
examples/weight.rs
Normal file
@@ -0,0 +1,140 @@
|
||||
//! Demonstrates the visitor pattern
|
||||
|
||||
use std::{convert::Infallible, error::Error};
|
||||
|
||||
use doughlang::{
|
||||
ast::{
|
||||
visit::{Visit, Walk},
|
||||
*,
|
||||
},
|
||||
lexer::Lexer,
|
||||
parser::{Parser, expr::Prec},
|
||||
};
|
||||
|
||||
const CODE: &str = r#"
|
||||
let x: [i32; 4] = [1, 2, 3, 4];
|
||||
|
||||
use foo::bar::baz::qux::{a, b, c, d, e};
|
||||
|
||||
struct Point<T> {x: T, y: T}
|
||||
|
||||
let v = Point {
|
||||
x, y: 20 + x
|
||||
}
|
||||
|
||||
fn main() -> (&str, bool, i128) {
|
||||
// An if expression is like the ternary conditional operator in C
|
||||
let y = if 10 < 50 {
|
||||
"\u{1f988}"
|
||||
} else {
|
||||
"x"
|
||||
}
|
||||
|
||||
// A `while` expression is like the while-else construct in Python,
|
||||
// but it returns a value via the `break` keyword
|
||||
let z = while false {
|
||||
// do a thing repeatedly
|
||||
break true
|
||||
} else {
|
||||
// If `while` does not `break`, fall through to the `else` expression
|
||||
false
|
||||
}
|
||||
|
||||
// The same is true of `for` expressions!
|
||||
let w = for idx in 0..100 {
|
||||
if idx > 2 * 2 {
|
||||
break idx
|
||||
}
|
||||
} else 12345; // semicolon operator required here
|
||||
|
||||
|
||||
// desugars to
|
||||
let w = match ((0..100).into_iter()) {
|
||||
__iter => loop match (__iter.next()) {
|
||||
None => break 12345,
|
||||
Some (idx) => {
|
||||
if (idx > (2 * 2)) {
|
||||
break idx
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
// A block evaluates to its last expression,
|
||||
// or Empty if there is none
|
||||
// (🦈, false, 5)
|
||||
(y, z, w)
|
||||
}
|
||||
|
||||
"#;
|
||||
|
||||
fn main() -> Result<(), Box<dyn Error>> {
|
||||
let ast: Anno<Expr> = Parser::new(Lexer::new(CODE)).parse(Prec::MIN)?;
|
||||
println!("{ast}");
|
||||
let mut counters = Weight::new();
|
||||
counters.visit(&ast);
|
||||
println!("{counters:#?}");
|
||||
println!("{}", CODE.len());
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, PartialEq, Eq)]
|
||||
struct Weight {
|
||||
size: usize,
|
||||
}
|
||||
|
||||
impl Weight {
|
||||
fn new() -> Self {
|
||||
Self::default()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Visit<'a> for Weight {
|
||||
type Error = Infallible;
|
||||
|
||||
fn visit_expr<A: Annotation>(&mut self, item: &'a Expr<A>) -> Result<(), Self::Error> {
|
||||
self.size += size_of_val(item);
|
||||
item.children(self)
|
||||
}
|
||||
|
||||
fn visit_ident(&mut self, item: &'a str) -> Result<(), Self::Error> {
|
||||
self.size += size_of_val(item);
|
||||
item.children(self)
|
||||
}
|
||||
|
||||
fn visit_path(&mut self, item: &'a Path) -> Result<(), Self::Error> {
|
||||
self.size += size_of_val(item) + size_of_val(item.parts.as_slice());
|
||||
item.children(self)
|
||||
}
|
||||
|
||||
fn visit_literal(&mut self, item: &'a Literal) -> Result<(), Self::Error> {
|
||||
self.size += size_of_val(item);
|
||||
item.children(self)
|
||||
}
|
||||
|
||||
fn visit_use(&mut self, item: &'a Use) -> Result<(), Self::Error> {
|
||||
self.size += size_of_val(item);
|
||||
item.children(self)
|
||||
}
|
||||
|
||||
fn visit_pat<A: Annotation>(&mut self, item: &'a Pat<A>) -> Result<(), Self::Error> {
|
||||
self.size += size_of_val(item);
|
||||
item.children(self)
|
||||
}
|
||||
|
||||
fn visit_bind<A: Annotation>(&mut self, item: &'a Bind<A>) -> Result<(), Self::Error> {
|
||||
self.size += size_of_val(item);
|
||||
item.children(self)
|
||||
}
|
||||
|
||||
fn visit_make<A: Annotation>(&mut self, item: &'a Make<A>) -> Result<(), Self::Error> {
|
||||
self.size += size_of_val(item);
|
||||
item.children(self)
|
||||
}
|
||||
|
||||
fn visit_makearm<A: Annotation>(&mut self, item: &'a MakeArm<A>) -> Result<(), Self::Error> {
|
||||
self.size += size_of_val(item);
|
||||
item.children(self)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user