Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
Xanewok committed Apr 4, 2024
1 parent 3da3eaa commit 787cf3c
Show file tree
Hide file tree
Showing 14 changed files with 421 additions and 433 deletions.
49 changes: 13 additions & 36 deletions crates/codegen/parser/runtime/src/napi_interface/cst.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
use std::rc::Rc;

use napi::bindgen_prelude::Env;
use napi::JsObject;
use napi_derive::napi;

use crate::napi_interface::cursor::Cursor;
Expand All @@ -16,6 +14,16 @@ pub enum NodeType {
Token,
}

impl RustNode {
/// Converts a Rust node into a choice of NAPI-exposed wrapper structs.
pub fn into_either(self) -> napi::Either<RuleNode, TokenNode> {
match self {
RustNode::Rule(rule) => napi::Either::A(RuleNode(rule)),
RustNode::Token(token) => napi::Either::B(TokenNode(token)),
}
}
}

#[napi(namespace = "cst")]
pub struct RuleNode(pub(crate) Rc<RustRuleNode>);

Expand Down Expand Up @@ -49,12 +57,12 @@ impl RuleNode {
(&self.0.text_len).into()
}

#[napi(ts_return_type = "Array<cst.Node>", catch_unwind)]
pub fn children(&self, env: Env) -> Vec<JsObject> {
#[napi(catch_unwind)]
pub fn children(&self) -> Vec<napi::Either<RuleNode, TokenNode>> {
self.0
.children
.iter()
.map(|child| child.to_js(env))
.map(|child| child.node.clone().into_either())
.collect()
}

Expand Down Expand Up @@ -117,34 +125,3 @@ impl TokenNode {
.into()
}
}

pub(crate) trait ToJS {
fn to_js(&self, env: Env) -> JsObject;
}

impl ToJS for Rc<RustRuleNode> {
fn to_js(&self, env: Env) -> JsObject {
RuleNode(self.clone())
.into_instance(env)
.expect("Class constructor to be defined by #[napi]")
.as_object(env)
}
}

impl ToJS for Rc<RustTokenNode> {
fn to_js(&self, env: Env) -> JsObject {
TokenNode(self.clone())
.into_instance(env)
.expect("Class constructor to be defined by #[napi]")
.as_object(env)
}
}

impl ToJS for RustNode {
fn to_js(&self, env: Env) -> JsObject {
match self {
RustNode::Rule(rust_rule_node) => rust_rule_node.to_js(env),
RustNode::Token(rust_token_node) => rust_token_node.to_js(env),
}
}
}
10 changes: 4 additions & 6 deletions crates/codegen/parser/runtime/src/napi_interface/cursor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,11 @@
// The functions are meant to be definitions for export, so they're not really used
#![allow(clippy::return_self_not_must_use)]

use cst::ToJS;
use napi::bindgen_prelude::Env;
use napi::JsObject;
use napi_derive::napi;
use text_index::{TextIndex, TextRange};

use crate::napi_interface::{cst, text_index, NodeLabel, RuleKind, RustCursor, TokenKind};
use crate::napi_interface::cst::{self, RuleNode, TokenNode};
use crate::napi_interface::{text_index, NodeLabel, RuleKind, RustCursor, TokenKind};

#[napi(namespace = "cursor")]
pub struct Cursor(pub(super) RustCursor);
Expand Down Expand Up @@ -53,8 +51,8 @@ impl Cursor {
}

#[napi(ts_return_type = "cst.Node", catch_unwind)]
pub fn node(&self, env: Env) -> JsObject {
self.0.node().to_js(env)
pub fn node(&self) -> napi::Either<RuleNode, TokenNode> {
self.0.node().into_either()
}

#[napi(getter, ts_return_type = "kinds.NodeLabel", catch_unwind)]
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
use cst::ToJS;
use napi::bindgen_prelude::Env;
use napi_derive::napi;

use crate::napi_interface::{cst, cursor, parse_error, RustParseOutput};
Expand All @@ -16,8 +14,8 @@ impl From<RustParseOutput> for ParseOutput {
#[napi(namespace = "parse_output")]
impl ParseOutput {
#[napi(ts_return_type = "cst.Node", catch_unwind)]
pub fn tree(&self, env: Env) -> napi::JsObject {
self.0.tree().to_js(env)
pub fn tree(&self) -> napi::Either<cst::RuleNode, cst::TokenNode> {
self.0.tree().into_either()
}

#[napi(ts_return_type = "Array<parse_error.ParseError>", catch_unwind)]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,9 @@

use std::rc::Rc;

use napi::{Env, JsObject};
use napi_derive::napi;

use crate::napi_interface::cst::{RuleNode, ToJS};
use crate::napi_interface::cst::{RuleNode, TokenNode};
use crate::napi_interface::{RuleKind, RustLabeledNode, RustNode, RustRuleNode, TokenKind};

//
Expand All @@ -19,9 +18,8 @@ use crate::napi_interface::{RuleKind, RustLabeledNode, RustNode, RustRuleNode, T
)]
pub fn select_sequence(
#[napi(ts_arg_type = "cst.RuleNode")] node: &RuleNode,
env: Env,
) -> Result<Vec<Option<JsObject>>> {
let mut selector = Selector::new(node, env);
) -> Result<Vec<Option<napi::Either<RuleNode, TokenNode>>>> {
let mut selector = Selector::new(node);

let result = match node.kind() {
{%- for sequence in ast_model.sequences -%}
Expand All @@ -40,7 +38,7 @@ pub fn select_sequence(

{% for sequence in ast_model.sequences %}
impl Selector {
fn {{ sequence.name | snake_case }}(&mut self) -> Result<Vec<Option<JsObject>>> {
fn {{ sequence.name | snake_case }}(&mut self) -> Result<Vec<Option<napi::Either<RuleNode, TokenNode>>>> {
Ok(vec![
{%- for field in sequence.fields -%}
{%- if field.is_optional -%}
Expand Down Expand Up @@ -81,9 +79,8 @@ pub fn select_sequence(
)]
pub fn select_choice(
#[napi(ts_arg_type = "cst.RuleNode")] node: &RuleNode,
env: Env,
) -> Result<JsObject> {
let mut selector = Selector::new(node, env);
) -> Result<napi::Either<RuleNode, TokenNode>> {
let mut selector = Selector::new(node);

let result = match node.kind() {
{%- for choice in ast_model.choices -%}
Expand All @@ -102,7 +99,7 @@ pub fn select_choice(

{% for choice in ast_model.choices %}
impl Selector {
fn {{ choice.name | snake_case }}(&mut self) -> Result<JsObject> {
fn {{ choice.name | snake_case }}(&mut self) -> Result<napi::Either<RuleNode, TokenNode>> {
self.select(|node| {
{%- set non_terminals_len = choice.non_terminals | length -%}
{%- set terminals_len = choice.terminals | length -%}
Expand Down Expand Up @@ -146,9 +143,8 @@ pub fn select_choice(
)]
pub fn select_repeated(
#[napi(ts_arg_type = "cst.RuleNode")] node: &RuleNode,
env: Env,
) -> Result<Vec<JsObject>> {
let mut selector = Selector::new(node, env);
) -> Result<Vec<napi::Either<RuleNode, TokenNode>>> {
let mut selector = Selector::new(node);

let result = match node.kind() {
{%- for repeated in ast_model.repeated -%}
Expand All @@ -167,7 +163,7 @@ pub fn select_repeated(

{% for repeated in ast_model.repeated %}
impl Selector {
fn {{ repeated.name | snake_case }}(&mut self) -> Result<Vec<JsObject>> {
fn {{ repeated.name | snake_case }}(&mut self) -> Result<Vec<napi::Either<RuleNode, TokenNode>>> {
let mut items = vec![];

while let Some(item) = self.try_select(|node| {
Expand Down Expand Up @@ -196,9 +192,8 @@ pub fn select_repeated(
)]
pub fn select_separated(
#[napi(ts_arg_type = "cst.RuleNode")] node: &RuleNode,
env: Env,
) -> Result<Vec<Vec<JsObject>>> {
let mut selector = Selector::new(node, env);
) -> Result<Vec<Vec<napi::Either<RuleNode, TokenNode>>>> {
let mut selector = Selector::new(node);

let result = match node.kind() {
{%- for separated in ast_model.separated -%}
Expand All @@ -217,7 +212,7 @@ pub fn select_separated(

{% for separated in ast_model.separated %}
impl Selector {
fn {{ separated.name | snake_case }}(&mut self) -> Result<Vec<Vec<JsObject>>> {
fn {{ separated.name | snake_case }}(&mut self) -> Result<Vec<Vec<napi::Either<RuleNode, TokenNode>>>> {
let mut separated = vec![];
let mut separators = vec![];

Expand Down Expand Up @@ -253,28 +248,26 @@ pub fn select_separated(
//

struct Selector {
env: Env,
node: Rc<RustRuleNode>,
index: usize,
}

impl Selector {
fn new(node: &RuleNode, env: Env) -> Self {
fn new(node: &RuleNode) -> Self {
Self {
env,
node: node.0.clone(),
index: 0,
}
}

fn select(&mut self, filter: impl FnOnce(&RustNode) -> bool) -> Result<JsObject> {
fn select(&mut self, filter: impl FnOnce(&RustNode) -> bool) -> Result<napi::Either<RuleNode, TokenNode>> {
match self.try_select(filter)? {
Some(node) => Ok(node),
None => Error::MissingChild(self.index).into(),
}
}

fn try_select(&mut self, filter: impl FnOnce(&RustNode) -> bool) -> Result<Option<JsObject>> {
fn try_select(&mut self, filter: impl FnOnce(&RustNode) -> bool) -> Result<Option<napi::Either<RuleNode, TokenNode>>> {
while let Some(child) = self.node.children.get(self.index) {
match child {
node if node.is_trivia() => {
Expand All @@ -288,9 +281,9 @@ impl Selector {
} if matches!(token.kind, TokenKind::SKIPPED) => {
return Error::SkippedToken(self.index).into();
}
node if filter(node) => {
labeled if filter(labeled) => {
self.index += 1;
return Ok(Some(node.to_js(self.env)));
return Ok(Some(labeled.node.clone().into_either()));
}
_ => {
break;
Expand Down
Loading

0 comments on commit 787cf3c

Please sign in to comment.