mirror of
https://github.com/danbulant/oxc
synced 2026-05-24 20:32:10 +00:00
feat(semantic): add semantic builder with untyped ast tree creation
This commit is contained in:
parent
0de5020d07
commit
5f7a756229
10 changed files with 234 additions and 0 deletions
14
Cargo.lock
generated
14
Cargo.lock
generated
|
|
@ -493,6 +493,12 @@ dependencies = [
|
|||
"hashbrown",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "indextree"
|
||||
version = "4.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "497f036ac2fae75c34224648a77802e5dd4e9cfb56f4713ab6b12b7160a0523b"
|
||||
|
||||
[[package]]
|
||||
name = "io-lifetimes"
|
||||
version = "1.0.5"
|
||||
|
|
@ -838,6 +844,14 @@ dependencies = [
|
|||
"oxc_parser",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "oxc_semantic"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"indextree",
|
||||
"oxc_ast",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "percent-encoding"
|
||||
version = "2.2.0"
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ serde_json = "1.0.93"
|
|||
thiserror = "1.0.38"
|
||||
jemallocator = "0.5.0"
|
||||
clap = "4.1.4"
|
||||
indextree = "4.5.0"
|
||||
|
||||
[profile.release]
|
||||
lto = "fat"
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ pub mod span;
|
|||
pub mod syntax_directed_operations;
|
||||
pub mod visit;
|
||||
|
||||
pub use ast_kind::AstKind;
|
||||
pub use num_bigint::BigUint;
|
||||
|
||||
pub use crate::ast_builder::*;
|
||||
|
|
|
|||
15
crates/oxc_semantic/Cargo.toml
Normal file
15
crates/oxc_semantic/Cargo.toml
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
[package]
|
||||
name = "oxc_semantic"
|
||||
authors.workspace = true
|
||||
description.workspace = true
|
||||
edition.workspace = true
|
||||
homepage.workspace = true
|
||||
keywords.workspace = true
|
||||
license.workspace = true
|
||||
repository.workspace = true
|
||||
version.workspace = true
|
||||
|
||||
[dependencies]
|
||||
oxc_ast = { path = "../oxc_ast" }
|
||||
|
||||
indextree = { workspace = true }
|
||||
10
crates/oxc_semantic/src/Cargo.toml
Normal file
10
crates/oxc_semantic/src/Cargo.toml
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
[package]
|
||||
name = "oxc_printer"
|
||||
authors.workspace = true
|
||||
description.workspace = true
|
||||
edition.workspace = true
|
||||
homepage.workspace = true
|
||||
keywords.workspace = true
|
||||
license.workspace = true
|
||||
repository.workspace = true
|
||||
version.workspace = true
|
||||
56
crates/oxc_semantic/src/builder.rs
Normal file
56
crates/oxc_semantic/src/builder.rs
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
//! Semantic Builder
|
||||
//! This builds:
|
||||
//! * The untyped and flattened ast nodes into an indextree
|
||||
|
||||
use oxc_ast::{ast::Program, visit::Visit, AstKind};
|
||||
|
||||
use crate::{
|
||||
node::{AstNodeId, AstNodes, SemanticNode},
|
||||
Semantic,
|
||||
};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct SemanticBuilder<'a> {
|
||||
nodes: AstNodes<'a>,
|
||||
current_node_id: AstNodeId,
|
||||
}
|
||||
|
||||
impl<'a> SemanticBuilder<'a> {
|
||||
#[must_use]
|
||||
#[allow(clippy::new_without_default)]
|
||||
pub fn new() -> Self {
|
||||
let mut nodes = AstNodes::default();
|
||||
let semantic_node = SemanticNode::new(AstKind::Root);
|
||||
let current_node_id = nodes.new_node(semantic_node).into();
|
||||
Self { nodes, current_node_id }
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn build(mut self, program: &'a Program<'a>) -> Semantic<'a> {
|
||||
// AST pass
|
||||
self.visit_program(program);
|
||||
Semantic { nodes: self.nodes }
|
||||
}
|
||||
|
||||
fn create_ast_node(&mut self, kind: AstKind<'a>) {
|
||||
let ast_node = SemanticNode::new(kind);
|
||||
let node_id = self.nodes.new_node(ast_node);
|
||||
self.current_node_id.append(node_id, &mut self.nodes);
|
||||
self.current_node_id = node_id.into();
|
||||
}
|
||||
|
||||
fn pop_ast_node(&mut self) {
|
||||
self.current_node_id =
|
||||
self.nodes[self.current_node_id.indextree_id()].parent().unwrap().into();
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Visit<'a> for SemanticBuilder<'a> {
|
||||
fn enter_node(&mut self, kind: AstKind<'a>) {
|
||||
self.create_ast_node(kind);
|
||||
}
|
||||
|
||||
fn leave_node(&mut self, _kind: AstKind<'a>) {
|
||||
self.pop_ast_node();
|
||||
}
|
||||
}
|
||||
16
crates/oxc_semantic/src/lib.rs
Normal file
16
crates/oxc_semantic/src/lib.rs
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
mod builder;
|
||||
mod node;
|
||||
|
||||
pub use builder::SemanticBuilder;
|
||||
use node::AstNodes;
|
||||
|
||||
pub struct Semantic<'a> {
|
||||
nodes: AstNodes<'a>,
|
||||
}
|
||||
|
||||
impl<'a> Semantic<'a> {
|
||||
#[must_use]
|
||||
pub const fn nodes(&self) -> &AstNodes<'a> {
|
||||
&self.nodes
|
||||
}
|
||||
}
|
||||
38
crates/oxc_semantic/src/node/id.rs
Normal file
38
crates/oxc_semantic/src/node/id.rs
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
use std::ops::Deref;
|
||||
|
||||
use indextree::NodeId;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub struct AstNodeId(NodeId);
|
||||
|
||||
impl AstNodeId {
|
||||
#[must_use]
|
||||
pub const fn new(node_id: NodeId) -> Self {
|
||||
Self(node_id)
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub const fn indextree_id(&self) -> NodeId {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl From<NodeId> for AstNodeId {
|
||||
fn from(node_id: NodeId) -> Self {
|
||||
Self(node_id)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<AstNodeId> for NodeId {
|
||||
fn from(ast_node_id: AstNodeId) -> Self {
|
||||
ast_node_id.indextree_id()
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for AstNodeId {
|
||||
type Target = NodeId;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
27
crates/oxc_semantic/src/node/mod.rs
Normal file
27
crates/oxc_semantic/src/node/mod.rs
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
mod id;
|
||||
mod tree;
|
||||
|
||||
pub use id::AstNodeId;
|
||||
use oxc_ast::AstKind;
|
||||
pub use tree::AstNodes;
|
||||
|
||||
/// Indextree node containing a semantic node
|
||||
pub type AstNode<'a> = indextree::Node<SemanticNode<'a>>;
|
||||
|
||||
/// Semantic node contains all the semantic information about an ast node.
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct SemanticNode<'a> {
|
||||
/// A pointer to the ast node, which resides in the `bumpalo` memory arena.
|
||||
kind: AstKind<'a>,
|
||||
}
|
||||
|
||||
impl<'a> SemanticNode<'a> {
|
||||
#[must_use]
|
||||
pub const fn new(kind: AstKind<'a>) -> Self {
|
||||
Self { kind }
|
||||
}
|
||||
|
||||
pub const fn kind(&self) -> AstKind<'a> {
|
||||
self.kind
|
||||
}
|
||||
}
|
||||
56
crates/oxc_semantic/src/node/tree.rs
Normal file
56
crates/oxc_semantic/src/node/tree.rs
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
use std::ops::{Deref, DerefMut, Index, IndexMut};
|
||||
|
||||
use indextree::{Arena, NodeId};
|
||||
|
||||
use super::{AstNode, AstNodeId, SemanticNode};
|
||||
|
||||
/// Untyped AST nodes flattened into an indextree
|
||||
#[derive(Debug, Default)]
|
||||
pub struct AstNodes<'a> {
|
||||
/// The memory storage of the indextree is backed by a vector,
|
||||
/// which allows for efficient traversal.
|
||||
/// This also allows for parallel traversal by using `rayon`.
|
||||
nodes: Arena<SemanticNode<'a>>,
|
||||
}
|
||||
|
||||
impl<'a> Index<NodeId> for AstNodes<'a> {
|
||||
type Output = AstNode<'a>;
|
||||
|
||||
fn index(&self, id: NodeId) -> &Self::Output {
|
||||
&self.nodes[id]
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> IndexMut<NodeId> for AstNodes<'a> {
|
||||
fn index_mut(&mut self, id: NodeId) -> &mut AstNode<'a> {
|
||||
&mut self.nodes[id]
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Index<AstNodeId> for AstNodes<'a> {
|
||||
type Output = SemanticNode<'a>;
|
||||
|
||||
fn index(&self, id: AstNodeId) -> &Self::Output {
|
||||
self.nodes[id.indextree_id()].get()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> IndexMut<AstNodeId> for AstNodes<'a> {
|
||||
fn index_mut(&mut self, id: AstNodeId) -> &mut SemanticNode<'a> {
|
||||
self.nodes[id.indextree_id()].get_mut()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Deref for AstNodes<'a> {
|
||||
type Target = Arena<SemanticNode<'a>>;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.nodes
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> DerefMut for AstNodes<'a> {
|
||||
fn deref_mut(&mut self) -> &mut Arena<SemanticNode<'a>> {
|
||||
&mut self.nodes
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue