-
Hi, I am trying to parse emmylua types but couldn't figure out how to recursively parse union and array types. For Example:
Besides that, I was able to parse other nested types like functions and tables.
I came up with this code so far use chumsky::{
prelude::Simple,
primitive::{choice, just},
recursive::recursive,
text::{ident, TextParser},
Parser,
};
// Source: https://github.com/sumneko/lua-language-server/wiki/Annotations#documenting-types
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum Ty {
Nil,
Unknown,
Boolean,
String,
Number,
Integer,
Function,
Thread,
Userdata,
Lightuserdata,
Union(Vec<Ty>),
Array(Box<Ty>),
Table(Option<(Box<Ty>, Box<Ty>)>),
Fun(Vec<(String, Ty)>, Option<Box<Ty>>),
}
recursive(|inner| {
let comma = just(',').padded();
let colon = just(':').padded();
choice((
just("any").to(Ty::Unknown),
just("unknown").to(Ty::Unknown),
just("nil").to(Ty::Nil),
just("boolean").to(Ty::Boolean),
just("string").to(Ty::String),
just("number").to(Ty::Number),
just("integer").to(Ty::Integer),
just("function").to(Ty::Function),
just("thread").to(Ty::Thread),
just("userdata").to(Ty::Userdata),
just("lightuserdata").to(Ty::Lightuserdata),
just("fun")
.ignore_then(
ident()
.padded()
.then_ignore(colon)
.then(inner.clone())
.separated_by(comma)
.allow_trailing()
.delimited_by(just('('), just(')')),
)
.then(colon.ignore_then(inner.clone().map(Box::new)).or_not())
.map(|(param, ret)| Ty::Fun(param, ret)),
just("table")
.ignore_then(
just('<')
.ignore_then(inner.clone().map(Box::new))
.then_ignore(comma)
.then(inner.clone().map(Box::new))
.then_ignore(just('>'))
.or_not(),
)
.map(Ty::Table),
// This produces stackoverflow :(
// inner
// .clone()
// .then_ignore(just('|'))
// .chain(inner.clone().separated_by(just('|')))
// .map(Ty::Union),
// inner
// .clone()
// .then_ignore(just('[').then(just(']')))
// .map(|x| Ty::Array(Box::new(x))),
))
}) I would appreciate it If you could guide me on how parse union and array types recursively :) |
Beta Was this translation helpful? Give feedback.
Replies: 1 comment 3 replies
-
You can think of the array notation as being a postfix unary operator. You'd do well to split the definition of your type syntax into 'atoms' (self-delimiting types) and other operators, as when parsing expressions (I find it easier to think of type syntax as being 'type-level expressions'). Then, array access can look something like this: let atom = ... ;
let array = atom
.then(just("[]").repeated())
.foldl(|ty, _| Type::Array(ty)); |
Beta Was this translation helpful? Give feedback.
You can think of the array notation as being a postfix unary operator. You'd do well to split the definition of your type syntax into 'atoms' (self-delimiting types) and other operators, as when parsing expressions (I find it easier to think of type syntax as being 'type-level expressions'). Then, array access can look something like this: