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 kind_syntax::concrete::Module;
use tree_sitter::{Parser, Tree, TreeCursor}; use kind_syntax::lexemes::Token;
use kind_syntax::concrete::{Block, ConstructorExpr, Expr, ExprKind, LocalExpr, Module, Pat, PatKind, Rule, Signature, Stmt, TopLevel, TopLevelKind}; mod expr;
use kind_syntax::lexemes::{Brace, Colon, Equal, Ident, Item, Name, Span, Token, Tokenized}; mod name;
mod parameter;
mod pattern;
mod primary;
mod statements;
mod top_level;
#[derive(Debug)] #[derive(Debug)]
pub enum FmtError { pub enum FmtError {
IoError(std::io::Error), IoError(std::io::Error),
Utf8Error(std::str::Utf8Error),
TreeSitterLanguageError(tree_sitter::LanguageError), TreeSitterLanguageError(tree_sitter::LanguageError),
TreeSitterQueryError(tree_sitter::QueryError), TreeSitterQueryError(tree_sitter::QueryError),
UnknownParseError, 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 type Result<T> = std::result::Result<T, FmtError>;
pub fn run_fmt(string: String) -> Result<Module> { pub fn run_fmt(string: String) -> Result<Module> {
@ -21,7 +35,7 @@ pub fn run_fmt(string: String) -> Result<Module> {
parser parser
.set_language(tree_sitter_kind::language()) .set_language(tree_sitter_kind::language())
.map_err(FmtError::TreeSitterLanguageError)?; .map_err(FmtError::TreeSitterLanguageError)?;
let tree = parser let mut tree = parser
.parse(string.as_bytes(), None) .parse(string.as_bytes(), None)
.ok_or(FmtError::UnknownParseError)?; .ok_or(FmtError::UnknownParseError)?;
@ -29,10 +43,16 @@ pub fn run_fmt(string: String) -> Result<Module> {
let mut cursor = tree.root_node().walk(); let mut cursor = tree.root_node().walk();
let declarations = tree.root_node().children(&mut cursor) let context = FmtContext {
.map(|node| { file: &string,
specialize_top_level(&string, &tree, &mut node.walk()) tree: &tree,
}) cursor: &mut cursor,
};
let declarations = tree
.root_node()
.children(&mut cursor)
.map(|node| context.cursor(node).top_level())
.collect::<Result<ThinVec<_>>>()?; .collect::<Result<ThinVec<_>>>()?;
Ok(Module { 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> { impl<'a> FmtContext<'a> {
let node = cursor.node(); pub fn node(&self) -> Node<'a> {
match node.kind() { unsafe { (*self.cursor).node() }
"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");
Ok(TopLevel { pub fn get_current_cursor(&self) -> TreeCursor<'a> {
data: Item::new( unsafe { (*self.cursor).clone() }
Span::default(), }
TopLevelKind::Signature(Signature {
name: specialize_name(file, tree, &mut name.walk())?, pub fn kind(&self) -> &'static str {
arguments: thin_vec![], self.node().kind()
return_type: return_type.map_or(Ok(None), |node| { }
let expr = specialize_expr(file, tree, &mut node.walk())?;
Ok(Some(Colon(Token::default(), expr))) pub fn first(&self) -> Option<Node<'a>> {
})?, self.node().child(0)
value: value.map_or(Ok(None), |node| { }
let block = specialize_statements(file, tree, &mut node.walk())?;
Ok(Some(block)) pub fn at(&self, at: usize) -> Option<Node<'a>> {
})?, self.node().child(at)
}), }
),
attributes: thin_vec![], 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> { pub fn named_children(&self) -> impl Iterator<Item = Node<'a>> + '_ {
let node = cursor.node(); unsafe {
match node.kind() { self.node().named_children(self.cursor.as_mut().unwrap())
"identifier" => {
specialize_name(file, tree, cursor)
.map(|name| Pat::new(
Span::default(),
PatKind::Name(name),
))
} }
"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> { pub fn children(&self) -> impl Iterator<Item = Node<'a>> + '_ {
let node = cursor.node(); let mut cursor = self.get_current_cursor();
match node.kind() {
"call" => {
let callee = node
.child_by_field_name("callee")
.unwrap();
specialize_primary(file, tree, &mut callee.walk()) cursor.reset(self.node());
}, cursor.goto_first_child();
kind => todo!("{}", kind), (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> { pub fn text(&self) -> Result<&'a str> {
let node = cursor.node(); self.node()
match node.kind() { .utf8_text(self.file.as_bytes())
"identifier" => { .map_err(FmtError::Utf8Error)
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),
} }
}
fn specialize_statements(file: &String, tree: &Tree, cursor: &mut TreeCursor) -> Result<Block> { pub fn text_of(&self, node: Node<'_>) -> Result<&'a str> {
let node = cursor.node(); node.utf8_text(self.file.as_bytes())
match node.kind() { .map_err(FmtError::Utf8Error)
"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),
} }
}
fn specialize_primary(file: &String, tree: &Tree, cursor: &mut TreeCursor) -> Result<Expr> { pub fn cursor<'b>(&'b self, node: Node<'b>) -> FmtContext<'b> {
let node = cursor.node(); // fix this leak
match node.kind() { let cursor = Box::leak(Box::new(node.walk()));
"constructor_identifier" => { FmtContext {
specialize_name(file, tree, cursor) file: self.file,
.map(|name| Expr::new( tree: self.tree,
Span::default(), cursor,
ExprKind::Constructor(Box::new(ConstructorExpr {
name,
})),
))
} }
"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] #[test]
fn it_works() { 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); 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. /// A type binding is a type annotation for a variable.
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
pub struct TypeBinding { pub struct TypeBinding {
pub name: Ident, pub name: Name,
pub typ: Colon<Box<Expr>>, pub binding_type: Option<Colon<Box<Expr>>>,
} }
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
pub enum ArgumentBinding { pub enum ParameterBinding {
Implicit(AngleBracket<Param>), Implicit(AngleBracket<TypeBinding>),
Explicit(Paren<Param>), Explicit(Paren<TypeBinding>),
} }
/// An argument of a type signature. /// An argument of a type signature.
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
pub struct Argument { pub enum SignatureParameter {
pub minus: Option<lexemes::Minus>, Exclude(ParameterBinding),
pub plus: Option<lexemes::Plus>, Include(ParameterBinding),
pub binding: ArgumentBinding, Both(ParameterBinding),
} }
/// A local expression is a reference atom to a local declaration. /// A local expression is a reference atom to a local declaration.
@ -79,9 +79,8 @@ pub struct ConstructorExpr {
/// (x : Int) /// (x : Int)
/// // or /// // or
/// x /// x
/// ```
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
pub enum Param { pub enum PiParameter {
Named(Paren<TypeBinding>), Named(Paren<TypeBinding>),
Expr(Box<Expr>), Expr(Box<Expr>),
} }
@ -90,7 +89,7 @@ pub enum Param {
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
pub struct PiExpr { pub struct PiExpr {
pub r#tilde: lexemes::Tilde, pub r#tilde: lexemes::Tilde,
pub param: Param, pub param: PiParameter,
pub r#arrow: lexemes::RightArrow, pub r#arrow: lexemes::RightArrow,
pub body: Box<Expr>, pub body: Box<Expr>,
} }
@ -109,7 +108,7 @@ pub struct SigmaExpr {
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
pub struct LambdaExpr { pub struct LambdaExpr {
pub r#tilde: Option<lexemes::Tilde>, pub r#tilde: Option<lexemes::Tilde>,
pub param: Param, pub param: PiParameter,
pub r#arrow: lexemes::FatArrow, pub r#arrow: lexemes::FatArrow,
pub body: Box<Expr>, pub body: Box<Expr>,
} }
@ -309,7 +308,7 @@ pub struct CaseNode {
pub struct MatchExpr { pub struct MatchExpr {
pub r#match: lexemes::Match, pub r#match: lexemes::Match,
pub typ: Option<Ident>, pub typ: Option<Ident>,
pub with: Option<(lexemes::With, ThinVec<Param>)>, pub with: Option<(lexemes::With, ThinVec<PiParameter>)>,
pub scrutinee: Box<Expr>, pub scrutinee: Box<Expr>,
pub cases: Brace<ThinVec<CaseNode>>, pub cases: Brace<ThinVec<CaseNode>>,
pub motive: Option<Colon<Box<Expr>>>, pub motive: Option<Colon<Box<Expr>>>,
@ -387,7 +386,7 @@ pub type Expr = Item<ExprKind>;
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
pub struct ConstructorPat { pub struct ConstructorPat {
pub name: QualifiedIdent, 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. /// 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)] #[derive(Debug, Clone, PartialEq)]
pub struct Signature { pub struct Signature {
pub name: Name, pub name: Name,
pub arguments: ThinVec<Argument>, pub parameters: ThinVec<SignatureParameter>,
pub return_type: Option<Colon<Expr>>, pub return_type: Option<Colon<Expr>>,
pub value: Option<Block>, pub value: Option<Block>,
} }
@ -440,7 +439,7 @@ pub struct Rule {
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
pub struct Function { pub struct Function {
pub name: Ident, pub name: Ident,
pub arguments: ThinVec<Argument>, pub arguments: ThinVec<SignatureParameter>,
pub return_typ: Option<Colon<Expr>>, pub return_typ: Option<Colon<Expr>>,
pub value: Brace<Expr>, pub value: Brace<Expr>,
} }
@ -468,7 +467,7 @@ pub struct Command {
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
pub struct Constructor { pub struct Constructor {
pub name: Ident, pub name: Ident,
pub arguments: ThinVec<Argument>, pub arguments: ThinVec<SignatureParameter>,
pub typ: Option<Colon<ThinVec<Expr>>>, pub typ: Option<Colon<ThinVec<Expr>>>,
} }
@ -478,8 +477,8 @@ pub struct Constructor {
pub struct TypeDef { pub struct TypeDef {
pub name: QualifiedIdent, pub name: QualifiedIdent,
pub constructors: ThinVec<Constructor>, pub constructors: ThinVec<Constructor>,
pub params: ThinVec<Argument>, pub params: ThinVec<SignatureParameter>,
pub indices: ThinVec<Argument>, pub indices: ThinVec<SignatureParameter>,
} }
/// A record definition is a top-level structure that defines a type with /// A record definition is a top-level structure that defines a type with
@ -488,8 +487,8 @@ pub struct TypeDef {
pub struct RecordDef { pub struct RecordDef {
pub name: QualifiedIdent, pub name: QualifiedIdent,
pub fields: ThinVec<TypeBinding>, pub fields: ThinVec<TypeBinding>,
pub params: ThinVec<Argument>, pub params: ThinVec<SignatureParameter>,
pub indices: ThinVec<Argument>, pub indices: ThinVec<SignatureParameter>,
} }
/// A top-level item is a item that is on the outermost level of a /// 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 concrete;
pub mod core; pub mod core;
pub mod lexemes; pub mod lexemes;
pub mod builders;