feat(kind-fmt): improve specialize structure

This commit is contained in:
Gabrielle Guimarães de Oliveira 2023-04-15 18:23:08 -03:00
parent d46739a9a5
commit 2cfea13c6e
No known key found for this signature in database
GPG Key ID: 1EFDBA29D0C4037A
11 changed files with 347 additions and 144 deletions

View File

@ -0,0 +1,15 @@
use kind_syntax::concrete::Expr;
use crate::{Result, FmtContext};
impl<'a> FmtContext<'a> {
pub fn expr(&mut self) -> Result<Expr> {
match self.kind() {
"call" => {
let callee = self.property("callee").unwrap();
self.cursor(callee).primary()
},
kind => todo!("{}", kind),
}
}
}

View File

@ -1,19 +1,33 @@
use std::path::PathBuf;
use thin_vec::ThinVec;
use tree_sitter::{Node, Parser, Tree, TreeCursor};
use thin_vec::{thin_vec, ThinVec};
use tree_sitter::{Parser, Tree, TreeCursor};
use kind_syntax::concrete::Module;
use kind_syntax::lexemes::Token;
use kind_syntax::concrete::{Block, ConstructorExpr, Expr, ExprKind, LocalExpr, Module, Pat, PatKind, Rule, Signature, Stmt, TopLevel, TopLevelKind};
use kind_syntax::lexemes::{Brace, Colon, Equal, Ident, Item, Name, Span, Token, Tokenized};
mod expr;
mod name;
mod parameter;
mod pattern;
mod primary;
mod statements;
mod top_level;
#[derive(Debug)]
pub enum FmtError {
IoError(std::io::Error),
Utf8Error(std::str::Utf8Error),
TreeSitterLanguageError(tree_sitter::LanguageError),
TreeSitterQueryError(tree_sitter::QueryError),
UnknownParseError,
}
#[derive(Clone, Copy)]
pub struct FmtContext<'a> {
pub file: &'a str,
pub tree: &'a Tree,
pub cursor: *mut TreeCursor<'a>,
}
pub type Result<T> = std::result::Result<T, FmtError>;
pub fn run_fmt(string: String) -> Result<Module> {
@ -21,7 +35,7 @@ pub fn run_fmt(string: String) -> Result<Module> {
parser
.set_language(tree_sitter_kind::language())
.map_err(FmtError::TreeSitterLanguageError)?;
let tree = parser
let mut tree = parser
.parse(string.as_bytes(), None)
.ok_or(FmtError::UnknownParseError)?;
@ -29,10 +43,16 @@ pub fn run_fmt(string: String) -> Result<Module> {
let mut cursor = tree.root_node().walk();
let declarations = tree.root_node().children(&mut cursor)
.map(|node| {
specialize_top_level(&string, &tree, &mut node.walk())
})
let context = FmtContext {
file: &string,
tree: &tree,
cursor: &mut cursor,
};
let declarations = tree
.root_node()
.children(&mut cursor)
.map(|node| context.cursor(node).top_level())
.collect::<Result<ThinVec<_>>>()?;
Ok(Module {
@ -42,132 +62,91 @@ pub fn run_fmt(string: String) -> Result<Module> {
})
}
fn specialize_top_level(file: &String, tree: &Tree, cursor: &mut TreeCursor) -> Result<TopLevel> {
let node = cursor.node();
match node.kind() {
"val_declaration" => {
let name = node.child_by_field_name("name").unwrap();
let return_type = node.child_by_field_name("return_type");
let value = node.child_by_field_name("value");
impl<'a> FmtContext<'a> {
pub fn node(&self) -> Node<'a> {
unsafe { (*self.cursor).node() }
}
Ok(TopLevel {
data: Item::new(
Span::default(),
TopLevelKind::Signature(Signature {
name: specialize_name(file, tree, &mut name.walk())?,
arguments: thin_vec![],
return_type: return_type.map_or(Ok(None), |node| {
let expr = specialize_expr(file, tree, &mut node.walk())?;
Ok(Some(Colon(Token::default(), expr)))
})?,
value: value.map_or(Ok(None), |node| {
let block = specialize_statements(file, tree, &mut node.walk())?;
Ok(Some(block))
})?,
}),
),
attributes: thin_vec![],
pub fn get_current_cursor(&self) -> TreeCursor<'a> {
unsafe { (*self.cursor).clone() }
}
pub fn kind(&self) -> &'static str {
self.node().kind()
}
pub fn first(&self) -> Option<Node<'a>> {
self.node().child(0)
}
pub fn at(&self, at: usize) -> Option<Node<'a>> {
self.node().child(at)
}
pub fn named_at(&self, at: usize) -> Option<Node<'a>> {
self.node().named_child(at)
}
pub fn property(&self, name: &str) -> Option<Node<'a>> {
self.node().child_by_field_name(name)
}
pub fn properties(&self, name: &'static str) -> impl Iterator<Item = Node<'a>> {
unsafe {
self.node().children_by_field_name(name, self.cursor.as_mut().unwrap())
}
}
pub fn find<F, T>(&self, name: &str, mut f: F) -> Result<Option<T>>
where
F: FnMut(Node) -> Result<T>,
{
self
.node()
.child_by_field_name(name)
.map_or(Ok(None), |node| {
let value = f(node)?;
Ok(Some(value))
})
}
_ => todo!(),
}
}
fn specialize_pattern(file: &String, tree: &Tree, cursor: &mut TreeCursor) -> Result<Pat> {
let node = cursor.node();
match node.kind() {
"identifier" => {
specialize_name(file, tree, cursor)
.map(|name| Pat::new(
Span::default(),
PatKind::Name(name),
))
pub fn named_children(&self) -> impl Iterator<Item = Node<'a>> + '_ {
unsafe {
self.node().named_children(self.cursor.as_mut().unwrap())
}
"constructor_identifier" => {
specialize_name(file, tree, cursor)
.map(|name| Pat::new(
Span::default(),
PatKind::Name(name),
))
}
kind => todo!("{}", kind),
}
}
fn specialize_expr(file: &String, tree: &Tree, cursor: &mut TreeCursor) -> Result<Expr> {
let node = cursor.node();
match node.kind() {
"call" => {
let callee = node
.child_by_field_name("callee")
.unwrap();
pub fn children(&self) -> impl Iterator<Item = Node<'a>> + '_ {
let mut cursor = self.get_current_cursor();
specialize_primary(file, tree, &mut callee.walk())
},
kind => todo!("{}", kind),
cursor.reset(self.node());
cursor.goto_first_child();
(0..self.node().child_count()).map(move |_| {
let result = cursor.node();
cursor.goto_next_sibling();
result
})
}
}
fn specialize_name(file: &String, _tree: &Tree, cursor: &mut TreeCursor) -> Result<Name> {
let node = cursor.node();
match node.kind() {
"identifier" => {
let name = node.utf8_text(file.as_bytes()).unwrap().to_string();
Ok(Name::Ident(Ident(Item::new(
Span::default(),
Tokenized(Token::default(), name),
))))
}
kind => todo!("{}", kind),
pub fn text(&self) -> Result<&'a str> {
self.node()
.utf8_text(self.file.as_bytes())
.map_err(FmtError::Utf8Error)
}
}
fn specialize_statements(file: &String, tree: &Tree, cursor: &mut TreeCursor) -> Result<Block> {
let node = cursor.node();
match node.kind() {
"statements" => {
let statements = node.named_children(cursor)
.map(|node| {
specialize_expr(file, tree, &mut node.walk())
})
.collect::<Result<ThinVec<_>>>()?;
Ok(Brace(
Token::default(),
statements.iter().map(|expr| Stmt {
value: expr.clone(),
semi: None,
}).collect(),
Token::default(),
))
}
kind => todo!("{}", kind),
pub fn text_of(&self, node: Node<'_>) -> Result<&'a str> {
node.utf8_text(self.file.as_bytes())
.map_err(FmtError::Utf8Error)
}
}
fn specialize_primary(file: &String, tree: &Tree, cursor: &mut TreeCursor) -> Result<Expr> {
let node = cursor.node();
match node.kind() {
"constructor_identifier" => {
specialize_name(file, tree, cursor)
.map(|name| Expr::new(
Span::default(),
ExprKind::Constructor(Box::new(ConstructorExpr {
name,
})),
))
pub fn cursor<'b>(&'b self, node: Node<'b>) -> FmtContext<'b> {
// fix this leak
let cursor = Box::leak(Box::new(node.walk()));
FmtContext {
file: self.file,
tree: self.tree,
cursor,
}
"identifier" => {
specialize_name(file, tree, cursor)
.map(|name| Expr::new(
Span::default(),
ExprKind::Local(Box::new(LocalExpr {
name,
})),
))
}
_ => todo!(),
}
}
@ -177,7 +156,7 @@ mod tests {
#[test]
fn it_works() {
let expr = run_fmt("bao:pao{a}".into()).unwrap();
let expr = run_fmt("Ata (name: U60) : Type { Something }".into()).unwrap();
println!("{:#?}", expr);
}
}

View File

@ -0,0 +1,26 @@
use kind_syntax::lexemes::{Ident, Item, Name, QualifiedIdent, Span, Token, Tokenized};
use crate::{Result, FmtContext};
impl<'a> FmtContext<'a> {
pub fn name(&mut self) -> Result<Name> {
match self.kind() {
"identifier" => {
let name = self.text()?.to_string();
Ok(Name::Ident(Ident(Item::new(
Span::default(),
Tokenized(Token::default(), name),
))))
}
"constructor_identifier" => {
let name = self.text()?.to_string();
Ok(Name::QualifiedIdent(QualifiedIdent(Item::new(
Span::default(),
Tokenized(Token::default(), name),
))))
}
kind => todo!("{}", kind),
}
}
}

View File

@ -0,0 +1,48 @@
use kind_syntax::concrete::{ParameterBinding, SignatureParameter, TypeBinding};
use kind_syntax::lexemes::{AngleBracket, Colon, Paren, Token};
use crate::{FmtContext, Result};
impl<'a> FmtContext<'a> {
pub fn parameter(&mut self) -> Result<SignatureParameter> {
match self.kind() {
"parameter" => {
let modifier = self.find("modifier", |node| self.text_of(node))?;
let signature = match modifier {
Some(x) if x == "+" => SignatureParameter::Include,
Some(x) if x == "-" => SignatureParameter::Exclude,
Some(x) if x == "-+" => SignatureParameter::Both,
Some(x) if x == "+-" => SignatureParameter::Both,
_ => SignatureParameter::Include,
};
let parameter = self.cursor(self.first().unwrap());
let name = parameter
.find("name", |node| parameter.cursor(node).name())?
.unwrap();
let binding_type = parameter.clone().find("type", |node| {
let expr = parameter.cursor(node).expr()?;
Ok(Colon(Token::default(), Box::new(expr)))
})?;
match parameter.kind() {
"explicit_parameter" => Ok(signature(ParameterBinding::Explicit(Paren(
Token::default(),
TypeBinding { name, binding_type },
Token::default(),
)))),
"implicit_parameter" => {
Ok(signature(ParameterBinding::Implicit(AngleBracket(
Token::default(),
TypeBinding { name, binding_type },
Token::default(),
))))
}
kind => todo!("{}", kind),
}
}
kind => todo!("{}", kind),
}
}
}

View File

@ -0,0 +1,15 @@
use kind_syntax::concrete::{Pat, PatKind};
use kind_syntax::lexemes::Span;
use crate::{Result, FmtContext};
impl<'a> FmtContext<'a> {
pub fn pattern(&mut self) -> Result<Pat> {
match self.kind() {
"identifier" | "constructor_identifier" => {
let name = self.name()?;
Ok(Pat::new(Span::default(), PatKind::Name(name)))
}
kind => todo!("{}", kind),
}
}
}

View File

@ -0,0 +1,19 @@
use kind_syntax::concrete::Expr;
use kind_syntax::lexemes::Span;
use crate::{FmtContext, Result};
impl<'a> FmtContext<'a> {
pub fn primary(&mut self) -> Result<Expr> {
match self.kind() {
"constructor_identifier" => {
let name = self.name()?;
Ok(Expr::constructor(Span::default(), name))
}
"identifier" => {
let name = self.name()?;
Ok(Expr::local(Span::default(), name))
}
kind => todo!("{}", kind),
}
}
}

View File

@ -0,0 +1,32 @@
use thin_vec::ThinVec;
use kind_syntax::concrete::{Block, Stmt};
use kind_syntax::lexemes::{Brace, Token};
use crate::{FmtContext, Result};
impl<'a> FmtContext<'a> {
pub fn statements(&mut self) -> Result<Block> {
match self.kind() {
"statements" => {
let statements = self
.named_children()
.map(|node| self.cursor(node).expr())
.collect::<Result<ThinVec<_>>>()?;
Ok(Brace(
Token::default(),
statements
.iter()
.map(|expr| Stmt {
value: expr.clone(),
semi: None,
})
.collect(),
Token::default(),
))
}
kind => todo!("{}", kind),
}
}
}

View File

@ -0,0 +1,37 @@
use thin_vec::thin_vec;
use kind_syntax::concrete::{Signature, TopLevel, TopLevelKind};
use kind_syntax::lexemes::{Colon, Item, Span, Token};
use crate::{FmtContext, Result};
impl<'a> FmtContext<'a> {
pub fn top_level(&mut self) -> Result<TopLevel> {
match self.kind() {
"val_declaration" => {
let name = self.find("name", |node| self.cursor(node).name())?.unwrap();
let value = self.find("value", |node| self.cursor(node).statements())?;
let parameters = self
.properties("parameters")
.map(|node| self.cursor(node).parameter())
.collect::<Result<_>>()?;
let return_type = self.find("return_type", |node| {
let value = self.cursor(node).expr()?;
Ok(Colon(Token::default(), value))
})?;
Ok(TopLevel {
data: Item::new(
Span::default(),
TopLevelKind::Signature(Signature {
name,
parameters,
return_type,
value,
}),
),
attributes: thin_vec![],
})
}
kind => todo!("{}", kind),
}
}
}

View File

@ -0,0 +1,32 @@
use crate::concrete::{ConstructorExpr, Expr, ExprKind, LocalExpr};
use crate::lexemes::{Name, Span};
impl Expr {
pub fn constructor(span: Span, name: Name) -> Self {
Expr::new(
span,
ExprKind::Constructor(Box::new(ConstructorExpr { name })),
)
}
pub fn local(span: Span, name: Name) -> Self {
Expr::new(span, ExprKind::Local(Box::new(LocalExpr { name })))
}
}
//
// macro_rules! impl_expr_kind {
// ( $( $name:ident( $( $arg:ident: $ty:ty ),* ) ),* ) => {
// impl Expr {
// $(pub fn $name($($arg: $ty),* span: Span) -> Self {
// Expr::new(
// span,
// ExprKind::$name(Box::new($name Expr { $($arg),* })))
// })*
// }
// };
// }
//
// impl_expr_kind!(
// Local( name: Name, ),
// Constructor( name: Name, ),
// );

View File

@ -41,22 +41,22 @@ pub type Attribute = Item<AttributeKind>;
/// A type binding is a type annotation for a variable.
#[derive(Debug, Clone, PartialEq)]
pub struct TypeBinding {
pub name: Ident,
pub typ: Colon<Box<Expr>>,
pub name: Name,
pub binding_type: Option<Colon<Box<Expr>>>,
}
#[derive(Debug, Clone, PartialEq)]
pub enum ArgumentBinding {
Implicit(AngleBracket<Param>),
Explicit(Paren<Param>),
pub enum ParameterBinding {
Implicit(AngleBracket<TypeBinding>),
Explicit(Paren<TypeBinding>),
}
/// An argument of a type signature.
#[derive(Debug, Clone, PartialEq)]
pub struct Argument {
pub minus: Option<lexemes::Minus>,
pub plus: Option<lexemes::Plus>,
pub binding: ArgumentBinding,
pub enum SignatureParameter {
Exclude(ParameterBinding),
Include(ParameterBinding),
Both(ParameterBinding),
}
/// A local expression is a reference atom to a local declaration.
@ -79,9 +79,8 @@ pub struct ConstructorExpr {
/// (x : Int)
/// // or
/// x
/// ```
#[derive(Debug, Clone, PartialEq)]
pub enum Param {
pub enum PiParameter {
Named(Paren<TypeBinding>),
Expr(Box<Expr>),
}
@ -90,7 +89,7 @@ pub enum Param {
#[derive(Debug, Clone, PartialEq)]
pub struct PiExpr {
pub r#tilde: lexemes::Tilde,
pub param: Param,
pub param: PiParameter,
pub r#arrow: lexemes::RightArrow,
pub body: Box<Expr>,
}
@ -109,7 +108,7 @@ pub struct SigmaExpr {
#[derive(Debug, Clone, PartialEq)]
pub struct LambdaExpr {
pub r#tilde: Option<lexemes::Tilde>,
pub param: Param,
pub param: PiParameter,
pub r#arrow: lexemes::FatArrow,
pub body: Box<Expr>,
}
@ -309,7 +308,7 @@ pub struct CaseNode {
pub struct MatchExpr {
pub r#match: lexemes::Match,
pub typ: Option<Ident>,
pub with: Option<(lexemes::With, ThinVec<Param>)>,
pub with: Option<(lexemes::With, ThinVec<PiParameter>)>,
pub scrutinee: Box<Expr>,
pub cases: Brace<ThinVec<CaseNode>>,
pub motive: Option<Colon<Box<Expr>>>,
@ -387,7 +386,7 @@ pub type Expr = Item<ExprKind>;
#[derive(Debug, Clone, PartialEq)]
pub struct ConstructorPat {
pub name: QualifiedIdent,
pub args: ThinVec<Argument>,
pub args: ThinVec<SignatureParameter>,
}
/// A pattern is part of a rule. It is a structure that matches an expression.
@ -411,7 +410,7 @@ pub type Pat = Item<PatKind>;
#[derive(Debug, Clone, PartialEq)]
pub struct Signature {
pub name: Name,
pub arguments: ThinVec<Argument>,
pub parameters: ThinVec<SignatureParameter>,
pub return_type: Option<Colon<Expr>>,
pub value: Option<Block>,
}
@ -440,7 +439,7 @@ pub struct Rule {
#[derive(Debug, Clone, PartialEq)]
pub struct Function {
pub name: Ident,
pub arguments: ThinVec<Argument>,
pub arguments: ThinVec<SignatureParameter>,
pub return_typ: Option<Colon<Expr>>,
pub value: Brace<Expr>,
}
@ -468,7 +467,7 @@ pub struct Command {
#[derive(Debug, Clone, PartialEq)]
pub struct Constructor {
pub name: Ident,
pub arguments: ThinVec<Argument>,
pub arguments: ThinVec<SignatureParameter>,
pub typ: Option<Colon<ThinVec<Expr>>>,
}
@ -478,8 +477,8 @@ pub struct Constructor {
pub struct TypeDef {
pub name: QualifiedIdent,
pub constructors: ThinVec<Constructor>,
pub params: ThinVec<Argument>,
pub indices: ThinVec<Argument>,
pub params: ThinVec<SignatureParameter>,
pub indices: ThinVec<SignatureParameter>,
}
/// A record definition is a top-level structure that defines a type with
@ -488,8 +487,8 @@ pub struct TypeDef {
pub struct RecordDef {
pub name: QualifiedIdent,
pub fields: ThinVec<TypeBinding>,
pub params: ThinVec<Argument>,
pub indices: ThinVec<Argument>,
pub params: ThinVec<SignatureParameter>,
pub indices: ThinVec<SignatureParameter>,
}
/// A top-level item is a item that is on the outermost level of a

View File

@ -4,3 +4,4 @@
pub mod concrete;
pub mod core;
pub mod lexemes;
pub mod builders;