Skip to content

Commit

Permalink
add emmylua_parser test
Browse files Browse the repository at this point in the history
  • Loading branch information
CppCXY committed Oct 30, 2024
1 parent 257c63a commit 9362db1
Show file tree
Hide file tree
Showing 10 changed files with 303 additions and 119 deletions.
49 changes: 48 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,5 @@ lazy_static = "1.4.0"
encoding_rs = "0.8"
tokio = { version = "1.40.0", features = ["full"] }
notify = { version = "6.1.1", features = ["serde"] }
emmylua_parser = "0.3"
rowan = { version = "0.15.16" }
3 changes: 2 additions & 1 deletion crates/basic/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ lazy_static.workspace = true
encoding_rs.workspace = true
tokio.workspace = true
notify.workspace = true

emmylua_parser.workspace = true
rowan.workspace = true

[build-dependencies]
cc = "1.0"
Expand Down
4 changes: 3 additions & 1 deletion crates/basic/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ mod codestyle;
mod lpeglabel;
mod lua_seri;
mod override_lua;
mod parser;

#[macro_use]
extern crate lazy_static;
Expand All @@ -20,11 +21,12 @@ pub fn lua_preload(lua: &Lua) -> LuaResult<()> {
// codestyle
codestyle::register_code_format_module(lua)?;

parser::register_parser_module(lua)?;

add_package_path(
&lua,
vec![
"resources/?.lua;resources/?/init.lua;",
// "resources/override_script/?.lua;resources/override_script/?/init.lua;",
"resources/script/?.lua;resources/script/?/init.lua",
],
)?;
Expand Down
157 changes: 157 additions & 0 deletions crates/basic/src/parser/lua_node.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
use emmylua_parser::{LuaSyntaxKind, LuaSyntaxNode, LuaSyntaxToken, LuaTokenKind};
use mlua::prelude::*;

pub enum LuaNodeWrapper {
Node(LuaSyntaxNode),
Token(LuaSyntaxToken),
}

impl LuaNodeWrapper {
pub fn new(node: LuaSyntaxNode) -> Self {
Self::Node(node)
}

pub fn from_node_or_token(
node_or_token: rowan::NodeOrToken<LuaSyntaxNode, LuaSyntaxToken>,
) -> Self {
match node_or_token {
rowan::NodeOrToken::Node(node) => Self::Node(node),
rowan::NodeOrToken::Token(token) => Self::Token(token),
}
}
}

impl LuaUserData for LuaNodeWrapper {
fn add_fields<F: LuaUserDataFields<Self>>(fields: &mut F) {
fields.add_field_method_get("isNode", |_, this| match this {
LuaNodeWrapper::Node(_) => Ok(true),
LuaNodeWrapper::Token(_) => Ok(false),
});
fields.add_field_method_get("isToken", |_, this| match this {
LuaNodeWrapper::Node(_) => Ok(false),
LuaNodeWrapper::Token(_) => Ok(true),
});
fields.add_field_method_get("kind", |_, this| match this {
LuaNodeWrapper::Node(node) => {
let kind: LuaSyntaxKind = node.kind().into();
Ok(kind as u16)
}
LuaNodeWrapper::Token(token) => {
let kind: LuaTokenKind = token.kind().into();
Ok(kind as u16)
}
});
fields.add_field_method_get("kindText", |_, this| {
let text = match this {
LuaNodeWrapper::Node(node) => {
let kind: LuaSyntaxKind = node.kind().into();
format!("{:?}", kind)
}
LuaNodeWrapper::Token(token) => {
let kind: LuaTokenKind = token.kind().into();
format!("{:?}", kind)
}
};

Ok(text)
});
}

fn add_methods<M: LuaUserDataMethods<Self>>(methods: &mut M) {
methods.add_method("getText", |_, this, ()| {
let text = match this {
LuaNodeWrapper::Node(node) => node.text().to_string(),
LuaNodeWrapper::Token(token) => token.text().to_string(),
};
Ok(text)
});
methods.add_method("getRange", |lua, this, ()| {
let range = match this {
LuaNodeWrapper::Node(node) => node.text_range(),
LuaNodeWrapper::Token(token) => token.text_range(),
};
let table = lua.create_table()?;
let line: u32 = range.start().into();
let col: u32 = range.start().into();
table.set("start", line)?;
table.set("end", col)?;
Ok(table)
});
methods.add_method("getChildren", |lua, this, ()| {
let children = match this {
LuaNodeWrapper::Node(node) => node
.children_with_tokens()
.filter_map(|it| match it {
rowan::NodeOrToken::Node(node) => Some(LuaNodeWrapper::Node(node)),
rowan::NodeOrToken::Token(token) => Some(LuaNodeWrapper::Token(token)),
})
.collect(),
LuaNodeWrapper::Token(_) => vec![],
};

Ok(children)
});

methods.add_method("dump", |_, this, ()| {
let dump = match this {
LuaNodeWrapper::Node(node) => format!("{:#?}", node),
LuaNodeWrapper::Token(token) => format!("{:#?}", token),
};
Ok(dump)
});

methods.add_method("getParent", |_, this, ()| {
let parent = match this {
LuaNodeWrapper::Node(node) => node.parent().map(LuaNodeWrapper::Node),
LuaNodeWrapper::Token(token) => token.parent().map(LuaNodeWrapper::Node),
};
Ok(parent)
});

methods.add_method("getPrevSibling", |_, this, ()| {
let prev_sibling = match this {
LuaNodeWrapper::Node(node) => node.prev_sibling().map(LuaNodeWrapper::Node),
LuaNodeWrapper::Token(token) => match token.prev_sibling_or_token() {
Some(rowan::NodeOrToken::Node(node)) => Some(LuaNodeWrapper::Node(node)),
Some(rowan::NodeOrToken::Token(token)) => Some(LuaNodeWrapper::Token(token)),
None => None,
},
};
Ok(prev_sibling)
});

methods.add_method("getNextSibling", |_, this, ()| {
let next_sibling = match this {
LuaNodeWrapper::Node(node) => node.next_sibling().map(LuaNodeWrapper::Node),
LuaNodeWrapper::Token(token) => match token.next_sibling_or_token() {
Some(rowan::NodeOrToken::Node(node)) => Some(LuaNodeWrapper::Node(node)),
Some(rowan::NodeOrToken::Token(token)) => Some(LuaNodeWrapper::Token(token)),
None => None,
},
};
Ok(next_sibling)
});

methods.add_method("getDescendants", |_, this, ()| {
let descendants = match this {
LuaNodeWrapper::Node(node) => node
.descendants_with_tokens()
.map(LuaNodeWrapper::from_node_or_token)
.collect(),
LuaNodeWrapper::Token(_) => vec![],
};
Ok(descendants)
});

methods.add_method("getAncestors", |_, this, ()| {
let ancestors: Vec<LuaNodeWrapper> = match this {
LuaNodeWrapper::Node(node) => node.ancestors().map(LuaNodeWrapper::Node).collect(),
LuaNodeWrapper::Token(token) => {
token.parent_ancestors().map(LuaNodeWrapper::Node).collect()
}
};

Ok(ancestors)
});
}
}
16 changes: 16 additions & 0 deletions crates/basic/src/parser/lua_parser.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
use emmylua_parser::{LuaParser, ParserConfig};
use mlua::{prelude::*, Lua};

use super::lua_syntax_tree::LuaSyntaxTree;

fn parse(_: &Lua, text: String) -> LuaResult<LuaSyntaxTree> {
let tree = LuaParser::parse(&text, ParserConfig::default());

Ok(LuaSyntaxTree::new(tree))
}

pub fn lua_parser(lua: &Lua) -> LuaResult<LuaTable> {
let parser = lua.create_table()?;
parser.set("parse", lua.create_function(parse)?)?;
Ok(parser)
}
49 changes: 49 additions & 0 deletions crates/basic/src/parser/lua_syntax_tree.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
use emmylua_parser::LuaSyntaxTree as EmmyLuaSyntaxTree;
use mlua::prelude::*;
use rowan::TextSize;

use super::lua_node::LuaNodeWrapper;

pub struct LuaSyntaxTree {
tree: EmmyLuaSyntaxTree,
}

impl LuaSyntaxTree {
pub fn new(tree: EmmyLuaSyntaxTree) -> Self {
Self { tree }
}

pub fn get_root(&self) -> LuaNodeWrapper {
LuaNodeWrapper::new(self.tree.get_red_root().clone())
}

pub fn get_line_col(&self, offset: usize) -> Option<(usize, usize)> {
let offset = TextSize::from(offset as u32);
let (line, col) = self.tree.get_line_col(offset)?;
Some((line, col))
}

pub fn get_offset(&self, line: usize, col: usize) -> Option<usize> {
let offset = self.tree.get_offset(line, col)?;
Some(offset.into())
}
}

impl LuaUserData for LuaSyntaxTree {
fn add_fields<F: LuaUserDataFields<Self>>(fields: &mut F) {}

fn add_methods<M: LuaUserDataMethods<Self>>(methods: &mut M) {
methods.add_method("getRoot", |_, this, ()| Ok(this.get_root()));
// methods.add_method("get_chunk_node", |_, this, ()| Ok(this.get_chunk_node()));
methods.add_method("getLineCol", |lua, this, offset: usize| {
let (line, col) = this.get_line_col(offset).unwrap();
let table = lua.create_table()?;
table.set(1, line)?;
table.set(2, col)?;
Ok(table)
});
methods.add_method("getOffset", |_, this, (line, col): (usize, usize)| {
Ok(this.get_offset(line, col))
});
}
}
16 changes: 16 additions & 0 deletions crates/basic/src/parser/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
mod lua_parser;
mod lua_syntax_tree;
mod lua_node;

use mlua::{prelude::*, Lua};

use crate::add_preload_module;


pub fn register_parser_module(lua: &Lua) -> LuaResult<()> {
// lua.parser
let lua_parser_loader =
lua.create_function(|lua: &Lua, ()| Ok(lua_parser::lua_parser(lua)))?;
add_preload_module(&lua, "lua.parser", lua_parser_loader)?;
Ok(())
}
2 changes: 1 addition & 1 deletion resources/main.lua
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ local fs = require 'bee.filesystem'
local util = require 'utility'
local version = require 'version'
require 'config.env'

require 'test'
local function getValue(value)
if value == 'true' or value == nil then
value = true
Expand Down
Loading

0 comments on commit 9362db1

Please sign in to comment.