From 59277100ac179bbf6cad40733732d0bc710c7c20 Mon Sep 17 00:00:00 2001 From: Kampfkarren Date: Fri, 9 Sep 2022 03:01:22 -0700 Subject: [PATCH 01/19] Initial commit --- Cargo.toml | 1 + full-moon-lua-types/Cargo.toml | 13 + full-moon-lua-types/src/core.rs | 1024 ++++++++++++++++++ full-moon-lua-types/src/lib.rs | 9 + full-moon-lua-types/src/lua.rs | 22 + full-moon-lua-types/src/mlua_util.rs | 10 + full-moon-lua-types/src/shared.rs | 114 ++ full-moon-lua-types/tests/lua/everything.lua | 4 + full-moon-lua-types/tests/lua_tests.rs | 12 + 9 files changed, 1209 insertions(+) create mode 100644 full-moon-lua-types/Cargo.toml create mode 100644 full-moon-lua-types/src/core.rs create mode 100644 full-moon-lua-types/src/lib.rs create mode 100644 full-moon-lua-types/src/lua.rs create mode 100644 full-moon-lua-types/src/mlua_util.rs create mode 100644 full-moon-lua-types/src/shared.rs create mode 100644 full-moon-lua-types/tests/lua/everything.lua create mode 100644 full-moon-lua-types/tests/lua_tests.rs diff --git a/Cargo.toml b/Cargo.toml index f642e964..65bf611e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,4 +3,5 @@ members = [ "full-moon", "full-moon-derive", + "full-moon-lua-types", ] \ No newline at end of file diff --git a/full-moon-lua-types/Cargo.toml b/full-moon-lua-types/Cargo.toml new file mode 100644 index 00000000..862a40fa --- /dev/null +++ b/full-moon-lua-types/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "full-moon-lua-types" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +full_moon = { version = "0.15.1", path = "../full-moon" } +mlua = { version = "0.8.3", features = ["luau"] } + +[features] +luau = ["full_moon/roblox"] diff --git a/full-moon-lua-types/src/core.rs b/full-moon-lua-types/src/core.rs new file mode 100644 index 00000000..c3546b39 --- /dev/null +++ b/full-moon-lua-types/src/core.rs @@ -0,0 +1,1024 @@ +use full_moon::{ast, node::Node, tokenizer}; +use mlua::UserData; + +use crate::{mlua_util::add_to_string_display, shared::*}; + +pub struct Ast { + nodes: Block, + eof: TokenReference, +} + +impl From for Ast { + fn from(ast: ast::Ast) -> Self { + Ast { + nodes: Block::new(ast.nodes()), + eof: TokenReference::new(ast.eof()), + } + } +} + +impl UserData for Ast { + fn add_fields<'lua, F: mlua::UserDataFields<'lua, Self>>(fields: &mut F) { + fields.add_field_method_get("nodes", |_, Ast { nodes, .. }| Ok(nodes)) + } + + fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) { + add_to_string_display("Ast", methods); + } +} + +pub struct Assignment { + var_list: Punctuated, + equal_token: TokenReference, + expr_list: Punctuated, +} + +impl Assignment { + fn new(assignment: &ast::Assignment) -> Self { + Assignment { + var_list: Punctuated::map_from_punctuated(assignment.variables(), Var::new), + equal_token: TokenReference::new(assignment.equal_token()), + expr_list: Punctuated::map_from_punctuated(assignment.expressions(), Expression::new), + } + } +} + +impl UserData for Assignment { + fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) { + add_to_string_display("Assignment", methods); + } +} + +pub enum BinOp { + And(TokenReference), + Caret(TokenReference), + GreaterThan(TokenReference), + GreaterThanEqual(TokenReference), + LessThan(TokenReference), + LessThanEqual(TokenReference), + Minus(TokenReference), + Or(TokenReference), + Percent(TokenReference), + Plus(TokenReference), + Slash(TokenReference), + Star(TokenReference), + TildeEqual(TokenReference), + TwoDots(TokenReference), + TwoEqual(TokenReference), +} + +impl BinOp { + fn new(bin_op: &ast::BinOp) -> Self { + match bin_op { + ast::BinOp::And(token) => BinOp::And(TokenReference::new(&token)), + ast::BinOp::Caret(token) => BinOp::Caret(TokenReference::new(&token)), + ast::BinOp::GreaterThan(token) => BinOp::GreaterThan(TokenReference::new(&token)), + ast::BinOp::GreaterThanEqual(token) => { + BinOp::GreaterThanEqual(TokenReference::new(&token)) + } + ast::BinOp::LessThan(token) => BinOp::LessThan(TokenReference::new(&token)), + ast::BinOp::LessThanEqual(token) => BinOp::LessThanEqual(TokenReference::new(&token)), + ast::BinOp::Minus(token) => BinOp::Minus(TokenReference::new(&token)), + ast::BinOp::Or(token) => BinOp::Or(TokenReference::new(&token)), + ast::BinOp::Percent(token) => BinOp::Percent(TokenReference::new(&token)), + ast::BinOp::Plus(token) => BinOp::Plus(TokenReference::new(&token)), + ast::BinOp::Slash(token) => BinOp::Slash(TokenReference::new(&token)), + ast::BinOp::Star(token) => BinOp::Star(TokenReference::new(&token)), + ast::BinOp::TildeEqual(token) => BinOp::TildeEqual(TokenReference::new(&token)), + ast::BinOp::TwoDots(token) => BinOp::TwoDots(TokenReference::new(&token)), + ast::BinOp::TwoEqual(token) => BinOp::TwoEqual(TokenReference::new(&token)), + other => panic!("unimplemented BinOp: {other:?}"), + } + } +} + +impl UserData for BinOp { + fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) { + add_to_string_display("BinOp", methods); + } +} + +pub struct Block { + stmts: Vec<(Stmt, Option)>, + last_stmt: Option<(LastStmt, Option)>, +} + +impl Block { + fn new(block: &ast::Block) -> Self { + Block { + stmts: block + .stmts_with_semicolon() + .map(|(stmt, token)| (Stmt::new(stmt), token.as_ref().map(TokenReference::new))) + .collect(), + + last_stmt: block + .last_stmt_with_semicolon() + .as_ref() + .map(|(last_stmt, token)| { + ( + LastStmt::new(last_stmt), + token.as_ref().map(TokenReference::new), + ) + }), + } + } +} + +impl UserData for Block { + fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) { + add_to_string_display("Block", methods); + } +} + +pub enum Call { + AnonymousCall(FunctionArgs), + MethodCall(MethodCall), +} + +impl Call { + fn new(call: &ast::Call) -> Self { + match call { + ast::Call::AnonymousCall(function_args) => { + Call::AnonymousCall(FunctionArgs::new(function_args)) + } + ast::Call::MethodCall(method_call) => Call::MethodCall(MethodCall::new(method_call)), + other => panic!("unimplemented Call: {other:?}"), + } + } +} + +impl UserData for Call { + fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) { + add_to_string_display("Call", methods); + } +} + +pub struct Do { + do_token: TokenReference, + block: Block, + end_token: TokenReference, +} + +impl Do { + fn new(do_: &ast::Do) -> Self { + Do { + do_token: TokenReference::new(do_.do_token()), + block: Block::new(do_.block()), + end_token: TokenReference::new(do_.end_token()), + } + } +} + +impl UserData for Do { + fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) { + add_to_string_display("Do", methods); + } +} + +pub struct ElseIf { + else_if_token: TokenReference, + condition: Expression, + then_token: TokenReference, + block: Block, +} + +impl ElseIf { + fn new(else_if: &ast::ElseIf) -> Self { + ElseIf { + else_if_token: TokenReference::new(else_if.else_if_token()), + condition: Expression::new(else_if.condition()), + then_token: TokenReference::new(else_if.then_token()), + block: Block::new(else_if.block()), + } + } +} + +impl UserData for ElseIf { + fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) { + add_to_string_display("ElseIf", methods); + } +} + +pub enum Expression { + BinaryOperator { + lhs: Box, + binop: BinOp, + rhs: Box, + }, + + Parentheses { + contained: ContainedSpan, + expression: Box, + }, + + UnaryOperator { + unop: UnOp, + expression: Box, + }, + + Value { + value: Box, + }, +} + +impl Expression { + fn new(expression: &ast::Expression) -> Self { + match expression { + ast::Expression::BinaryOperator { lhs, binop, rhs } => Expression::BinaryOperator { + lhs: Box::new(Expression::new(lhs)), + binop: BinOp::new(binop), + rhs: Box::new(Expression::new(rhs)), + }, + + ast::Expression::Parentheses { + contained, + expression, + } => Expression::Parentheses { + contained: ContainedSpan::new(contained), + expression: Box::new(Expression::new(expression)), + }, + + ast::Expression::UnaryOperator { unop, expression } => Expression::UnaryOperator { + unop: UnOp::new(unop), + expression: Box::new(Expression::new(expression)), + }, + + ast::Expression::Value { value } => Expression::Value { + value: Box::new(Value::new(value)), + }, + + other => panic!("unimplemented Expression: {other:?}"), + } + } +} + +impl UserData for Expression { + fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) { + add_to_string_display("Expression", methods); + } +} + +pub enum FunctionArgs { + Parentheses { + contained: ContainedSpan, + expressions: Punctuated, + }, + + String(TokenReference), + + TableConstructor(TableConstructor), +} + +impl FunctionArgs { + fn new(function_args: &ast::FunctionArgs) -> Self { + match function_args { + ast::FunctionArgs::Parentheses { + parentheses, + arguments, + } => FunctionArgs::Parentheses { + contained: ContainedSpan::new(parentheses), + expressions: Punctuated::map_from_punctuated(arguments, Expression::new), + }, + + ast::FunctionArgs::String(token) => FunctionArgs::String(TokenReference::new(token)), + + ast::FunctionArgs::TableConstructor(table_constructor) => { + FunctionArgs::TableConstructor(TableConstructor::new(table_constructor)) + } + + other => panic!("unimplemented FunctionArgs: {other:?}"), + } + } +} + +impl UserData for FunctionArgs { + fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) { + add_to_string_display("FunctionArgs", methods); + } +} + +pub struct FunctionBody { + parameters_parentheses: ContainedSpan, + parameters: Punctuated, + block: Block, + end_token: TokenReference, +} + +impl FunctionBody { + fn new(function_body: &ast::FunctionBody) -> Self { + FunctionBody { + parameters_parentheses: ContainedSpan::new(function_body.parameters_parentheses()), + + parameters: Punctuated::map_from_punctuated(function_body.parameters(), Parameter::new), + + block: Block::new(function_body.block()), + end_token: TokenReference::new(function_body.end_token()), + } + } +} + +impl UserData for FunctionBody { + fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) { + add_to_string_display("FunctionBody", methods); + } +} + +pub enum LastStmt { + Break(TokenReference), + #[cfg(feature = "luau")] + Continue(TokenReference), + Return(Return), +} + +impl LastStmt { + fn new(last_stmt: &ast::LastStmt) -> Self { + match last_stmt { + ast::LastStmt::Break(break_token) => LastStmt::Break(TokenReference::new(break_token)), + + #[cfg(feature = "luau")] + ast::LastStmt::Continue(continue_token) => { + LastStmt::Continue(TokenReference::new(continue_token)) + } + + ast::LastStmt::Return(return_token) => LastStmt::Return(Return::new(return_token)), + + _ => unimplemented!("unexpected LastStmt variant: {last_stmt:#?}"), + } + } +} + +impl UserData for LastStmt { + fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) { + add_to_string_display("LastStmt", methods); + } +} + +pub enum Field { + ExpressionKey { + brackets: ContainedSpan, + key: Expression, + equal: TokenReference, + value: Expression, + }, + + NameKey { + key: TokenReference, + equal: TokenReference, + value: Expression, + }, + + NoKey(Expression), +} + +impl Field { + fn new(field: &ast::Field) -> Self { + match field { + ast::Field::ExpressionKey { + brackets, + key, + equal, + value, + } => Field::ExpressionKey { + brackets: ContainedSpan::new(brackets), + key: Expression::new(key), + equal: TokenReference::new(equal), + value: Expression::new(value), + }, + + ast::Field::NameKey { key, equal, value } => Field::NameKey { + key: TokenReference::new(key), + equal: TokenReference::new(equal), + value: Expression::new(value), + }, + + ast::Field::NoKey(expression) => Field::NoKey(Expression::new(expression)), + + other => panic!("unimplemented Field: {other:?}"), + } + } +} + +impl UserData for Field { + fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) { + add_to_string_display("Field", methods); + } +} + +pub struct FunctionCall { + prefix: Prefix, + suffixes: Vec, +} + +impl FunctionCall { + fn new(function_call: &ast::FunctionCall) -> Self { + FunctionCall { + prefix: Prefix::new(function_call.prefix()), + suffixes: function_call.suffixes().map(Suffix::new).collect(), + } + } +} + +impl UserData for FunctionCall { + fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) { + add_to_string_display("FunctionCall", methods); + } +} + +pub struct FunctionDeclaration { + function_token: TokenReference, + name: FunctionName, + body: FunctionBody, +} + +impl FunctionDeclaration { + fn new(function_declaration: &ast::FunctionDeclaration) -> Self { + FunctionDeclaration { + function_token: TokenReference::new(function_declaration.function_token()), + name: FunctionName::new(function_declaration.name()), + body: FunctionBody::new(function_declaration.body()), + } + } +} + +impl UserData for FunctionDeclaration { + fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) { + add_to_string_display("FunctionDeclaration", methods); + } +} + +pub struct FunctionName { + names: Punctuated, + colon_name: Option<(TokenReference, TokenReference)>, +} + +impl FunctionName { + fn new(function_name: &ast::FunctionName) -> Self { + FunctionName { + names: Punctuated::map_from_punctuated(function_name.names(), TokenReference::new), + + colon_name: match (function_name.method_colon(), function_name.method_name()) { + (Some(colon), Some(name)) => { + Some((TokenReference::new(colon), TokenReference::new(name))) + } + + _ => None, + }, + } + } +} + +impl UserData for FunctionName { + fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) { + add_to_string_display("FunctionName", methods); + } +} + +pub struct GenericFor { + for_token: TokenReference, + names: Punctuated, + in_token: TokenReference, + expr_list: Punctuated, + do_token: TokenReference, + block: Block, + end_token: TokenReference, +} + +impl GenericFor { + fn new(generic_for: &ast::GenericFor) -> Self { + GenericFor { + for_token: TokenReference::new(generic_for.for_token()), + names: Punctuated::map_from_punctuated(generic_for.names(), TokenReference::new), + in_token: TokenReference::new(generic_for.in_token()), + expr_list: Punctuated::map_from_punctuated(generic_for.expressions(), Expression::new), + do_token: TokenReference::new(generic_for.do_token()), + block: Block::new(generic_for.block()), + end_token: TokenReference::new(generic_for.end_token()), + } + } +} + +impl UserData for GenericFor { + fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) { + add_to_string_display("GenericFor", methods); + } +} + +pub struct If { + if_token: TokenReference, + condition: Expression, + then_token: TokenReference, + block: Block, + else_if: Option>, + else_token: Option, + else_block: Option, + end_token: TokenReference, +} + +impl If { + fn new(if_node: &ast::If) -> Self { + If { + if_token: TokenReference::new(if_node.if_token()), + condition: Expression::new(if_node.condition()), + then_token: TokenReference::new(if_node.then_token()), + block: Block::new(if_node.block()), + else_if: if_node + .else_if() + .map(|else_if| else_if.iter().map(ElseIf::new).collect()), + else_token: if_node.else_token().map(TokenReference::new), + else_block: if_node.else_block().map(Block::new), + end_token: TokenReference::new(if_node.end_token()), + } + } +} + +impl UserData for If { + fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) { + add_to_string_display("If", methods); + } +} + +pub enum Index { + Brackets { + brackets: ContainedSpan, + expression: Expression, + }, + + Dot { + dot: TokenReference, + name: TokenReference, + }, +} + +impl Index { + fn new(index: &ast::Index) -> Self { + match index { + ast::Index::Brackets { + brackets, + expression, + } => Index::Brackets { + brackets: ContainedSpan::new(brackets), + expression: Expression::new(expression), + }, + + ast::Index::Dot { dot, name } => Index::Dot { + dot: TokenReference::new(dot), + name: TokenReference::new(name), + }, + + other => panic!("unimplemented Index: {other:?}"), + } + } +} + +impl UserData for Index { + fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) { + add_to_string_display("Index", methods); + } +} + +pub struct LocalAssignment { + local_token: TokenReference, + name_list: Punctuated, + equal_token: Option, + expr_list: Punctuated, +} + +impl LocalAssignment { + fn new(local_assignment: &ast::LocalAssignment) -> Self { + LocalAssignment { + local_token: TokenReference::new(local_assignment.local_token()), + name_list: Punctuated::map_from_punctuated( + local_assignment.names(), + TokenReference::new, + ), + equal_token: local_assignment.equal_token().map(TokenReference::new), + expr_list: Punctuated::map_from_punctuated( + local_assignment.expressions(), + Expression::new, + ), + } + } +} + +impl UserData for LocalAssignment { + fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) { + add_to_string_display("LocalAssignment", methods); + } +} + +pub struct LocalFunction { + local_token: TokenReference, + function_token: TokenReference, + name: TokenReference, + body: FunctionBody, +} + +impl LocalFunction { + fn new(local_function: &ast::LocalFunction) -> Self { + LocalFunction { + local_token: TokenReference::new(local_function.local_token()), + function_token: TokenReference::new(local_function.function_token()), + name: TokenReference::new(local_function.name()), + body: FunctionBody::new(local_function.body()), + } + } +} + +impl UserData for LocalFunction { + fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) { + add_to_string_display("LocalFunction", methods); + } +} + +pub struct MethodCall { + colon_token: TokenReference, + name: TokenReference, + args: FunctionArgs, +} + +impl MethodCall { + fn new(method_call: &ast::MethodCall) -> Self { + MethodCall { + colon_token: TokenReference::new(method_call.colon_token()), + name: TokenReference::new(method_call.name()), + args: FunctionArgs::new(method_call.args()), + } + } +} + +impl UserData for MethodCall { + fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) { + add_to_string_display("MethodCall", methods); + } +} + +pub struct NumericFor { + for_token: TokenReference, + index_variable: TokenReference, + equal_token: TokenReference, + start: Expression, + start_end_comma: TokenReference, + end: Expression, + end_step_comma: Option, + step: Option, + do_token: TokenReference, + block: Block, + end_token: TokenReference, +} + +impl NumericFor { + fn new(numeric_for: &ast::NumericFor) -> Self { + NumericFor { + for_token: TokenReference::new(numeric_for.for_token()), + index_variable: TokenReference::new(numeric_for.index_variable()), + equal_token: TokenReference::new(numeric_for.equal_token()), + start: Expression::new(numeric_for.start()), + start_end_comma: TokenReference::new(numeric_for.start_end_comma()), + end: Expression::new(numeric_for.end()), + end_step_comma: numeric_for.end_step_comma().map(TokenReference::new), + step: numeric_for.step().map(Expression::new), + do_token: TokenReference::new(numeric_for.do_token()), + block: Block::new(numeric_for.block()), + end_token: TokenReference::new(numeric_for.end_token()), + } + } +} + +impl UserData for NumericFor { + fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) { + add_to_string_display("NumericFor", methods); + } +} + +pub enum Parameter { + Ellipse(TokenReference), + Name(TokenReference), +} + +impl Parameter { + fn new(parameter: &ast::Parameter) -> Self { + match parameter { + ast::Parameter::Ellipse(ellipse_token) => { + Parameter::Ellipse(TokenReference::new(ellipse_token)) + } + + ast::Parameter::Name(name_token) => Parameter::Name(TokenReference::new(name_token)), + + _ => unimplemented!("unexpected Parameter variant: {parameter:#?}"), + } + } +} + +impl UserData for Parameter { + fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) { + add_to_string_display("Parameter", methods); + } +} + +pub enum Prefix { + Expression(Expression), + Name(TokenReference), +} + +impl Prefix { + fn new(prefix: &ast::Prefix) -> Self { + match prefix { + ast::Prefix::Expression(expr) => Prefix::Expression(Expression::new(expr)), + ast::Prefix::Name(name) => Prefix::Name(TokenReference::new(name)), + other => unimplemented!("unexpected Prefix variant: {other:?}"), + } + } +} + +impl UserData for Prefix { + fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) { + add_to_string_display("Prefix", methods); + } +} + +pub struct Return { + token: TokenReference, + returns: Punctuated, +} + +impl Return { + fn new(return_token: &ast::Return) -> Self { + Return { + token: TokenReference::new(return_token.token()), + returns: Punctuated::map_from_punctuated(return_token.returns(), Expression::new), + } + } +} + +impl UserData for Return { + fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) { + add_to_string_display("Return", methods); + } +} + +pub struct Repeat { + repeat_token: TokenReference, + block: Block, + until_token: TokenReference, + until: Expression, +} + +impl Repeat { + fn new(repeat: &ast::Repeat) -> Self { + Repeat { + repeat_token: TokenReference::new(repeat.repeat_token()), + block: Block::new(repeat.block()), + until_token: TokenReference::new(repeat.until_token()), + until: Expression::new(repeat.until()), + } + } +} + +impl UserData for Repeat { + fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) { + add_to_string_display("Repeat", methods); + } +} + +pub enum Stmt { + Assignment(Assignment), + Do(Do), + FunctionCall(FunctionCall), + FunctionDeclaration(FunctionDeclaration), + GenericFor(GenericFor), + If(If), + LocalAssignment(LocalAssignment), + LocalFunction(LocalFunction), + NumericFor(NumericFor), + Repeat(Repeat), + While(While), + + NonStandard(Vec), +} + +impl Stmt { + fn new(stmt: &ast::Stmt) -> Self { + match stmt { + ast::Stmt::Assignment(assignment) => Stmt::Assignment(Assignment::new(assignment)), + ast::Stmt::Do(do_token) => Stmt::Do(Do::new(do_token)), + ast::Stmt::FunctionCall(function_call) => { + Stmt::FunctionCall(FunctionCall::new(function_call)) + } + ast::Stmt::FunctionDeclaration(function_declaration) => { + Stmt::FunctionDeclaration(FunctionDeclaration::new(function_declaration)) + } + ast::Stmt::GenericFor(generic_for) => Stmt::GenericFor(GenericFor::new(generic_for)), + ast::Stmt::If(if_token) => Stmt::If(If::new(if_token)), + ast::Stmt::LocalAssignment(local_assignment) => { + Stmt::LocalAssignment(LocalAssignment::new(local_assignment)) + } + ast::Stmt::LocalFunction(local_function) => { + Stmt::LocalFunction(LocalFunction::new(local_function)) + } + ast::Stmt::NumericFor(numeric_for) => Stmt::NumericFor(NumericFor::new(numeric_for)), + ast::Stmt::Repeat(repeat_token) => Stmt::Repeat(Repeat::new(repeat_token)), + ast::Stmt::While(while_token) => Stmt::While(While::new(while_token)), + + // TODO: Support everything, then make this `unimplemented!` + _ => Stmt::NonStandard( + stmt.tokens() + .map(|token| TokenReference::new(token)) + .collect(), + ), + } + } +} + +impl UserData for Stmt { + fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) { + add_to_string_display("Stmt", methods); + } +} + +pub enum Suffix { + Call(Call), + Index(Index), +} + +impl Suffix { + fn new(suffix: &ast::Suffix) -> Self { + match suffix { + ast::Suffix::Call(call) => Suffix::Call(Call::new(call)), + ast::Suffix::Index(index) => Suffix::Index(Index::new(index)), + other => unimplemented!("unexpected Suffix variant: {other:#?}"), + } + } +} + +impl UserData for Suffix { + fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) { + add_to_string_display("Suffix", methods); + } +} + +pub struct TableConstructor { + braces: ContainedSpan, + fields: Punctuated, +} + +impl TableConstructor { + fn new(table_constructor: &ast::TableConstructor) -> Self { + TableConstructor { + braces: ContainedSpan::new(table_constructor.braces()), + fields: Punctuated::map_from_punctuated(table_constructor.fields(), Field::new), + } + } +} + +impl UserData for TableConstructor { + fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) { + add_to_string_display("TableConstructor", methods); + } +} + +pub enum UnOp { + Minus(TokenReference), + Not(TokenReference), + Hash(TokenReference), +} + +impl UnOp { + fn new(unop: &ast::UnOp) -> Self { + match unop { + ast::UnOp::Minus(token) => UnOp::Minus(TokenReference::new(token)), + ast::UnOp::Not(token) => UnOp::Not(TokenReference::new(token)), + ast::UnOp::Hash(token) => UnOp::Hash(TokenReference::new(token)), + other => panic!("unimplemented UnOp: {other:?}"), + } + } +} + +impl UserData for UnOp { + fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) { + add_to_string_display("UnOp", methods); + } +} + +pub enum Value { + Function((TokenReference, FunctionBody)), + FunctionCall(FunctionCall), + TableConstructor(TableConstructor), + Number(TokenReference), + ParenthesesExpression(Expression), + String(TokenReference), + Symbol(TokenReference), + Var(Var), + + NonStandard(Vec), +} + +impl Value { + pub fn new(value: &ast::Value) -> Self { + match value { + ast::Value::Function((token_reference, function_body)) => Value::Function(( + TokenReference::new(token_reference), + FunctionBody::new(function_body), + )), + + ast::Value::FunctionCall(function_call) => { + Value::FunctionCall(FunctionCall::new(function_call)) + } + + ast::Value::TableConstructor(table_constructor) => { + Value::TableConstructor(TableConstructor::new(table_constructor)) + } + + ast::Value::Number(number) => Value::Number(TokenReference::new(number)), + ast::Value::ParenthesesExpression(expression) => { + Value::ParenthesesExpression(Expression::new(expression)) + } + ast::Value::String(string) => Value::String(TokenReference::new(string)), + ast::Value::Symbol(symbol) => Value::Symbol(TokenReference::new(symbol)), + ast::Value::Var(var) => Value::Var(Var::new(var)), + + // TODO: implement everything, then `unimplemented!` + other => Value::NonStandard( + other + .tokens() + .map(|token| TokenReference::new(token)) + .collect(), + ), + } + } +} + +impl UserData for Value { + fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) { + add_to_string_display("Value", methods); + } +} + +pub enum Var { + Expression(VarExpression), + Name(TokenReference), +} + +impl Var { + fn new(var: &ast::Var) -> Self { + match var { + ast::Var::Expression(expression) => Var::Expression(VarExpression::new(expression)), + ast::Var::Name(name_token) => Var::Name(TokenReference::new(name_token)), + other => unimplemented!("unexpected Var variant: {var:#?}"), + } + } +} + +impl UserData for Var { + fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) { + add_to_string_display("Var", methods); + } +} + +pub struct VarExpression { + prefix: Prefix, + suffixes: Vec, +} + +impl VarExpression { + fn new(var_expression: &ast::VarExpression) -> Self { + VarExpression { + prefix: Prefix::new(var_expression.prefix()), + suffixes: var_expression + .suffixes() + .map(|suffix| Suffix::new(suffix)) + .collect(), + } + } +} + +impl UserData for VarExpression { + fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) { + add_to_string_display("VarExpression", methods); + } +} + +pub struct While { + while_token: TokenReference, + condition: Expression, + do_token: TokenReference, + block: Block, + end_token: TokenReference, +} + +impl While { + fn new(while_token: &ast::While) -> Self { + While { + while_token: TokenReference::new(while_token.while_token()), + condition: Expression::new(while_token.condition()), + do_token: TokenReference::new(while_token.do_token()), + block: Block::new(while_token.block()), + end_token: TokenReference::new(while_token.end_token()), + } + } +} + +impl UserData for While { + fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) { + add_to_string_display("While", methods); + } +} diff --git a/full-moon-lua-types/src/lib.rs b/full-moon-lua-types/src/lib.rs new file mode 100644 index 00000000..36d8a1f6 --- /dev/null +++ b/full-moon-lua-types/src/lib.rs @@ -0,0 +1,9 @@ +// fix this later? +#![allow(clippy::large_enum_variant)] + +mod core; +mod lua; +mod mlua_util; +mod shared; + +pub use lua::create_lua; diff --git a/full-moon-lua-types/src/lua.rs b/full-moon-lua-types/src/lua.rs new file mode 100644 index 00000000..919dd304 --- /dev/null +++ b/full-moon-lua-types/src/lua.rs @@ -0,0 +1,22 @@ +use crate::core; + +pub fn create_lua() -> mlua::Result { + let lua = mlua::Lua::new(); + + assign_globals(&lua)?; + + Ok(lua) +} + +fn assign_globals(lua: &mlua::Lua) -> mlua::Result<()> { + let globals = lua.globals(); + + globals.set( + "parse", + lua.create_function(|_, code: String| { + let ast = full_moon::parse(&code).expect("NYI: Error on failure"); + + Ok(core::Ast::from(ast)) + })?, + ) +} diff --git a/full-moon-lua-types/src/mlua_util.rs b/full-moon-lua-types/src/mlua_util.rs new file mode 100644 index 00000000..23bb09db --- /dev/null +++ b/full-moon-lua-types/src/mlua_util.rs @@ -0,0 +1,10 @@ +use mlua::UserData; + +pub fn add_to_string_display<'lua, T: UserData, M: mlua::UserDataMethods<'lua, T>>( + name: &'static str, + methods: &mut M, +) { + methods.add_meta_method(mlua::MetaMethod::ToString, move |_, this, _: ()| { + Ok(format!("{name}({:x})", this as *const _ as usize)) + }); +} diff --git a/full-moon-lua-types/src/shared.rs b/full-moon-lua-types/src/shared.rs new file mode 100644 index 00000000..c4645def --- /dev/null +++ b/full-moon-lua-types/src/shared.rs @@ -0,0 +1,114 @@ +use std::iter::FromIterator; + +use full_moon::{ + ast::{self, punctuated::Pair}, + tokenizer, +}; + +use mlua::{MetaMethod, ToLua, UserData}; + +pub struct ContainedSpan { + start: TokenReference, + end: TokenReference, +} + +impl ContainedSpan { + pub fn new(contained_span: &ast::span::ContainedSpan) -> Self { + let (start, end) = contained_span.tokens(); + + ContainedSpan { + start: TokenReference::new(start), + end: TokenReference::new(end), + } + } +} + +pub struct Position(tokenizer::Position); + +pub struct Punctuated(ast::punctuated::Punctuated); + +impl Punctuated { + pub fn map_from_punctuated T>( + punctuated: &ast::punctuated::Punctuated, + mut map: F, + ) -> Self { + Punctuated(ast::punctuated::Punctuated::from_iter( + punctuated.pairs().map(|pair| match pair { + Pair::Punctuated(value, punctuation) => { + Pair::Punctuated(map(value), punctuation.clone()) + } + + Pair::End(value) => Pair::End(map(value)), + }), + )) + } +} + +impl FromIterator> for Punctuated { + fn from_iter>>(iter: I) -> Self { + Punctuated(ast::punctuated::Punctuated::from_iter(iter)) + } +} + +impl Punctuated { + fn to_table<'lua>(&self, lua: &'lua mlua::Lua) -> mlua::Result> { + let table = lua.create_table()?; + + for (i, item) in self.0.iter().enumerate() { + table.set(i + 1, item.clone().to_lua(lua)?)?; + } + + Ok(table) + } +} + +impl UserData for Punctuated { + fn add_fields<'lua, F: mlua::UserDataFields<'lua, Self>>(_fields: &mut F) {} + + fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) { + methods.add_meta_method(MetaMethod::Iter, |lua, this, _: ()| { + Ok(( + lua.globals().get::<_, mlua::Function>("next")?, + this.to_table(lua)?, + )) + }); + + methods.add_meta_method(MetaMethod::Len, |_, Punctuated(punctuated), _: ()| { + Ok(punctuated.len()) + }); + } +} + +pub struct TokenType(tokenizer::TokenType); + +pub struct Token { + start_position: Position, + end_position: Position, + token_type: TokenType, +} + +impl From<&tokenizer::Token> for Token { + fn from(token: &tokenizer::Token) -> Self { + Token { + start_position: Position(token.start_position()), + end_position: Position(token.end_position()), + token_type: TokenType(token.token_type().clone()), + } + } +} + +pub struct TokenReference { + leading_trivia: Vec, + token: Token, + trailing_trivia: Vec, +} + +impl TokenReference { + pub fn new(token_reference: &tokenizer::TokenReference) -> Self { + TokenReference { + leading_trivia: token_reference.leading_trivia().map(Token::from).collect(), + token: Token::from(token_reference.token()), + trailing_trivia: token_reference.trailing_trivia().map(Token::from).collect(), + } + } +} diff --git a/full-moon-lua-types/tests/lua/everything.lua b/full-moon-lua-types/tests/lua/everything.lua new file mode 100644 index 00000000..cb8a2cf1 --- /dev/null +++ b/full-moon-lua-types/tests/lua/everything.lua @@ -0,0 +1,4 @@ +local ast + +ast = parse("x, y = 1, 2") +error(tostring(ast)) diff --git a/full-moon-lua-types/tests/lua_tests.rs b/full-moon-lua-types/tests/lua_tests.rs new file mode 100644 index 00000000..5a303edc --- /dev/null +++ b/full-moon-lua-types/tests/lua_tests.rs @@ -0,0 +1,12 @@ +fn test_lua_code(code: &str) { + let lua = full_moon_lua_types::create_lua().expect("can't create lua"); + + if let Err(error) = lua.load(code).exec() { + panic!("lua error:\n{error}"); + } +} + +#[test] +fn everything() { + test_lua_code(include_str!("lua/everything.lua")); +} From 0e4bcb779f088fd40c535103d4ff6159ed8239d1 Mon Sep 17 00:00:00 2001 From: Kampfkarren Date: Fri, 9 Sep 2022 03:07:04 -0700 Subject: [PATCH 02/19] UserData --- full-moon-lua-types/src/core.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/full-moon-lua-types/src/core.rs b/full-moon-lua-types/src/core.rs index c3546b39..ba9134fc 100644 --- a/full-moon-lua-types/src/core.rs +++ b/full-moon-lua-types/src/core.rs @@ -19,7 +19,7 @@ impl From for Ast { impl UserData for Ast { fn add_fields<'lua, F: mlua::UserDataFields<'lua, Self>>(fields: &mut F) { - fields.add_field_method_get("nodes", |_, Ast { nodes, .. }| Ok(nodes)) + // fields.add_field_method_get("nodes", |_, Ast { nodes, .. }| Ok(nodes)) } fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) { From 9d78457192e644c8ebdfa6e36c74c3daa7cf1131 Mon Sep 17 00:00:00 2001 From: Kampfkarren Date: Tue, 13 Sep 2022 06:05:53 -0700 Subject: [PATCH 03/19] Enums and a lot more --- Cargo.toml | 1 + full-moon-lua-types-derive/Cargo.toml | 14 + full-moon-lua-types-derive/src/lib.rs | 10 + .../src/lua_user_data.rs | 288 +++++++ full-moon-lua-types/Cargo.toml | 1 + full-moon-lua-types/src/core.rs | 768 ++++++++++++------ full-moon-lua-types/src/create_ast_node.rs | 41 + full-moon-lua-types/src/lib.rs | 2 + full-moon-lua-types/src/lua.rs | 12 +- full-moon-lua-types/src/mlua_util.rs | 54 +- full-moon-lua-types/src/prepare_for_lua.rs | 31 + full-moon-lua-types/src/shared.rs | 84 +- full-moon-lua-types/tests/lua/core.lua | 40 + full-moon-lua-types/tests/lua/everything.lua | 4 - full-moon-lua-types/tests/lua_tests.rs | 5 + 15 files changed, 1077 insertions(+), 278 deletions(-) create mode 100644 full-moon-lua-types-derive/Cargo.toml create mode 100644 full-moon-lua-types-derive/src/lib.rs create mode 100644 full-moon-lua-types-derive/src/lua_user_data.rs create mode 100644 full-moon-lua-types/src/create_ast_node.rs create mode 100644 full-moon-lua-types/src/prepare_for_lua.rs create mode 100644 full-moon-lua-types/tests/lua/core.lua diff --git a/Cargo.toml b/Cargo.toml index 65bf611e..9c3acabd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,4 +4,5 @@ members = [ "full-moon", "full-moon-derive", "full-moon-lua-types", + "full-moon-lua-types-derive", ] \ No newline at end of file diff --git a/full-moon-lua-types-derive/Cargo.toml b/full-moon-lua-types-derive/Cargo.toml new file mode 100644 index 00000000..a468da28 --- /dev/null +++ b/full-moon-lua-types-derive/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "full_moon_lua_types_derive" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[lib] +proc-macro = true + +[dependencies] +proc-macro2 = "1.0.43" +quote = "1.0.21" +syn = { version = "1.0.99" } diff --git a/full-moon-lua-types-derive/src/lib.rs b/full-moon-lua-types-derive/src/lib.rs new file mode 100644 index 00000000..d68e7bc1 --- /dev/null +++ b/full-moon-lua-types-derive/src/lib.rs @@ -0,0 +1,10 @@ +use proc_macro::TokenStream; + +extern crate proc_macro; + +mod lua_user_data; + +#[proc_macro_derive(LuaUserData, attributes(lua))] +pub fn derive_lua_user_data(input: TokenStream) -> TokenStream { + lua_user_data::derive(input) +} diff --git a/full-moon-lua-types-derive/src/lua_user_data.rs b/full-moon-lua-types-derive/src/lua_user_data.rs new file mode 100644 index 00000000..60f5698d --- /dev/null +++ b/full-moon-lua-types-derive/src/lua_user_data.rs @@ -0,0 +1,288 @@ +use proc_macro::TokenStream; +use quote::{format_ident, quote}; + +fn match_all proc_macro2::TokenStream>( + input_ident: &syn::Ident, + variants: &syn::punctuated::Punctuated, + case: F, +) -> proc_macro2::TokenStream { + let mut cases = Vec::new(); + + for variant in variants { + let ident = &variant.ident; + let result = case(ident); + + match variant.fields { + syn::Fields::Named(_) => { + cases.push(quote! { + #input_ident::#ident { .. } => { #result } + }); + } + + syn::Fields::Unnamed(_) => { + cases.push(quote! { + #input_ident::#ident(..) => { #result } + }); + } + + syn::Fields::Unit => { + cases.push(quote! { + #input_ident::#ident => { #result } + }); + } + } + } + + quote! { + match this { + #(#cases,)* + } + } +} + +pub fn derive(input: TokenStream) -> TokenStream { + let input = syn::parse_macro_input!(input as syn::DeriveInput); + + let input_enum = match &input.data { + syn::Data::Enum(input_enum) => input_enum, + _ => panic!("can only derive for enums"), + }; + + let input_ident = &input.ident; + + let match_kind = match_all(input_ident, &input_enum.variants, |variant| { + quote! { + stringify!(#variant) + } + }); + + let match_to_string = match_all(input_ident, &input_enum.variants, |variant| { + quote! { + format!("{}::{}", stringify!(#input_ident), stringify!(#variant)) + } + }); + + let match_match = { + let mut cases = Vec::with_capacity(input_enum.variants.len()); + + for variant in &input_enum.variants { + let variant_ident = &variant.ident; + + match &variant.fields { + syn::Fields::Named(fields) => { + let fields = fields + .named + .iter() + .map(|field| &field.ident) + .collect::>(); + + cases.push(quote! { + #input_ident::#variant_ident { #(#fields),* } => { + let mut table = lua.create_table()?; + + #( + table.set(stringify!(#fields), #fields.prepare_for_lua(lua)?)?; + )* + + (stringify!(#variant_ident), table.to_lua_multi(lua)?) + } + }); + } + + syn::Fields::Unnamed(fields) => { + let fields = fields + .unnamed + .iter() + .enumerate() + .map(|(index, _)| format_ident!("_{index}")) + .collect::>(); + + cases.push(quote! { + #input_ident::#variant_ident(#(#fields),*) => { + let mut fields = Vec::new(); + + #( + fields.push(#fields.prepare_for_lua(lua)?); + )* + + (stringify!(#variant_ident), mlua::MultiValue::from_vec(fields)) + } + }); + } + + syn::Fields::Unit => { + cases.push(quote! { + #input_ident::#variant_ident => { + (stringify!(#variant_ident), ().to_lua_multi(lua)?) + } + }); + } + } + } + + quote! { + use mlua::ToLuaMulti; + + let (function_name, args) = match this { + #(#cases,)* + }; + + match table.get::<_, Option>(function_name)? { + Some(mlua::Value::Function(function)) => { + function.call::<_, mlua::Value>(args) + } + + Some(other) => { + Err(mlua::Error::external(format!( + "expected function for {}, got {}", + function_name, + other.type_name(), + ))) + } + + None => { + Ok(mlua::Value::Nil) + } + } + } + }; + + let match_create_ast_node = { + let mut cases = Vec::with_capacity(input_enum.variants.len()); + + for variant in &input_enum.variants { + let variant_ident = &variant.ident; + + if variant_ident == "NonStandard" { + let fields = match &variant.fields { + syn::Fields::Named(_) => quote! { { .. } }, + syn::Fields::Unnamed(_) => quote! { ( .. ) }, + syn::Fields::Unit => quote! {}, + }; + + cases.push(quote! { + #input_ident::#variant_ident #fields => { + None + } + }); + + continue; + } + + match &variant.fields { + syn::Fields::Named(field) => { + let fields = field + .named + .iter() + .map(|field| &field.ident) + .collect::>(); + + cases.push(quote! { + #input_ident::#variant_ident { #(#fields),* } => { + Some(full_moon::ast::#input_ident::#variant_ident { + #(#fields: #fields.create_ast_node()?),* + }) + } + }); + } + + syn::Fields::Unnamed(field) => { + let fields = field + .unnamed + .iter() + .enumerate() + .map(|(index, _)| format_ident!("_{index}")) + .collect::>(); + + let body = match variant + .attrs + .iter() + .filter_map(|attr| { + if !attr.path.is_ident("lua") { + return None; + } + + let name_value = attr + .parse_args::() + .expect("expected name value for #[lua(create_ast_node)]"); + + if name_value.path.is_ident("create_ast_node") { + Some(match name_value.lit { + syn::Lit::Str(lit_str) => lit_str.value(), + _ => panic!("expected string for #[lua(create_ast_node)]"), + }) + } else { + None + } + }) + .next() + { + Some(create_ast_node_attr) => { + syn::parse_str(&create_ast_node_attr).expect("expected valid rust code") + } + + None => { + quote! { + full_moon::ast::#input_ident::#variant_ident( + #(#fields.create_ast_node()?),* + ) + } + } + }; + + cases.push(quote! { + #input_ident::#variant_ident(#(#fields),*) => { + #body.into() + } + }); + } + + syn::Fields::Unit => { + cases.push(quote! { + #input_ident::#variant_ident => { + Some(full_moon::ast::#input_ident::#variant_ident) + } + }); + } + } + } + + quote! { + match self { + #(#cases,)* + } + } + }; + + quote! { + impl mlua::UserData for #input_ident { + fn add_fields<'lua, F: mlua::UserDataFields<'lua, Self>>(fields: &mut F) { + fields.add_field_method_get("kind", |_, this| { + Ok(#match_kind) + }); + } + + fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) { + crate::mlua_util::add_core_metamethods_no_tostring(stringify!(#input_ident), methods); + crate::mlua_util::add_print(methods); + + methods.add_meta_method(mlua::MetaMethod::ToString, |_, this, _: ()| { + Ok(#match_to_string) + }); + + methods.add_method("match", |lua, this, table: mlua::Table| { + #match_match + }); + } + } + + impl crate::create_ast_node::CreateAstNode for #input_ident { + type Node = full_moon::ast::#input_ident; + + fn create_ast_node(&self) -> Option { + #match_create_ast_node + } + } + } + .into() +} diff --git a/full-moon-lua-types/Cargo.toml b/full-moon-lua-types/Cargo.toml index 862a40fa..dc0d150b 100644 --- a/full-moon-lua-types/Cargo.toml +++ b/full-moon-lua-types/Cargo.toml @@ -7,6 +7,7 @@ edition = "2021" [dependencies] full_moon = { version = "0.15.1", path = "../full-moon" } +full_moon_lua_types_derive = { path = "../full-moon-lua-types-derive" } mlua = { version = "0.8.3", features = ["luau"] } [features] diff --git a/full-moon-lua-types/src/core.rs b/full-moon-lua-types/src/core.rs index ba9134fc..4488fe59 100644 --- a/full-moon-lua-types/src/core.rs +++ b/full-moon-lua-types/src/core.rs @@ -1,29 +1,43 @@ +use std::sync::{Arc, RwLock}; + use full_moon::{ast, node::Node, tokenizer}; -use mlua::UserData; +use full_moon_lua_types_derive::LuaUserData; +use mlua::{Table, UserData}; -use crate::{mlua_util::add_to_string_display, shared::*}; +use crate::{ + create_ast_node::CreateAstNode, + mlua_util::{ + add_core_meta_methods, add_newindex_block, add_print, add_to_string_display, ArcLocked, + }, + prepare_for_lua::PrepareForLua, + shared::*, +}; + +fn l(t: T) -> ArcLocked { + Arc::new(RwLock::new(t)) +} pub struct Ast { - nodes: Block, - eof: TokenReference, + nodes: ArcLocked, + eof: ArcLocked, } impl From for Ast { fn from(ast: ast::Ast) -> Self { Ast { - nodes: Block::new(ast.nodes()), - eof: TokenReference::new(ast.eof()), + nodes: l(Block::new(ast.nodes())), + eof: l(TokenReference::new(ast.eof())), } } } impl UserData for Ast { fn add_fields<'lua, F: mlua::UserDataFields<'lua, Self>>(fields: &mut F) { - // fields.add_field_method_get("nodes", |_, Ast { nodes, .. }| Ok(nodes)) + fields.add_field_method_get("nodes", |_, Ast { nodes, .. }| Ok(nodes.clone())); } fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) { - add_to_string_display("Ast", methods); + add_core_meta_methods("Ast", methods); } } @@ -46,61 +60,73 @@ impl Assignment { impl UserData for Assignment { fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) { add_to_string_display("Assignment", methods); + add_print(methods); + } +} + +impl CreateAstNode for Assignment { + type Node = ast::Assignment; + + fn create_ast_node(&self) -> Option { + Some( + ast::Assignment::new( + self.var_list.create_ast_node()?, + self.expr_list.create_ast_node()?, + ) + .with_equal_token(self.equal_token.create_ast_node()?), + ) } } +#[derive(LuaUserData)] pub enum BinOp { - And(TokenReference), - Caret(TokenReference), - GreaterThan(TokenReference), - GreaterThanEqual(TokenReference), - LessThan(TokenReference), - LessThanEqual(TokenReference), - Minus(TokenReference), - Or(TokenReference), - Percent(TokenReference), - Plus(TokenReference), - Slash(TokenReference), - Star(TokenReference), - TildeEqual(TokenReference), - TwoDots(TokenReference), - TwoEqual(TokenReference), + And(ArcLocked), + Caret(ArcLocked), + GreaterThan(ArcLocked), + GreaterThanEqual(ArcLocked), + LessThan(ArcLocked), + LessThanEqual(ArcLocked), + Minus(ArcLocked), + Or(ArcLocked), + Percent(ArcLocked), + Plus(ArcLocked), + Slash(ArcLocked), + Star(ArcLocked), + TildeEqual(ArcLocked), + TwoDots(ArcLocked), + TwoEqual(ArcLocked), } impl BinOp { fn new(bin_op: &ast::BinOp) -> Self { match bin_op { - ast::BinOp::And(token) => BinOp::And(TokenReference::new(&token)), - ast::BinOp::Caret(token) => BinOp::Caret(TokenReference::new(&token)), - ast::BinOp::GreaterThan(token) => BinOp::GreaterThan(TokenReference::new(&token)), + ast::BinOp::And(token) => BinOp::And(l(TokenReference::new(&token))), + ast::BinOp::Caret(token) => BinOp::Caret(l(TokenReference::new(&token))), + ast::BinOp::GreaterThan(token) => BinOp::GreaterThan(l(TokenReference::new(&token))), ast::BinOp::GreaterThanEqual(token) => { - BinOp::GreaterThanEqual(TokenReference::new(&token)) + BinOp::GreaterThanEqual(l(TokenReference::new(&token))) } - ast::BinOp::LessThan(token) => BinOp::LessThan(TokenReference::new(&token)), - ast::BinOp::LessThanEqual(token) => BinOp::LessThanEqual(TokenReference::new(&token)), - ast::BinOp::Minus(token) => BinOp::Minus(TokenReference::new(&token)), - ast::BinOp::Or(token) => BinOp::Or(TokenReference::new(&token)), - ast::BinOp::Percent(token) => BinOp::Percent(TokenReference::new(&token)), - ast::BinOp::Plus(token) => BinOp::Plus(TokenReference::new(&token)), - ast::BinOp::Slash(token) => BinOp::Slash(TokenReference::new(&token)), - ast::BinOp::Star(token) => BinOp::Star(TokenReference::new(&token)), - ast::BinOp::TildeEqual(token) => BinOp::TildeEqual(TokenReference::new(&token)), - ast::BinOp::TwoDots(token) => BinOp::TwoDots(TokenReference::new(&token)), - ast::BinOp::TwoEqual(token) => BinOp::TwoEqual(TokenReference::new(&token)), + ast::BinOp::LessThan(token) => BinOp::LessThan(l(TokenReference::new(&token))), + ast::BinOp::LessThanEqual(token) => { + BinOp::LessThanEqual(l(TokenReference::new(&token))) + } + ast::BinOp::Minus(token) => BinOp::Minus(l(TokenReference::new(&token))), + ast::BinOp::Or(token) => BinOp::Or(l(TokenReference::new(&token))), + ast::BinOp::Percent(token) => BinOp::Percent(l(TokenReference::new(&token))), + ast::BinOp::Plus(token) => BinOp::Plus(l(TokenReference::new(&token))), + ast::BinOp::Slash(token) => BinOp::Slash(l(TokenReference::new(&token))), + ast::BinOp::Star(token) => BinOp::Star(l(TokenReference::new(&token))), + ast::BinOp::TildeEqual(token) => BinOp::TildeEqual(l(TokenReference::new(&token))), + ast::BinOp::TwoDots(token) => BinOp::TwoDots(l(TokenReference::new(&token))), + ast::BinOp::TwoEqual(token) => BinOp::TwoEqual(l(TokenReference::new(&token))), other => panic!("unimplemented BinOp: {other:?}"), } } } -impl UserData for BinOp { - fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) { - add_to_string_display("BinOp", methods); - } -} - pub struct Block { - stmts: Vec<(Stmt, Option)>, - last_stmt: Option<(LastStmt, Option)>, + stmts: Vec<(ArcLocked, Option>)>, + last_stmt: Option<(ArcLocked, Option>)>, } impl Block { @@ -108,7 +134,12 @@ impl Block { Block { stmts: block .stmts_with_semicolon() - .map(|(stmt, token)| (Stmt::new(stmt), token.as_ref().map(TokenReference::new))) + .map(|(stmt, token)| { + ( + l(Stmt::new(stmt)), + token.as_ref().map(TokenReference::new).map(l), + ) + }) .collect(), last_stmt: block @@ -116,8 +147,8 @@ impl Block { .as_ref() .map(|(last_stmt, token)| { ( - LastStmt::new(last_stmt), - token.as_ref().map(TokenReference::new), + l(LastStmt::new(last_stmt)), + token.as_ref().map(TokenReference::new).map(l), ) }), } @@ -125,34 +156,59 @@ impl Block { } impl UserData for Block { + fn add_fields<'lua, F: mlua::UserDataFields<'lua, Self>>(fields: &mut F) { + fields.add_field_method_get("stmts", |_, Block { stmts, .. }| { + Ok(stmts + .iter() + .map(|(stmt, _)| stmt.clone()) + .collect::>()) + }); + } + fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) { - add_to_string_display("Block", methods); + add_core_meta_methods("Block", methods); + } +} + +impl CreateAstNode for Block { + type Node = ast::Block; + + fn create_ast_node(&self) -> Option { + Some( + ast::Block::new() + .with_stmts( + self.stmts + .iter() + .map(|(stmt, token)| { + Some((stmt.create_ast_node()?, token.create_ast_node())) + }) + .collect::>>()?, + ) + .with_last_stmt(self.last_stmt.as_ref().map(|(last_stmt, token)| { + Some((last_stmt.create_ast_node()?, token.create_ast_node())) + })?), + ) } } +#[derive(LuaUserData)] pub enum Call { - AnonymousCall(FunctionArgs), - MethodCall(MethodCall), + AnonymousCall(ArcLocked), + MethodCall(ArcLocked), } impl Call { fn new(call: &ast::Call) -> Self { match call { ast::Call::AnonymousCall(function_args) => { - Call::AnonymousCall(FunctionArgs::new(function_args)) + Call::AnonymousCall(l(FunctionArgs::new(function_args))) } - ast::Call::MethodCall(method_call) => Call::MethodCall(MethodCall::new(method_call)), + ast::Call::MethodCall(method_call) => Call::MethodCall(l(MethodCall::new(method_call))), other => panic!("unimplemented Call: {other:?}"), } } } -impl UserData for Call { - fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) { - add_to_string_display("Call", methods); - } -} - pub struct Do { do_token: TokenReference, block: Block, @@ -175,6 +231,19 @@ impl UserData for Do { } } +impl CreateAstNode for Do { + type Node = ast::Do; + + fn create_ast_node(&self) -> Option { + Some( + ast::Do::new() + .with_block(self.block.create_ast_node()?) + .with_do_token(self.do_token.create_ast_node()?) + .with_end_token(self.end_token.create_ast_node()?), + ) + } +} + pub struct ElseIf { else_if_token: TokenReference, condition: Expression, @@ -199,25 +268,39 @@ impl UserData for ElseIf { } } +impl CreateAstNode for ElseIf { + type Node = ast::ElseIf; + + fn create_ast_node(&self) -> Option { + Some( + ast::ElseIf::new(self.condition.create_ast_node()?) + .with_block(self.block.create_ast_node()?) + .with_else_if_token(self.else_if_token.create_ast_node()?) + .with_then_token(self.then_token.create_ast_node()?), + ) + } +} + +#[derive(Clone, LuaUserData)] pub enum Expression { BinaryOperator { - lhs: Box, - binop: BinOp, - rhs: Box, + lhs: Box>, + binop: ArcLocked, + rhs: Box>, }, Parentheses { - contained: ContainedSpan, - expression: Box, + contained: ArcLocked, + expression: Box>, }, UnaryOperator { - unop: UnOp, - expression: Box, + unop: ArcLocked, + expression: Box>, }, Value { - value: Box, + value: Box>, }, } @@ -225,26 +308,26 @@ impl Expression { fn new(expression: &ast::Expression) -> Self { match expression { ast::Expression::BinaryOperator { lhs, binop, rhs } => Expression::BinaryOperator { - lhs: Box::new(Expression::new(lhs)), - binop: BinOp::new(binop), - rhs: Box::new(Expression::new(rhs)), + lhs: Box::new(l(Expression::new(lhs))), + binop: l(BinOp::new(binop)), + rhs: Box::new(l(Expression::new(rhs))), }, ast::Expression::Parentheses { contained, expression, } => Expression::Parentheses { - contained: ContainedSpan::new(contained), - expression: Box::new(Expression::new(expression)), + contained: l(ContainedSpan::new(contained)), + expression: Box::new(l(Expression::new(expression))), }, ast::Expression::UnaryOperator { unop, expression } => Expression::UnaryOperator { - unop: UnOp::new(unop), - expression: Box::new(Expression::new(expression)), + unop: l(UnOp::new(unop)), + expression: Box::new(l(Expression::new(expression))), }, ast::Expression::Value { value } => Expression::Value { - value: Box::new(Value::new(value)), + value: Box::new(l(Value::new(value))), }, other => panic!("unimplemented Expression: {other:?}"), @@ -252,21 +335,16 @@ impl Expression { } } -impl UserData for Expression { - fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) { - add_to_string_display("Expression", methods); - } -} - +#[derive(LuaUserData)] pub enum FunctionArgs { Parentheses { - contained: ContainedSpan, - expressions: Punctuated, + parentheses: ArcLocked, + arguments: ArcLocked>, }, - String(TokenReference), + String(ArcLocked), - TableConstructor(TableConstructor), + TableConstructor(ArcLocked), } impl FunctionArgs { @@ -276,14 +354,14 @@ impl FunctionArgs { parentheses, arguments, } => FunctionArgs::Parentheses { - contained: ContainedSpan::new(parentheses), - expressions: Punctuated::map_from_punctuated(arguments, Expression::new), + parentheses: l(ContainedSpan::new(parentheses)), + arguments: l(Punctuated::map_from_punctuated(arguments, Expression::new)), }, - ast::FunctionArgs::String(token) => FunctionArgs::String(TokenReference::new(token)), + ast::FunctionArgs::String(token) => FunctionArgs::String(l(TokenReference::new(token))), ast::FunctionArgs::TableConstructor(table_constructor) => { - FunctionArgs::TableConstructor(TableConstructor::new(table_constructor)) + FunctionArgs::TableConstructor(l(TableConstructor::new(table_constructor))) } other => panic!("unimplemented FunctionArgs: {other:?}"), @@ -291,12 +369,6 @@ impl FunctionArgs { } } -impl UserData for FunctionArgs { - fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) { - add_to_string_display("FunctionArgs", methods); - } -} - pub struct FunctionBody { parameters_parentheses: ContainedSpan, parameters: Punctuated, @@ -323,51 +395,63 @@ impl UserData for FunctionBody { } } +impl CreateAstNode for FunctionBody { + type Node = ast::FunctionBody; + + fn create_ast_node(&self) -> Option { + Some( + ast::FunctionBody::new() + .with_block(self.block.create_ast_node()?) + .with_end_token(self.end_token.create_ast_node()?) + .with_parameters(self.parameters.create_ast_node()?) + .with_parameters_parentheses(self.parameters_parentheses.create_ast_node()?), + ) + } +} + +#[derive(LuaUserData)] pub enum LastStmt { - Break(TokenReference), + Break(ArcLocked), #[cfg(feature = "luau")] - Continue(TokenReference), - Return(Return), + Continue(ArcLocked), + Return(ArcLocked), } impl LastStmt { fn new(last_stmt: &ast::LastStmt) -> Self { match last_stmt { - ast::LastStmt::Break(break_token) => LastStmt::Break(TokenReference::new(break_token)), + ast::LastStmt::Break(break_token) => { + LastStmt::Break(l(TokenReference::new(break_token))) + } #[cfg(feature = "luau")] ast::LastStmt::Continue(continue_token) => { - LastStmt::Continue(TokenReference::new(continue_token)) + LastStmt::Continue(l(TokenReference::new(continue_token))) } - ast::LastStmt::Return(return_token) => LastStmt::Return(Return::new(return_token)), + ast::LastStmt::Return(return_token) => LastStmt::Return(l(Return::new(return_token))), _ => unimplemented!("unexpected LastStmt variant: {last_stmt:#?}"), } } } -impl UserData for LastStmt { - fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) { - add_to_string_display("LastStmt", methods); - } -} - +#[derive(LuaUserData)] pub enum Field { ExpressionKey { - brackets: ContainedSpan, - key: Expression, - equal: TokenReference, - value: Expression, + brackets: ArcLocked, + key: ArcLocked, + equal: ArcLocked, + value: ArcLocked, }, NameKey { - key: TokenReference, - equal: TokenReference, - value: Expression, + key: ArcLocked, + equal: ArcLocked, + value: ArcLocked, }, - NoKey(Expression), + NoKey(ArcLocked), } impl Field { @@ -379,31 +463,25 @@ impl Field { equal, value, } => Field::ExpressionKey { - brackets: ContainedSpan::new(brackets), - key: Expression::new(key), - equal: TokenReference::new(equal), - value: Expression::new(value), + brackets: l(ContainedSpan::new(brackets)), + key: l(Expression::new(key)), + equal: l(TokenReference::new(equal)), + value: l(Expression::new(value)), }, ast::Field::NameKey { key, equal, value } => Field::NameKey { - key: TokenReference::new(key), - equal: TokenReference::new(equal), - value: Expression::new(value), + key: l(TokenReference::new(key)), + equal: l(TokenReference::new(equal)), + value: l(Expression::new(value)), }, - ast::Field::NoKey(expression) => Field::NoKey(Expression::new(expression)), + ast::Field::NoKey(expression) => Field::NoKey(l(Expression::new(expression))), other => panic!("unimplemented Field: {other:?}"), } } } -impl UserData for Field { - fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) { - add_to_string_display("Field", methods); - } -} - pub struct FunctionCall { prefix: Prefix, suffixes: Vec, @@ -424,6 +502,21 @@ impl UserData for FunctionCall { } } +impl CreateAstNode for FunctionCall { + type Node = ast::FunctionCall; + + fn create_ast_node(&self) -> Option { + Some( + ast::FunctionCall::new(self.prefix.create_ast_node()?).with_suffixes( + self.suffixes + .iter() + .map(Suffix::create_ast_node) + .collect::>>()?, + ), + ) + } +} + pub struct FunctionDeclaration { function_token: TokenReference, name: FunctionName, @@ -446,6 +539,18 @@ impl UserData for FunctionDeclaration { } } +impl CreateAstNode for FunctionDeclaration { + type Node = ast::FunctionDeclaration; + + fn create_ast_node(&self) -> Option { + Some( + ast::FunctionDeclaration::new(self.name.create_ast_node()?) + .with_body(self.body.create_ast_node()?) + .with_function_token(self.function_token.create_ast_node()?), + ) + } +} + pub struct FunctionName { names: Punctuated, colon_name: Option<(TokenReference, TokenReference)>, @@ -473,6 +578,21 @@ impl UserData for FunctionName { } } +impl CreateAstNode for FunctionName { + type Node = ast::FunctionName; + + fn create_ast_node(&self) -> Option { + Some( + ast::FunctionName::new(self.names.create_ast_node()?).with_method( + self.colon_name + .as_ref() + .map(|(colon, name)| Some((colon.create_ast_node()?, name.create_ast_node()?))) + .flatten(), + ), + ) + } +} + pub struct GenericFor { for_token: TokenReference, names: Punctuated, @@ -503,6 +623,24 @@ impl UserData for GenericFor { } } +impl CreateAstNode for GenericFor { + type Node = ast::GenericFor; + + fn create_ast_node(&self) -> Option { + Some( + ast::GenericFor::new( + self.names.create_ast_node()?, + self.expr_list.create_ast_node()?, + ) + .with_for_token(self.for_token.create_ast_node()?) + .with_in_token(self.in_token.create_ast_node()?) + .with_do_token(self.do_token.create_ast_node()?) + .with_block(self.block.create_ast_node()?) + .with_end_token(self.end_token.create_ast_node()?), + ) + } +} + pub struct If { if_token: TokenReference, condition: Expression, @@ -537,15 +675,43 @@ impl UserData for If { } } +impl CreateAstNode for If { + type Node = ast::If; + + fn create_ast_node(&self) -> Option { + Some( + ast::If::new(self.condition.create_ast_node()?) + .with_if_token(self.if_token.create_ast_node()?) + .with_then_token(self.then_token.create_ast_node()?) + .with_block(self.block.create_ast_node()?) + .with_else_if( + self.else_if + .as_ref() + .map(|else_if| { + else_if + .iter() + .map(ElseIf::create_ast_node) + .collect::>>() + }) + .flatten(), + ) + .with_else_token(self.else_token.create_ast_node()) + .with_else(self.else_block.create_ast_node()) + .with_end_token(self.end_token.create_ast_node()?), + ) + } +} + +#[derive(LuaUserData)] pub enum Index { Brackets { - brackets: ContainedSpan, - expression: Expression, + brackets: ArcLocked, + expression: ArcLocked, }, Dot { - dot: TokenReference, - name: TokenReference, + dot: ArcLocked, + name: ArcLocked, }, } @@ -556,13 +722,13 @@ impl Index { brackets, expression, } => Index::Brackets { - brackets: ContainedSpan::new(brackets), - expression: Expression::new(expression), + brackets: l(ContainedSpan::new(brackets)), + expression: l(Expression::new(expression)), }, ast::Index::Dot { dot, name } => Index::Dot { - dot: TokenReference::new(dot), - name: TokenReference::new(name), + dot: l(TokenReference::new(dot)), + name: l(TokenReference::new(name)), }, other => panic!("unimplemented Index: {other:?}"), @@ -570,12 +736,6 @@ impl Index { } } -impl UserData for Index { - fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) { - add_to_string_display("Index", methods); - } -} - pub struct LocalAssignment { local_token: TokenReference, name_list: Punctuated, @@ -606,6 +766,19 @@ impl UserData for LocalAssignment { } } +impl CreateAstNode for LocalAssignment { + type Node = ast::LocalAssignment; + + fn create_ast_node(&self) -> Option { + Some( + ast::LocalAssignment::new(self.name_list.create_ast_node()?) + .with_expressions(self.expr_list.create_ast_node()?) + .with_local_token(self.local_token.create_ast_node()?) + .with_equal_token(self.equal_token.create_ast_node()), + ) + } +} + pub struct LocalFunction { local_token: TokenReference, function_token: TokenReference, @@ -630,6 +803,19 @@ impl UserData for LocalFunction { } } +impl CreateAstNode for LocalFunction { + type Node = ast::LocalFunction; + + fn create_ast_node(&self) -> Option { + Some( + ast::LocalFunction::new(self.name.create_ast_node()?) + .with_body(self.body.create_ast_node()?) + .with_local_token(self.local_token.create_ast_node()?) + .with_function_token(self.function_token.create_ast_node()?), + ) + } +} + pub struct MethodCall { colon_token: TokenReference, name: TokenReference, @@ -652,6 +838,17 @@ impl UserData for MethodCall { } } +impl CreateAstNode for MethodCall { + type Node = ast::MethodCall; + + fn create_ast_node(&self) -> Option { + Some( + ast::MethodCall::new(self.name.create_ast_node()?, self.args.create_ast_node()?) + .with_colon_token(self.colon_token.create_ast_node()?), + ) + } +} + pub struct NumericFor { for_token: TokenReference, index_variable: TokenReference, @@ -690,52 +887,64 @@ impl UserData for NumericFor { } } +impl CreateAstNode for NumericFor { + type Node = ast::NumericFor; + + fn create_ast_node(&self) -> Option { + Some( + ast::NumericFor::new( + self.index_variable.create_ast_node()?, + self.start.create_ast_node()?, + self.end.create_ast_node()?, + ) + .with_step(self.step.create_ast_node()) + .with_block(self.block.create_ast_node()?) + .with_end_token(self.end_token.create_ast_node()?) + .with_start_end_comma(self.start_end_comma.create_ast_node()?) + .with_end_step_comma(self.end_step_comma.create_ast_node()) + .with_for_token(self.for_token.create_ast_node()?) + .with_equal_token(self.equal_token.create_ast_node()?) + .with_do_token(self.do_token.create_ast_node()?), + ) + } +} + +#[derive(LuaUserData)] pub enum Parameter { - Ellipse(TokenReference), - Name(TokenReference), + Ellipse(ArcLocked), + Name(ArcLocked), } impl Parameter { fn new(parameter: &ast::Parameter) -> Self { match parameter { ast::Parameter::Ellipse(ellipse_token) => { - Parameter::Ellipse(TokenReference::new(ellipse_token)) + Parameter::Ellipse(l(TokenReference::new(ellipse_token))) } - ast::Parameter::Name(name_token) => Parameter::Name(TokenReference::new(name_token)), + ast::Parameter::Name(name_token) => Parameter::Name(l(TokenReference::new(name_token))), _ => unimplemented!("unexpected Parameter variant: {parameter:#?}"), } } } -impl UserData for Parameter { - fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) { - add_to_string_display("Parameter", methods); - } -} - +#[derive(LuaUserData)] pub enum Prefix { - Expression(Expression), - Name(TokenReference), + Expression(ArcLocked), + Name(ArcLocked), } impl Prefix { fn new(prefix: &ast::Prefix) -> Self { match prefix { - ast::Prefix::Expression(expr) => Prefix::Expression(Expression::new(expr)), - ast::Prefix::Name(name) => Prefix::Name(TokenReference::new(name)), + ast::Prefix::Expression(expr) => Prefix::Expression(l(Expression::new(expr))), + ast::Prefix::Name(name) => Prefix::Name(l(TokenReference::new(name))), other => unimplemented!("unexpected Prefix variant: {other:?}"), } } } -impl UserData for Prefix { - fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) { - add_to_string_display("Prefix", methods); - } -} - pub struct Return { token: TokenReference, returns: Punctuated, @@ -756,6 +965,18 @@ impl UserData for Return { } } +impl CreateAstNode for Return { + type Node = ast::Return; + + fn create_ast_node(&self) -> Option { + Some( + ast::Return::new() + .with_token(self.token.create_ast_node()?) + .with_returns(self.returns.create_ast_node()?), + ) + } +} + pub struct Repeat { repeat_token: TokenReference, block: Block, @@ -780,82 +1001,81 @@ impl UserData for Repeat { } } +impl CreateAstNode for Repeat { + type Node = ast::Repeat; + + fn create_ast_node(&self) -> Option { + Some( + ast::Repeat::new(self.until.create_ast_node()?) + .with_repeat_token(self.repeat_token.create_ast_node()?) + .with_block(self.block.create_ast_node()?) + .with_until_token(self.until_token.create_ast_node()?), + ) + } +} + +#[derive(LuaUserData)] pub enum Stmt { - Assignment(Assignment), - Do(Do), - FunctionCall(FunctionCall), - FunctionDeclaration(FunctionDeclaration), - GenericFor(GenericFor), - If(If), - LocalAssignment(LocalAssignment), - LocalFunction(LocalFunction), - NumericFor(NumericFor), - Repeat(Repeat), - While(While), + Assignment(ArcLocked), + Do(ArcLocked), + FunctionCall(ArcLocked), + FunctionDeclaration(ArcLocked), + GenericFor(ArcLocked), + If(ArcLocked), + LocalAssignment(ArcLocked), + LocalFunction(ArcLocked), + NumericFor(ArcLocked), + Repeat(ArcLocked), + While(ArcLocked), - NonStandard(Vec), + NonStandard(Vec>), } impl Stmt { fn new(stmt: &ast::Stmt) -> Self { match stmt { - ast::Stmt::Assignment(assignment) => Stmt::Assignment(Assignment::new(assignment)), - ast::Stmt::Do(do_token) => Stmt::Do(Do::new(do_token)), + ast::Stmt::Assignment(assignment) => Stmt::Assignment(l(Assignment::new(assignment))), + ast::Stmt::Do(do_token) => Stmt::Do(l(Do::new(do_token))), ast::Stmt::FunctionCall(function_call) => { - Stmt::FunctionCall(FunctionCall::new(function_call)) + Stmt::FunctionCall(l(FunctionCall::new(function_call))) } ast::Stmt::FunctionDeclaration(function_declaration) => { - Stmt::FunctionDeclaration(FunctionDeclaration::new(function_declaration)) + Stmt::FunctionDeclaration(l(FunctionDeclaration::new(function_declaration))) } - ast::Stmt::GenericFor(generic_for) => Stmt::GenericFor(GenericFor::new(generic_for)), - ast::Stmt::If(if_token) => Stmt::If(If::new(if_token)), + ast::Stmt::GenericFor(generic_for) => Stmt::GenericFor(l(GenericFor::new(generic_for))), + ast::Stmt::If(if_token) => Stmt::If(l(If::new(if_token))), ast::Stmt::LocalAssignment(local_assignment) => { - Stmt::LocalAssignment(LocalAssignment::new(local_assignment)) + Stmt::LocalAssignment(l(LocalAssignment::new(local_assignment))) } ast::Stmt::LocalFunction(local_function) => { - Stmt::LocalFunction(LocalFunction::new(local_function)) + Stmt::LocalFunction(l(LocalFunction::new(local_function))) } - ast::Stmt::NumericFor(numeric_for) => Stmt::NumericFor(NumericFor::new(numeric_for)), - ast::Stmt::Repeat(repeat_token) => Stmt::Repeat(Repeat::new(repeat_token)), - ast::Stmt::While(while_token) => Stmt::While(While::new(while_token)), + ast::Stmt::NumericFor(numeric_for) => Stmt::NumericFor(l(NumericFor::new(numeric_for))), + ast::Stmt::Repeat(repeat_token) => Stmt::Repeat(l(Repeat::new(repeat_token))), + ast::Stmt::While(while_token) => Stmt::While(l(While::new(while_token))), // TODO: Support everything, then make this `unimplemented!` - _ => Stmt::NonStandard( - stmt.tokens() - .map(|token| TokenReference::new(token)) - .collect(), - ), + _ => Stmt::NonStandard(stmt.tokens().map(TokenReference::new).map(l).collect()), } } } -impl UserData for Stmt { - fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) { - add_to_string_display("Stmt", methods); - } -} - +#[derive(LuaUserData)] pub enum Suffix { - Call(Call), - Index(Index), + Call(ArcLocked), + Index(ArcLocked), } impl Suffix { fn new(suffix: &ast::Suffix) -> Self { match suffix { - ast::Suffix::Call(call) => Suffix::Call(Call::new(call)), - ast::Suffix::Index(index) => Suffix::Index(Index::new(index)), + ast::Suffix::Call(call) => Suffix::Call(l(Call::new(call))), + ast::Suffix::Index(index) => Suffix::Index(l(Index::new(index))), other => unimplemented!("unexpected Suffix variant: {other:#?}"), } } } -impl UserData for Suffix { - fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) { - add_to_string_display("Suffix", methods); - } -} - pub struct TableConstructor { braces: ContainedSpan, fields: Punctuated, @@ -876,104 +1096,99 @@ impl UserData for TableConstructor { } } +impl CreateAstNode for TableConstructor { + type Node = ast::TableConstructor; + + fn create_ast_node(&self) -> Option { + Some( + ast::TableConstructor::new() + .with_braces(self.braces.create_ast_node()?) + .with_fields(self.fields.create_ast_node()?), + ) + } +} + +#[derive(LuaUserData)] pub enum UnOp { - Minus(TokenReference), - Not(TokenReference), - Hash(TokenReference), + Minus(ArcLocked), + Not(ArcLocked), + Hash(ArcLocked), } impl UnOp { fn new(unop: &ast::UnOp) -> Self { match unop { - ast::UnOp::Minus(token) => UnOp::Minus(TokenReference::new(token)), - ast::UnOp::Not(token) => UnOp::Not(TokenReference::new(token)), - ast::UnOp::Hash(token) => UnOp::Hash(TokenReference::new(token)), + ast::UnOp::Minus(token) => UnOp::Minus(l(TokenReference::new(token))), + ast::UnOp::Not(token) => UnOp::Not(l(TokenReference::new(token))), + ast::UnOp::Hash(token) => UnOp::Hash(l(TokenReference::new(token))), other => panic!("unimplemented UnOp: {other:?}"), } } } -impl UserData for UnOp { - fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) { - add_to_string_display("UnOp", methods); - } -} - +#[derive(LuaUserData)] pub enum Value { - Function((TokenReference, FunctionBody)), - FunctionCall(FunctionCall), - TableConstructor(TableConstructor), - Number(TokenReference), - ParenthesesExpression(Expression), - String(TokenReference), - Symbol(TokenReference), - Var(Var), + #[lua( + create_ast_node = "ast::Value::Function((_0.create_ast_node()?, _1.create_ast_node()?))" + )] + Function(ArcLocked, ArcLocked), + FunctionCall(ArcLocked), + TableConstructor(ArcLocked), + Number(ArcLocked), + ParenthesesExpression(ArcLocked), + String(ArcLocked), + Symbol(ArcLocked), + Var(ArcLocked), - NonStandard(Vec), + NonStandard(Vec>), } impl Value { pub fn new(value: &ast::Value) -> Self { match value { - ast::Value::Function((token_reference, function_body)) => Value::Function(( - TokenReference::new(token_reference), - FunctionBody::new(function_body), - )), + ast::Value::Function((token_reference, function_body)) => Value::Function( + l(TokenReference::new(token_reference)), + l(FunctionBody::new(function_body)), + ), ast::Value::FunctionCall(function_call) => { - Value::FunctionCall(FunctionCall::new(function_call)) + Value::FunctionCall(l(FunctionCall::new(function_call))) } ast::Value::TableConstructor(table_constructor) => { - Value::TableConstructor(TableConstructor::new(table_constructor)) + Value::TableConstructor(l(TableConstructor::new(table_constructor))) } - ast::Value::Number(number) => Value::Number(TokenReference::new(number)), + ast::Value::Number(number) => Value::Number(l(TokenReference::new(number))), ast::Value::ParenthesesExpression(expression) => { - Value::ParenthesesExpression(Expression::new(expression)) + Value::ParenthesesExpression(l(Expression::new(expression))) } - ast::Value::String(string) => Value::String(TokenReference::new(string)), - ast::Value::Symbol(symbol) => Value::Symbol(TokenReference::new(symbol)), - ast::Value::Var(var) => Value::Var(Var::new(var)), + ast::Value::String(string) => Value::String(l(TokenReference::new(string))), + ast::Value::Symbol(symbol) => Value::Symbol(l(TokenReference::new(symbol))), + ast::Value::Var(var) => Value::Var(l(Var::new(var))), // TODO: implement everything, then `unimplemented!` - other => Value::NonStandard( - other - .tokens() - .map(|token| TokenReference::new(token)) - .collect(), - ), + other => Value::NonStandard(other.tokens().map(TokenReference::new).map(l).collect()), } } } -impl UserData for Value { - fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) { - add_to_string_display("Value", methods); - } -} - +#[derive(LuaUserData)] pub enum Var { - Expression(VarExpression), - Name(TokenReference), + Expression(ArcLocked), + Name(ArcLocked), } impl Var { fn new(var: &ast::Var) -> Self { match var { - ast::Var::Expression(expression) => Var::Expression(VarExpression::new(expression)), - ast::Var::Name(name_token) => Var::Name(TokenReference::new(name_token)), + ast::Var::Expression(expression) => Var::Expression(l(VarExpression::new(expression))), + ast::Var::Name(name_token) => Var::Name(l(TokenReference::new(name_token))), other => unimplemented!("unexpected Var variant: {var:#?}"), } } } -impl UserData for Var { - fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) { - add_to_string_display("Var", methods); - } -} - pub struct VarExpression { prefix: Prefix, suffixes: Vec, @@ -997,6 +1212,21 @@ impl UserData for VarExpression { } } +impl CreateAstNode for VarExpression { + type Node = ast::VarExpression; + + fn create_ast_node(&self) -> Option { + Some( + ast::VarExpression::new(self.prefix.create_ast_node()?).with_suffixes( + self.suffixes + .iter() + .map(|suffix| suffix.create_ast_node()) + .collect::>>()?, + ), + ) + } +} + pub struct While { while_token: TokenReference, condition: Expression, @@ -1022,3 +1252,17 @@ impl UserData for While { add_to_string_display("While", methods); } } + +impl CreateAstNode for While { + type Node = ast::While; + + fn create_ast_node(&self) -> Option { + Some( + ast::While::new(self.condition.create_ast_node()?) + .with_block(self.block.create_ast_node()?) + .with_do_token(self.do_token.create_ast_node()?) + .with_end_token(self.end_token.create_ast_node()?) + .with_while_token(self.while_token.create_ast_node()?), + ) + } +} diff --git a/full-moon-lua-types/src/create_ast_node.rs b/full-moon-lua-types/src/create_ast_node.rs new file mode 100644 index 00000000..7dc6b12f --- /dev/null +++ b/full-moon-lua-types/src/create_ast_node.rs @@ -0,0 +1,41 @@ +use std::sync::Arc; + +use crate::mlua_util::ArcLocked; + +pub trait CreateAstNode { + type Node; + + fn create_ast_node(&self) -> Option; +} + +impl CreateAstNode for Box { + type Node = Box; + + fn create_ast_node(&self) -> Option { + Some(Box::new((**self).create_ast_node()?)) + } +} + +impl CreateAstNode for Option { + type Node = T::Node; + + fn create_ast_node(&self) -> Option { + self.as_ref().and_then(|value| value.create_ast_node()) + } +} + +impl CreateAstNode for ArcLocked { + type Node = T::Node; + + fn create_ast_node(&self) -> Option { + Arc::clone(self).read().unwrap().create_ast_node() + } +} + +impl CreateAstNode for (T, U) { + type Node = (T::Node, U::Node); + + fn create_ast_node(&self) -> Option { + Some((self.0.create_ast_node()?, self.1.create_ast_node()?)) + } +} diff --git a/full-moon-lua-types/src/lib.rs b/full-moon-lua-types/src/lib.rs index 36d8a1f6..5797599c 100644 --- a/full-moon-lua-types/src/lib.rs +++ b/full-moon-lua-types/src/lib.rs @@ -2,8 +2,10 @@ #![allow(clippy::large_enum_variant)] mod core; +mod create_ast_node; mod lua; mod mlua_util; +mod prepare_for_lua; mod shared; pub use lua::create_lua; diff --git a/full-moon-lua-types/src/lua.rs b/full-moon-lua-types/src/lua.rs index 919dd304..2af133d9 100644 --- a/full-moon-lua-types/src/lua.rs +++ b/full-moon-lua-types/src/lua.rs @@ -1,4 +1,4 @@ -use crate::core; +use crate::{core, create_ast_node::CreateAstNode}; pub fn create_lua() -> mlua::Result { let lua = mlua::Lua::new(); @@ -11,12 +11,18 @@ pub fn create_lua() -> mlua::Result { fn assign_globals(lua: &mlua::Lua) -> mlua::Result<()> { let globals = lua.globals(); - globals.set( + let full_moon = lua.create_table()?; + + full_moon.set( "parse", lua.create_function(|_, code: String| { let ast = full_moon::parse(&code).expect("NYI: Error on failure"); Ok(core::Ast::from(ast)) })?, - ) + )?; + + globals.set("full_moon", full_moon)?; + + Ok(()) } diff --git a/full-moon-lua-types/src/mlua_util.rs b/full-moon-lua-types/src/mlua_util.rs index 23bb09db..eb2f6869 100644 --- a/full-moon-lua-types/src/mlua_util.rs +++ b/full-moon-lua-types/src/mlua_util.rs @@ -1,10 +1,58 @@ -use mlua::UserData; +use std::sync::{Arc, RwLock}; -pub fn add_to_string_display<'lua, T: UserData, M: mlua::UserDataMethods<'lua, T>>( +use mlua::{ToLua, UserData, UserDataFields}; + +use crate::create_ast_node::CreateAstNode; + +pub type ArcLocked = Arc>; + +pub fn add_core_meta_methods<'lua, T: UserData>( + name: &'static str, + methods: &mut impl mlua::UserDataMethods<'lua, T>, +) { + add_to_string_display(name, methods); + add_newindex_block(name, methods); +} + +pub fn add_core_metamethods_no_tostring<'lua, T: UserData>( name: &'static str, - methods: &mut M, + methods: &mut impl mlua::UserDataMethods<'lua, T>, +) { + add_newindex_block(name, methods); +} + +pub fn add_print<'lua, T, N>(methods: &mut impl mlua::UserDataMethods<'lua, T>) +where + T: UserData + CreateAstNode, + N: std::fmt::Display, +{ + methods.add_method("print", |lua, this, ()| match this.create_ast_node() { + Some(node) => node.to_string().to_lua(lua), + None => Ok(mlua::Value::Nil), + }); +} + +pub fn add_to_string_display<'lua, T: UserData>( + name: &'static str, + methods: &mut impl mlua::UserDataMethods<'lua, T>, ) { methods.add_meta_method(mlua::MetaMethod::ToString, move |_, this, _: ()| { Ok(format!("{name}({:x})", this as *const _ as usize)) }); } + +pub fn add_newindex_block<'lua, T: UserData>( + name: &'static str, + methods: &mut impl mlua::UserDataMethods<'lua, T>, +) { + methods.add_meta_method( + mlua::MetaMethod::NewIndex, + move |_, _, (_, _): (String, mlua::Value)| -> mlua::Result<()> { + // TODO: Detect if withKey exists, and suggest that + + Err(mlua::Error::RuntimeError(format!( + "can't mutate {name} directly", + ))) + }, + ); +} diff --git a/full-moon-lua-types/src/prepare_for_lua.rs b/full-moon-lua-types/src/prepare_for_lua.rs new file mode 100644 index 00000000..b8ab11b0 --- /dev/null +++ b/full-moon-lua-types/src/prepare_for_lua.rs @@ -0,0 +1,31 @@ +use std::sync::Arc; + +use mlua::{ToLua, UserData}; + +use crate::mlua_util::ArcLocked; + +pub trait PrepareForLua { + fn prepare_for_lua<'lua>(&self, lua: &'lua mlua::Lua) -> mlua::Result>; +} + +impl PrepareForLua for ArcLocked { + fn prepare_for_lua<'lua>(&self, lua: &'lua mlua::Lua) -> mlua::Result> { + Arc::clone(self).to_lua(lua) + } +} + +impl PrepareForLua for Vec> { + fn prepare_for_lua<'lua>(&self, lua: &'lua mlua::Lua) -> mlua::Result> { + self.iter() + .map(Arc::clone) + .map(|x| x.to_lua(lua)) + .collect::>>()? + .to_lua(lua) + } +} + +impl PrepareForLua for Box { + fn prepare_for_lua<'lua>(&self, lua: &'lua mlua::Lua) -> mlua::Result> { + (**self).clone().to_lua(lua) + } +} diff --git a/full-moon-lua-types/src/shared.rs b/full-moon-lua-types/src/shared.rs index c4645def..5d5a80e1 100644 --- a/full-moon-lua-types/src/shared.rs +++ b/full-moon-lua-types/src/shared.rs @@ -7,6 +7,11 @@ use full_moon::{ use mlua::{MetaMethod, ToLua, UserData}; +use crate::{ + create_ast_node::CreateAstNode, + mlua_util::{add_core_meta_methods, add_to_string_display}, +}; + pub struct ContainedSpan { start: TokenReference, end: TokenReference, @@ -23,6 +28,23 @@ impl ContainedSpan { } } +impl UserData for ContainedSpan { + fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) { + add_core_meta_methods("ContainedSpan", methods); + } +} + +impl CreateAstNode for ContainedSpan { + type Node = ast::span::ContainedSpan; + + fn create_ast_node(&self) -> Option { + Some(ast::span::ContainedSpan::new( + self.start.create_ast_node()?, + self.end.create_ast_node()?, + )) + } +} + pub struct Position(tokenizer::Position); pub struct Punctuated(ast::punctuated::Punctuated); @@ -44,12 +66,6 @@ impl Punctuated { } } -impl FromIterator> for Punctuated { - fn from_iter>>(iter: I) -> Self { - Punctuated(ast::punctuated::Punctuated::from_iter(iter)) - } -} - impl Punctuated { fn to_table<'lua>(&self, lua: &'lua mlua::Lua) -> mlua::Result> { let table = lua.create_table()?; @@ -62,6 +78,12 @@ impl Punctuated { } } +impl FromIterator> for Punctuated { + fn from_iter>>(iter: I) -> Self { + Punctuated(ast::punctuated::Punctuated::from_iter(iter)) + } +} + impl UserData for Punctuated { fn add_fields<'lua, F: mlua::UserDataFields<'lua, Self>>(_fields: &mut F) {} @@ -79,6 +101,27 @@ impl UserData for Punctuated { } } +impl CreateAstNode for Punctuated { + type Node = ast::punctuated::Punctuated; + + fn create_ast_node(&self) -> Option { + Some(ast::punctuated::Punctuated::from_iter( + self.0 + .pairs() + .map(|pair| { + Some(match pair { + Pair::Punctuated(value, punctuation) => { + Pair::Punctuated(value.create_ast_node()?, punctuation.clone()) + } + + Pair::End(value) => Pair::End(value.create_ast_node()?), + }) + }) + .collect::>>()?, + )) + } +} + pub struct TokenType(tokenizer::TokenType); pub struct Token { @@ -97,6 +140,14 @@ impl From<&tokenizer::Token> for Token { } } +impl CreateAstNode for Token { + type Node = tokenizer::Token; + + fn create_ast_node(&self) -> Option { + Some(tokenizer::Token::new(self.token_type.0.clone())) + } +} + pub struct TokenReference { leading_trivia: Vec, token: Token, @@ -112,3 +163,24 @@ impl TokenReference { } } } + +// TODO +impl UserData for TokenReference {} + +impl CreateAstNode for TokenReference { + type Node = tokenizer::TokenReference; + + fn create_ast_node(&self) -> Option { + Some(tokenizer::TokenReference::new( + self.leading_trivia + .iter() + .map(Token::create_ast_node) + .collect::>>()?, + self.token.create_ast_node()?, + self.trailing_trivia + .iter() + .map(Token::create_ast_node) + .collect::>>()?, + )) + } +} diff --git a/full-moon-lua-types/tests/lua/core.lua b/full-moon-lua-types/tests/lua/core.lua new file mode 100644 index 00000000..3c96190a --- /dev/null +++ b/full-moon-lua-types/tests/lua/core.lua @@ -0,0 +1,40 @@ +local function assertEq(x, y) + if x == y then + return + end + + error(("%s ~= %s"):format(tostring(x), tostring(y))) +end + +local ast = full_moon.parse("x, y = 1, 2") +assert(not pcall(function() + ast.nodes = {} +end), "expected ast.nodes to be read-only") + +local stmt = ast.nodes.stmts[1] + +assertEq(tostring(stmt), "Stmt::Assignment") +assertEq(stmt.kind, "Assignment") + +assertEq( + stmt:match({ + Assignment = function(assignment) + local saysAssignment = tostring(assignment):match("^[A-Za-z]+") + + return assert(saysAssignment, "tostring(assignment) didn't match (" .. tostring(assignment) .. ")") + end, + }), + + "Assignment" +) + +local assignments = {} + +stmt:visit({ + Assignment = function(assignment) + table.insert(assignments, assignment:print()) + end, +}) + +assertEq(#assignments, 1) +assertEq(assignments[1], "x, y = 1, 2") diff --git a/full-moon-lua-types/tests/lua/everything.lua b/full-moon-lua-types/tests/lua/everything.lua index cb8a2cf1..e69de29b 100644 --- a/full-moon-lua-types/tests/lua/everything.lua +++ b/full-moon-lua-types/tests/lua/everything.lua @@ -1,4 +0,0 @@ -local ast - -ast = parse("x, y = 1, 2") -error(tostring(ast)) diff --git a/full-moon-lua-types/tests/lua_tests.rs b/full-moon-lua-types/tests/lua_tests.rs index 5a303edc..2aa28283 100644 --- a/full-moon-lua-types/tests/lua_tests.rs +++ b/full-moon-lua-types/tests/lua_tests.rs @@ -6,6 +6,11 @@ fn test_lua_code(code: &str) { } } +#[test] +fn core() { + test_lua_code(include_str!("lua/core.lua")); +} + #[test] fn everything() { test_lua_code(include_str!("lua/everything.lua")); From ece709e5e33c0216b14558477ba62f954bf4c366 Mon Sep 17 00:00:00 2001 From: Kampfkarren Date: Tue, 13 Sep 2022 07:30:33 -0700 Subject: [PATCH 04/19] :visit --- full-moon-lua-types/Cargo.toml | 1 + full-moon-lua-types/src/core.rs | 89 ++++++----- full-moon-lua-types/src/lib.rs | 1 + full-moon-lua-types/src/mlua_util.rs | 4 +- full-moon-lua-types/src/visitor.rs | 198 +++++++++++++++++++++++++ full-moon-lua-types/tests/lua/core.lua | 22 ++- 6 files changed, 278 insertions(+), 37 deletions(-) create mode 100644 full-moon-lua-types/src/visitor.rs diff --git a/full-moon-lua-types/Cargo.toml b/full-moon-lua-types/Cargo.toml index dc0d150b..45266b9a 100644 --- a/full-moon-lua-types/Cargo.toml +++ b/full-moon-lua-types/Cargo.toml @@ -9,6 +9,7 @@ edition = "2021" full_moon = { version = "0.15.1", path = "../full-moon" } full_moon_lua_types_derive = { path = "../full-moon-lua-types-derive" } mlua = { version = "0.8.3", features = ["luau"] } +paste = "1.0.9" [features] luau = ["full_moon/roblox"] diff --git a/full-moon-lua-types/src/core.rs b/full-moon-lua-types/src/core.rs index 4488fe59..d137595d 100644 --- a/full-moon-lua-types/src/core.rs +++ b/full-moon-lua-types/src/core.rs @@ -7,7 +7,8 @@ use mlua::{Table, UserData}; use crate::{ create_ast_node::CreateAstNode, mlua_util::{ - add_core_meta_methods, add_newindex_block, add_print, add_to_string_display, ArcLocked, + add_core_meta_methods, add_newindex_block, add_print, add_to_string_display, add_visit, + ArcLocked, }, prepare_for_lua::PrepareForLua, shared::*, @@ -38,6 +39,24 @@ impl UserData for Ast { fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) { add_core_meta_methods("Ast", methods); + + crate::visitor::add_visit_with_visitor(methods, |ast, visitor| { + use full_moon::visitors::Visitor; + visitor.visit_ast(&ast); + }); + } +} + +impl CreateAstNode for Ast { + type Node = ast::Ast; + + fn create_ast_node(&self) -> Option { + Some( + ast::Ast::from_tokens(vec![tokenizer::Token::new(tokenizer::TokenType::Eof)]) + .unwrap() + .with_eof(self.eof.create_ast_node()?) + .with_nodes(self.nodes.create_ast_node()?), + ) } } @@ -48,7 +67,7 @@ pub struct Assignment { } impl Assignment { - fn new(assignment: &ast::Assignment) -> Self { + pub fn new(assignment: &ast::Assignment) -> Self { Assignment { var_list: Punctuated::map_from_punctuated(assignment.variables(), Var::new), equal_token: TokenReference::new(assignment.equal_token()), @@ -98,7 +117,7 @@ pub enum BinOp { } impl BinOp { - fn new(bin_op: &ast::BinOp) -> Self { + pub fn new(bin_op: &ast::BinOp) -> Self { match bin_op { ast::BinOp::And(token) => BinOp::And(l(TokenReference::new(&token))), ast::BinOp::Caret(token) => BinOp::Caret(l(TokenReference::new(&token))), @@ -130,7 +149,7 @@ pub struct Block { } impl Block { - fn new(block: &ast::Block) -> Self { + pub fn new(block: &ast::Block) -> Self { Block { stmts: block .stmts_with_semicolon() @@ -184,9 +203,9 @@ impl CreateAstNode for Block { }) .collect::>>()?, ) - .with_last_stmt(self.last_stmt.as_ref().map(|(last_stmt, token)| { + .with_last_stmt(self.last_stmt.as_ref().and_then(|(last_stmt, token)| { Some((last_stmt.create_ast_node()?, token.create_ast_node())) - })?), + })), ) } } @@ -198,7 +217,7 @@ pub enum Call { } impl Call { - fn new(call: &ast::Call) -> Self { + pub fn new(call: &ast::Call) -> Self { match call { ast::Call::AnonymousCall(function_args) => { Call::AnonymousCall(l(FunctionArgs::new(function_args))) @@ -216,7 +235,7 @@ pub struct Do { } impl Do { - fn new(do_: &ast::Do) -> Self { + pub fn new(do_: &ast::Do) -> Self { Do { do_token: TokenReference::new(do_.do_token()), block: Block::new(do_.block()), @@ -252,7 +271,7 @@ pub struct ElseIf { } impl ElseIf { - fn new(else_if: &ast::ElseIf) -> Self { + pub fn new(else_if: &ast::ElseIf) -> Self { ElseIf { else_if_token: TokenReference::new(else_if.else_if_token()), condition: Expression::new(else_if.condition()), @@ -305,7 +324,7 @@ pub enum Expression { } impl Expression { - fn new(expression: &ast::Expression) -> Self { + pub fn new(expression: &ast::Expression) -> Self { match expression { ast::Expression::BinaryOperator { lhs, binop, rhs } => Expression::BinaryOperator { lhs: Box::new(l(Expression::new(lhs))), @@ -348,7 +367,7 @@ pub enum FunctionArgs { } impl FunctionArgs { - fn new(function_args: &ast::FunctionArgs) -> Self { + pub fn new(function_args: &ast::FunctionArgs) -> Self { match function_args { ast::FunctionArgs::Parentheses { parentheses, @@ -377,7 +396,7 @@ pub struct FunctionBody { } impl FunctionBody { - fn new(function_body: &ast::FunctionBody) -> Self { + pub fn new(function_body: &ast::FunctionBody) -> Self { FunctionBody { parameters_parentheses: ContainedSpan::new(function_body.parameters_parentheses()), @@ -418,7 +437,7 @@ pub enum LastStmt { } impl LastStmt { - fn new(last_stmt: &ast::LastStmt) -> Self { + pub fn new(last_stmt: &ast::LastStmt) -> Self { match last_stmt { ast::LastStmt::Break(break_token) => { LastStmt::Break(l(TokenReference::new(break_token))) @@ -455,7 +474,7 @@ pub enum Field { } impl Field { - fn new(field: &ast::Field) -> Self { + pub fn new(field: &ast::Field) -> Self { match field { ast::Field::ExpressionKey { brackets, @@ -488,7 +507,7 @@ pub struct FunctionCall { } impl FunctionCall { - fn new(function_call: &ast::FunctionCall) -> Self { + pub fn new(function_call: &ast::FunctionCall) -> Self { FunctionCall { prefix: Prefix::new(function_call.prefix()), suffixes: function_call.suffixes().map(Suffix::new).collect(), @@ -524,7 +543,7 @@ pub struct FunctionDeclaration { } impl FunctionDeclaration { - fn new(function_declaration: &ast::FunctionDeclaration) -> Self { + pub fn new(function_declaration: &ast::FunctionDeclaration) -> Self { FunctionDeclaration { function_token: TokenReference::new(function_declaration.function_token()), name: FunctionName::new(function_declaration.name()), @@ -557,7 +576,7 @@ pub struct FunctionName { } impl FunctionName { - fn new(function_name: &ast::FunctionName) -> Self { + pub fn new(function_name: &ast::FunctionName) -> Self { FunctionName { names: Punctuated::map_from_punctuated(function_name.names(), TokenReference::new), @@ -604,7 +623,7 @@ pub struct GenericFor { } impl GenericFor { - fn new(generic_for: &ast::GenericFor) -> Self { + pub fn new(generic_for: &ast::GenericFor) -> Self { GenericFor { for_token: TokenReference::new(generic_for.for_token()), names: Punctuated::map_from_punctuated(generic_for.names(), TokenReference::new), @@ -653,7 +672,7 @@ pub struct If { } impl If { - fn new(if_node: &ast::If) -> Self { + pub fn new(if_node: &ast::If) -> Self { If { if_token: TokenReference::new(if_node.if_token()), condition: Expression::new(if_node.condition()), @@ -716,7 +735,7 @@ pub enum Index { } impl Index { - fn new(index: &ast::Index) -> Self { + pub fn new(index: &ast::Index) -> Self { match index { ast::Index::Brackets { brackets, @@ -744,7 +763,7 @@ pub struct LocalAssignment { } impl LocalAssignment { - fn new(local_assignment: &ast::LocalAssignment) -> Self { + pub fn new(local_assignment: &ast::LocalAssignment) -> Self { LocalAssignment { local_token: TokenReference::new(local_assignment.local_token()), name_list: Punctuated::map_from_punctuated( @@ -787,7 +806,7 @@ pub struct LocalFunction { } impl LocalFunction { - fn new(local_function: &ast::LocalFunction) -> Self { + pub fn new(local_function: &ast::LocalFunction) -> Self { LocalFunction { local_token: TokenReference::new(local_function.local_token()), function_token: TokenReference::new(local_function.function_token()), @@ -823,7 +842,7 @@ pub struct MethodCall { } impl MethodCall { - fn new(method_call: &ast::MethodCall) -> Self { + pub fn new(method_call: &ast::MethodCall) -> Self { MethodCall { colon_token: TokenReference::new(method_call.colon_token()), name: TokenReference::new(method_call.name()), @@ -864,7 +883,7 @@ pub struct NumericFor { } impl NumericFor { - fn new(numeric_for: &ast::NumericFor) -> Self { + pub fn new(numeric_for: &ast::NumericFor) -> Self { NumericFor { for_token: TokenReference::new(numeric_for.for_token()), index_variable: TokenReference::new(numeric_for.index_variable()), @@ -916,7 +935,7 @@ pub enum Parameter { } impl Parameter { - fn new(parameter: &ast::Parameter) -> Self { + pub fn new(parameter: &ast::Parameter) -> Self { match parameter { ast::Parameter::Ellipse(ellipse_token) => { Parameter::Ellipse(l(TokenReference::new(ellipse_token))) @@ -936,7 +955,7 @@ pub enum Prefix { } impl Prefix { - fn new(prefix: &ast::Prefix) -> Self { + pub fn new(prefix: &ast::Prefix) -> Self { match prefix { ast::Prefix::Expression(expr) => Prefix::Expression(l(Expression::new(expr))), ast::Prefix::Name(name) => Prefix::Name(l(TokenReference::new(name))), @@ -951,7 +970,7 @@ pub struct Return { } impl Return { - fn new(return_token: &ast::Return) -> Self { + pub fn new(return_token: &ast::Return) -> Self { Return { token: TokenReference::new(return_token.token()), returns: Punctuated::map_from_punctuated(return_token.returns(), Expression::new), @@ -985,7 +1004,7 @@ pub struct Repeat { } impl Repeat { - fn new(repeat: &ast::Repeat) -> Self { + pub fn new(repeat: &ast::Repeat) -> Self { Repeat { repeat_token: TokenReference::new(repeat.repeat_token()), block: Block::new(repeat.block()), @@ -1032,7 +1051,7 @@ pub enum Stmt { } impl Stmt { - fn new(stmt: &ast::Stmt) -> Self { + pub fn new(stmt: &ast::Stmt) -> Self { match stmt { ast::Stmt::Assignment(assignment) => Stmt::Assignment(l(Assignment::new(assignment))), ast::Stmt::Do(do_token) => Stmt::Do(l(Do::new(do_token))), @@ -1067,7 +1086,7 @@ pub enum Suffix { } impl Suffix { - fn new(suffix: &ast::Suffix) -> Self { + pub fn new(suffix: &ast::Suffix) -> Self { match suffix { ast::Suffix::Call(call) => Suffix::Call(l(Call::new(call))), ast::Suffix::Index(index) => Suffix::Index(l(Index::new(index))), @@ -1082,7 +1101,7 @@ pub struct TableConstructor { } impl TableConstructor { - fn new(table_constructor: &ast::TableConstructor) -> Self { + pub fn new(table_constructor: &ast::TableConstructor) -> Self { TableConstructor { braces: ContainedSpan::new(table_constructor.braces()), fields: Punctuated::map_from_punctuated(table_constructor.fields(), Field::new), @@ -1116,7 +1135,7 @@ pub enum UnOp { } impl UnOp { - fn new(unop: &ast::UnOp) -> Self { + pub fn new(unop: &ast::UnOp) -> Self { match unop { ast::UnOp::Minus(token) => UnOp::Minus(l(TokenReference::new(token))), ast::UnOp::Not(token) => UnOp::Not(l(TokenReference::new(token))), @@ -1180,7 +1199,7 @@ pub enum Var { } impl Var { - fn new(var: &ast::Var) -> Self { + pub fn new(var: &ast::Var) -> Self { match var { ast::Var::Expression(expression) => Var::Expression(l(VarExpression::new(expression))), ast::Var::Name(name_token) => Var::Name(l(TokenReference::new(name_token))), @@ -1195,7 +1214,7 @@ pub struct VarExpression { } impl VarExpression { - fn new(var_expression: &ast::VarExpression) -> Self { + pub fn new(var_expression: &ast::VarExpression) -> Self { VarExpression { prefix: Prefix::new(var_expression.prefix()), suffixes: var_expression @@ -1236,7 +1255,7 @@ pub struct While { } impl While { - fn new(while_token: &ast::While) -> Self { + pub fn new(while_token: &ast::While) -> Self { While { while_token: TokenReference::new(while_token.while_token()), condition: Expression::new(while_token.condition()), diff --git a/full-moon-lua-types/src/lib.rs b/full-moon-lua-types/src/lib.rs index 5797599c..1ce66bb5 100644 --- a/full-moon-lua-types/src/lib.rs +++ b/full-moon-lua-types/src/lib.rs @@ -7,5 +7,6 @@ mod lua; mod mlua_util; mod prepare_for_lua; mod shared; +mod visitor; pub use lua::create_lua; diff --git a/full-moon-lua-types/src/mlua_util.rs b/full-moon-lua-types/src/mlua_util.rs index eb2f6869..6c338c00 100644 --- a/full-moon-lua-types/src/mlua_util.rs +++ b/full-moon-lua-types/src/mlua_util.rs @@ -1,9 +1,11 @@ use std::sync::{Arc, RwLock}; -use mlua::{ToLua, UserData, UserDataFields}; +use mlua::{ToLua, UserData}; use crate::create_ast_node::CreateAstNode; +pub use crate::visitor::add_visit; + pub type ArcLocked = Arc>; pub fn add_core_meta_methods<'lua, T: UserData>( diff --git a/full-moon-lua-types/src/visitor.rs b/full-moon-lua-types/src/visitor.rs new file mode 100644 index 00000000..7af06234 --- /dev/null +++ b/full-moon-lua-types/src/visitor.rs @@ -0,0 +1,198 @@ +use crate::{core, create_ast_node::CreateAstNode, shared}; +use full_moon::{ + ast, + node::Node, + tokenizer, + visitors::{Visit, Visitor}, +}; +use mlua::UserData; +use paste::paste; + +macro_rules! create_visitor { + ( + $( + ($name:ident: $type:ty, $converter:expr), + )+ + ) => { + paste! { + #[derive(Clone, Debug, Default)] + pub struct VisitorTable<'lua> { + $( + $name: Option>, + [< $name _end >]: Option>, + )+ + } + + impl<'lua> mlua::FromLua<'lua> for VisitorTable<'lua> { + fn from_lua(value: mlua::Value<'lua>, _: &'lua mlua::Lua) -> mlua::Result { + let mut visitor_table = VisitorTable::default(); + + let table = match value { + mlua::Value::Table(table) => table, + _ => return Err(mlua::Error::external(format!(":visit() expects a table, received {}", value.type_name()))), + }; + + for pair in table.pairs::>() { + let (key, value) = pair?; + + // TODO: When validating names, have a list of names for 5.2/5.3/Luau only that won't error when the feature is not enabled + $( + let pascal_cased_name = pascal_case_name(stringify!($name)); + + if key == pascal_cased_name { + visitor_table.$name = Some(value); + continue; + } else if key == format!("{pascal_cased_name}End") { + visitor_table.[< $name _end >] = Some(value); + continue; + } + )+ + + return Err(mlua::Error::external(format!(":visit() received an unknown key {}", key.to_string_lossy()))); + } + + Ok(visitor_table) + } + } + + pub struct LuaVisitor<'lua> { + existing_error: Option, + visitor_table: VisitorTable<'lua>, + } + + impl<'lua> LuaVisitor<'lua> { + fn ok(self) -> mlua::Result<()> { + match self.existing_error { + Some(error) => Err(error), + None => Ok(()), + } + } + } + + impl<'lua> Visitor for LuaVisitor<'lua> { + $( + fn $name(&mut self, node: &$type) { + if self.existing_error.is_some() { + return; + } + + if let Some(function) = &self.visitor_table.$name { + if let Err(error) = function.call::<_, ()>($converter(node)) { + self.existing_error = Some(error); + } + } + } + + fn [<$name _end>](&mut self, node: &$type) { + if self.existing_error.is_some() { + return; + } + + if let Some(function) = &self.visitor_table.[< $name _end >] { + if let Err(error) = function.call::<_, ()>($converter(node)) { + self.existing_error = Some(error); + } + } + } + )+ + } + } + }; +} + +create_visitor! { + (visit_anonymous_call: ast::FunctionArgs, core::FunctionArgs::new), + (visit_assignment: ast::Assignment, core::Assignment::new), + (visit_block: ast::Block, core::Block::new), + (visit_call: ast::Call, core::Call::new), + (visit_contained_span: ast::span::ContainedSpan, shared::ContainedSpan::new), + (visit_do: ast::Do, core::Do::new), + (visit_else_if: ast::ElseIf, core::ElseIf::new), + (visit_eof: tokenizer::TokenReference, shared::TokenReference::new), + (visit_expression: ast::Expression, core::Expression::new), + (visit_field: ast::Field, core::Field::new), + (visit_function_args: ast::FunctionArgs, core::FunctionArgs::new), + (visit_function_body: ast::FunctionBody, core::FunctionBody::new), + (visit_function_call: ast::FunctionCall, core::FunctionCall::new), + (visit_function_declaration: ast::FunctionDeclaration, core::FunctionDeclaration::new), + (visit_function_name: ast::FunctionName, core::FunctionName::new), + (visit_generic_for: ast::GenericFor, core::GenericFor::new), + (visit_if: ast::If, core::If::new), + (visit_index: ast::Index, core::Index::new), + (visit_local_assignment: ast::LocalAssignment, core::LocalAssignment::new), + (visit_local_function: ast::LocalFunction, core::LocalFunction::new), + (visit_last_stmt: ast::LastStmt, core::LastStmt::new), + (visit_method_call: ast::MethodCall, core::MethodCall::new), + (visit_numeric_for: ast::NumericFor, core::NumericFor::new), + (visit_parameter: ast::Parameter, core::Parameter::new), + (visit_prefix: ast::Prefix, core::Prefix::new), + (visit_return: ast::Return, core::Return::new), + (visit_repeat: ast::Repeat, core::Repeat::new), + (visit_stmt: ast::Stmt, core::Stmt::new), + (visit_suffix: ast::Suffix, core::Suffix::new), + (visit_table_constructor: ast::TableConstructor, core::TableConstructor::new), + (visit_token_reference: tokenizer::TokenReference, shared::TokenReference::new), + (visit_un_op: ast::UnOp, core::UnOp::new), + (visit_value: ast::Value, core::Value::new), + (visit_var: ast::Var, core::Var::new), + (visit_var_expression: ast::VarExpression, core::VarExpression::new), + (visit_while: ast::While, core::While::new), +} + +fn pascal_case_name(name: &str) -> String { + let mut pascal_case_name = String::new(); + + let mut should_capitalize = true; + for character in name.chars().skip("visit_".len()) { + if should_capitalize { + pascal_case_name.push(character.to_ascii_uppercase()); + should_capitalize = false; + } else if character == '_' { + should_capitalize = true; + } else { + pascal_case_name.push(character); + } + } + + pascal_case_name +} + +pub fn add_visit<'lua, T, N>(methods: &mut impl mlua::UserDataMethods<'lua, T>) +where + T: UserData + CreateAstNode, + N: Visit, +{ + methods.add_method_mut("visit", |_, this, visitor: VisitorTable| { + let mut visitor = LuaVisitor { + existing_error: None, + visitor_table: visitor, + }; + + if let Some(ast_node) = this.create_ast_node() { + ast_node.visit(&mut visitor); + } + + visitor.ok() + }); +} + +pub fn add_visit_with_visitor<'lua, T, N, F>( + methods: &mut impl mlua::UserDataMethods<'lua, T>, + mut callback: F, +) where + T: UserData + CreateAstNode, + F: 'static + FnMut(N, &mut LuaVisitor<'lua>), +{ + methods.add_method_mut("visit", move |_, this, visitor: VisitorTable| { + let mut visitor = LuaVisitor { + existing_error: None, + visitor_table: visitor, + }; + + if let Some(ast_node) = this.create_ast_node() { + callback(ast_node, &mut visitor); + } + + visitor.ok() + }); +} diff --git a/full-moon-lua-types/tests/lua/core.lua b/full-moon-lua-types/tests/lua/core.lua index 3c96190a..fe56f31d 100644 --- a/full-moon-lua-types/tests/lua/core.lua +++ b/full-moon-lua-types/tests/lua/core.lua @@ -29,12 +29,32 @@ assertEq( ) local assignments = {} +local assignmentEnds = {} -stmt:visit({ +ast:visit({ Assignment = function(assignment) table.insert(assignments, assignment:print()) end, + + AssignmentEnd = function(assignmentEnd) + table.insert(assignmentEnds, assignmentEnd:print()) + end, }) +assert(not pcall(function() + ast:visit({ + Funky = function() end, + }) +end), "expected :visit to not allow invalid names") + +assert(not pcall(function() + ast:visit({ + Assignment = 3, + }) +end), "expected :visit to not allow invalid values") + assertEq(#assignments, 1) assertEq(assignments[1], "x, y = 1, 2") + +assertEq(#assignmentEnds, 1) +assertEq(assignmentEnds[1], "x, y = 1, 2") From dd48f0bc0f3ae82f16ec6ccbbbb7118ff5136ba7 Mon Sep 17 00:00:00 2001 From: Kampfkarren Date: Tue, 13 Sep 2022 07:57:08 -0700 Subject: [PATCH 05/19] Token stuff --- .../src/lua_user_data.rs | 1 + full-moon-lua-types/src/shared.rs | 9 +++- full-moon-lua-types/src/visitor.rs | 54 +++++++++++++++++-- full-moon-lua-types/tests/lua/core.lua | 13 +++++ 4 files changed, 71 insertions(+), 6 deletions(-) diff --git a/full-moon-lua-types-derive/src/lua_user_data.rs b/full-moon-lua-types-derive/src/lua_user_data.rs index 60f5698d..fd148a66 100644 --- a/full-moon-lua-types-derive/src/lua_user_data.rs +++ b/full-moon-lua-types-derive/src/lua_user_data.rs @@ -265,6 +265,7 @@ pub fn derive(input: TokenStream) -> TokenStream { fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) { crate::mlua_util::add_core_metamethods_no_tostring(stringify!(#input_ident), methods); crate::mlua_util::add_print(methods); + crate::mlua_util::add_visit(methods); methods.add_meta_method(mlua::MetaMethod::ToString, |_, this, _: ()| { Ok(#match_to_string) diff --git a/full-moon-lua-types/src/shared.rs b/full-moon-lua-types/src/shared.rs index 5d5a80e1..cb2a0821 100644 --- a/full-moon-lua-types/src/shared.rs +++ b/full-moon-lua-types/src/shared.rs @@ -9,7 +9,7 @@ use mlua::{MetaMethod, ToLua, UserData}; use crate::{ create_ast_node::CreateAstNode, - mlua_util::{add_core_meta_methods, add_to_string_display}, + mlua_util::{add_core_meta_methods, add_print, add_to_string_display}, }; pub struct ContainedSpan { @@ -148,6 +148,13 @@ impl CreateAstNode for Token { } } +impl UserData for Token { + fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) { + add_core_meta_methods("Token", methods); + add_print(methods); + } +} + pub struct TokenReference { leading_trivia: Vec, token: Token, diff --git a/full-moon-lua-types/src/visitor.rs b/full-moon-lua-types/src/visitor.rs index 7af06234..dfd2acbd 100644 --- a/full-moon-lua-types/src/visitor.rs +++ b/full-moon-lua-types/src/visitor.rs @@ -10,9 +10,17 @@ use paste::paste; macro_rules! create_visitor { ( - $( - ($name:ident: $type:ty, $converter:expr), - )+ + ast: { + $( + ($name:ident: $type:ty, $converter:expr), + )+ + }, + + tokens: { + $( + $token_name:ident, + )+ + } ) => { paste! { #[derive(Clone, Debug, Default)] @@ -21,6 +29,10 @@ macro_rules! create_visitor { $name: Option>, [< $name _end >]: Option>, )+ + + $( + $token_name: Option>, + )+ } impl<'lua> mlua::FromLua<'lua> for VisitorTable<'lua> { @@ -48,6 +60,15 @@ macro_rules! create_visitor { } )+ + $( + let pascal_cased_name = pascal_case_name(stringify!($token_name)); + + if key == pascal_cased_name { + visitor_table.$token_name = Some(value); + continue; + } + )+ + return Err(mlua::Error::external(format!(":visit() received an unknown key {}", key.to_string_lossy()))); } @@ -95,12 +116,26 @@ macro_rules! create_visitor { } } )+ + + $( + fn $token_name(&mut self, token: &tokenizer::Token) { + if self.existing_error.is_some() { + return; + } + + if let Some(function) = &self.visitor_table.$token_name { + if let Err(error) = function.call::<_, ()>(shared::Token::from(token)) { + self.existing_error = Some(error); + } + } + } + )+ } } }; } -create_visitor! { +create_visitor!(ast: { (visit_anonymous_call: ast::FunctionArgs, core::FunctionArgs::new), (visit_assignment: ast::Assignment, core::Assignment::new), (visit_block: ast::Block, core::Block::new), @@ -137,7 +172,16 @@ create_visitor! { (visit_var: ast::Var, core::Var::new), (visit_var_expression: ast::VarExpression, core::VarExpression::new), (visit_while: ast::While, core::While::new), -} +}, tokens: { + visit_identifier, + visit_multi_line_comment, + visit_number, + visit_single_line_comment, + visit_string_literal, + visit_symbol, + visit_token, + visit_whitespace, +}); fn pascal_case_name(name: &str) -> String { let mut pascal_case_name = String::new(); diff --git a/full-moon-lua-types/tests/lua/core.lua b/full-moon-lua-types/tests/lua/core.lua index fe56f31d..9ee59028 100644 --- a/full-moon-lua-types/tests/lua/core.lua +++ b/full-moon-lua-types/tests/lua/core.lua @@ -58,3 +58,16 @@ assertEq(assignments[1], "x, y = 1, 2") assertEq(#assignmentEnds, 1) assertEq(assignmentEnds[1], "x, y = 1, 2") + +-- Test non-AST visiting +local numbers = {} + +stmt:visit({ + Number = function(token) + table.insert(numbers, token:print()) + end, +}) + +assertEq(#numbers, 2) +assertEq(numbers[1], "1") +assertEq(numbers[2], "2") From 73424cb70cc25e2491037884c197f75290b419a7 Mon Sep 17 00:00:00 2001 From: Kampfkarren Date: Tue, 13 Sep 2022 08:40:28 -0700 Subject: [PATCH 06/19] :expect(), slowly beef types --- .../src/lua_user_data.rs | 83 +++++++++++++++++++ full-moon-lua-types/src/core.rs | 81 +++++++++++++----- full-moon-lua-types/src/shared.rs | 10 +++ full-moon-lua-types/tests/lua/core.lua | 18 ++++ 4 files changed, 173 insertions(+), 19 deletions(-) diff --git a/full-moon-lua-types-derive/src/lua_user_data.rs b/full-moon-lua-types-derive/src/lua_user_data.rs index fd148a66..c478a952 100644 --- a/full-moon-lua-types-derive/src/lua_user_data.rs +++ b/full-moon-lua-types-derive/src/lua_user_data.rs @@ -62,6 +62,7 @@ pub fn derive(input: TokenStream) -> TokenStream { } }); + // TODO: Error for invalid names let match_match = { let mut cases = Vec::with_capacity(input_enum.variants.len()); @@ -254,6 +255,84 @@ pub fn derive(input: TokenStream) -> TokenStream { } }; + // TODO: This is copy-paste from match_match + let match_expect = { + let mut cases = Vec::with_capacity(input_enum.variants.len()); + + for variant in &input_enum.variants { + let variant_ident = &variant.ident; + + match &variant.fields { + syn::Fields::Named(fields) => { + let fields = fields + .named + .iter() + .map(|field| &field.ident) + .collect::>(); + + cases.push(quote! { + #input_ident::#variant_ident { #(#fields),* } => { + let mut table = lua.create_table()?; + + #( + table.set(stringify!(#fields), #fields.prepare_for_lua(lua)?)?; + )* + + (stringify!(#variant_ident), table.to_lua_multi(lua)?) + } + }); + } + + syn::Fields::Unnamed(fields) => { + let fields = fields + .unnamed + .iter() + .enumerate() + .map(|(index, _)| format_ident!("_{index}")) + .collect::>(); + + cases.push(quote! { + #input_ident::#variant_ident(#(#fields),*) => { + let mut fields = Vec::new(); + + #( + fields.push(#fields.prepare_for_lua(lua)?); + )* + + (stringify!(#variant_ident), mlua::MultiValue::from_vec(fields)) + } + }); + } + + syn::Fields::Unit => { + cases.push(quote! { + #input_ident::#variant_ident => { + (stringify!(#variant_ident), ().to_lua_multi(lua)?) + } + }); + } + } + } + + quote! { + use mlua::ToLuaMulti; + + let (function_name, args) = match this { + #(#cases,)* + }; + + if function_name == variant { + Ok(args) + } else { + Err(mlua::Error::external(format!( + "expected {}, got {}", + variant, + function_name, + ))) + } + } + }; + quote! { impl mlua::UserData for #input_ident { fn add_fields<'lua, F: mlua::UserDataFields<'lua, Self>>(fields: &mut F) { @@ -271,6 +350,10 @@ pub fn derive(input: TokenStream) -> TokenStream { Ok(#match_to_string) }); + methods.add_method("expect", |lua, this, variant: String| { + #match_expect + }); + methods.add_method("match", |lua, this, table: mlua::Table| { #match_match }); diff --git a/full-moon-lua-types/src/core.rs b/full-moon-lua-types/src/core.rs index d137595d..9cbed6b3 100644 --- a/full-moon-lua-types/src/core.rs +++ b/full-moon-lua-types/src/core.rs @@ -34,6 +34,7 @@ impl From for Ast { impl UserData for Ast { fn add_fields<'lua, F: mlua::UserDataFields<'lua, Self>>(fields: &mut F) { + fields.add_field_method_get("eof", |_, Ast { eof, .. }| Ok(eof.clone())); fields.add_field_method_get("nodes", |_, Ast { nodes, .. }| Ok(nodes.clone())); } @@ -61,22 +62,42 @@ impl CreateAstNode for Ast { } pub struct Assignment { - var_list: Punctuated, - equal_token: TokenReference, - expr_list: Punctuated, + var_list: ArcLocked>, + equal_token: ArcLocked, + expr_list: ArcLocked>, } impl Assignment { pub fn new(assignment: &ast::Assignment) -> Self { Assignment { - var_list: Punctuated::map_from_punctuated(assignment.variables(), Var::new), - equal_token: TokenReference::new(assignment.equal_token()), - expr_list: Punctuated::map_from_punctuated(assignment.expressions(), Expression::new), + var_list: l(Punctuated::map_from_punctuated( + assignment.variables(), + Var::new, + )), + equal_token: l(TokenReference::new(assignment.equal_token())), + expr_list: l(Punctuated::map_from_punctuated( + assignment.expressions(), + Expression::new, + )), } } } impl UserData for Assignment { + fn add_fields<'lua, F: mlua::UserDataFields<'lua, Self>>(fields: &mut F) { + fields.add_field_method_get("var_list", |_, Assignment { var_list, .. }| { + Ok(var_list.clone()) + }); + + fields.add_field_method_get("equal_token", |_, Assignment { equal_token, .. }| { + Ok(equal_token.clone()) + }); + + fields.add_field_method_get("expr_list", |_, Assignment { expr_list, .. }| { + Ok(expr_list.clone()) + }); + } + fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) { add_to_string_display("Assignment", methods); add_print(methods); @@ -97,7 +118,7 @@ impl CreateAstNode for Assignment { } } -#[derive(LuaUserData)] +#[derive(Clone, LuaUserData)] pub enum BinOp { And(ArcLocked), Caret(ArcLocked), @@ -143,6 +164,7 @@ impl BinOp { } } +#[derive(Clone)] pub struct Block { stmts: Vec<(ArcLocked, Option>)>, last_stmt: Option<(ArcLocked, Option>)>, @@ -182,6 +204,10 @@ impl UserData for Block { .map(|(stmt, _)| stmt.clone()) .collect::>()) }); + + fields.add_field_method_get("last_stmt", |_, Block { last_stmt, .. }| { + Ok(last_stmt.as_ref().map(|(last_stmt, _)| last_stmt.clone())) + }); } fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) { @@ -210,7 +236,7 @@ impl CreateAstNode for Block { } } -#[derive(LuaUserData)] +#[derive(Clone, LuaUserData)] pub enum Call { AnonymousCall(ArcLocked), MethodCall(ArcLocked), @@ -228,6 +254,7 @@ impl Call { } } +#[derive(Clone)] pub struct Do { do_token: TokenReference, block: Block, @@ -263,6 +290,7 @@ impl CreateAstNode for Do { } } +#[derive(Clone)] pub struct ElseIf { else_if_token: TokenReference, condition: Expression, @@ -354,7 +382,7 @@ impl Expression { } } -#[derive(LuaUserData)] +#[derive(Clone, LuaUserData)] pub enum FunctionArgs { Parentheses { parentheses: ArcLocked, @@ -388,6 +416,7 @@ impl FunctionArgs { } } +#[derive(Clone)] pub struct FunctionBody { parameters_parentheses: ContainedSpan, parameters: Punctuated, @@ -428,7 +457,7 @@ impl CreateAstNode for FunctionBody { } } -#[derive(LuaUserData)] +#[derive(Clone, LuaUserData)] pub enum LastStmt { Break(ArcLocked), #[cfg(feature = "luau")] @@ -455,7 +484,7 @@ impl LastStmt { } } -#[derive(LuaUserData)] +#[derive(Clone, LuaUserData)] pub enum Field { ExpressionKey { brackets: ArcLocked, @@ -501,6 +530,7 @@ impl Field { } } +#[derive(Clone)] pub struct FunctionCall { prefix: Prefix, suffixes: Vec, @@ -536,6 +566,7 @@ impl CreateAstNode for FunctionCall { } } +#[derive(Clone)] pub struct FunctionDeclaration { function_token: TokenReference, name: FunctionName, @@ -570,6 +601,7 @@ impl CreateAstNode for FunctionDeclaration { } } +#[derive(Clone)] pub struct FunctionName { names: Punctuated, colon_name: Option<(TokenReference, TokenReference)>, @@ -612,6 +644,7 @@ impl CreateAstNode for FunctionName { } } +#[derive(Clone)] pub struct GenericFor { for_token: TokenReference, names: Punctuated, @@ -660,6 +693,7 @@ impl CreateAstNode for GenericFor { } } +#[derive(Clone)] pub struct If { if_token: TokenReference, condition: Expression, @@ -721,7 +755,7 @@ impl CreateAstNode for If { } } -#[derive(LuaUserData)] +#[derive(Clone, LuaUserData)] pub enum Index { Brackets { brackets: ArcLocked, @@ -755,6 +789,7 @@ impl Index { } } +#[derive(Clone)] pub struct LocalAssignment { local_token: TokenReference, name_list: Punctuated, @@ -798,6 +833,7 @@ impl CreateAstNode for LocalAssignment { } } +#[derive(Clone)] pub struct LocalFunction { local_token: TokenReference, function_token: TokenReference, @@ -835,6 +871,7 @@ impl CreateAstNode for LocalFunction { } } +#[derive(Clone)] pub struct MethodCall { colon_token: TokenReference, name: TokenReference, @@ -868,6 +905,7 @@ impl CreateAstNode for MethodCall { } } +#[derive(Clone)] pub struct NumericFor { for_token: TokenReference, index_variable: TokenReference, @@ -928,7 +966,7 @@ impl CreateAstNode for NumericFor { } } -#[derive(LuaUserData)] +#[derive(Clone, LuaUserData)] pub enum Parameter { Ellipse(ArcLocked), Name(ArcLocked), @@ -948,7 +986,7 @@ impl Parameter { } } -#[derive(LuaUserData)] +#[derive(Clone, LuaUserData)] pub enum Prefix { Expression(ArcLocked), Name(ArcLocked), @@ -964,6 +1002,7 @@ impl Prefix { } } +#[derive(Clone)] pub struct Return { token: TokenReference, returns: Punctuated, @@ -996,6 +1035,7 @@ impl CreateAstNode for Return { } } +#[derive(Clone)] pub struct Repeat { repeat_token: TokenReference, block: Block, @@ -1033,7 +1073,7 @@ impl CreateAstNode for Repeat { } } -#[derive(LuaUserData)] +#[derive(Clone, LuaUserData)] pub enum Stmt { Assignment(ArcLocked), Do(ArcLocked), @@ -1079,7 +1119,7 @@ impl Stmt { } } -#[derive(LuaUserData)] +#[derive(Clone, LuaUserData)] pub enum Suffix { Call(ArcLocked), Index(ArcLocked), @@ -1095,6 +1135,7 @@ impl Suffix { } } +#[derive(Clone)] pub struct TableConstructor { braces: ContainedSpan, fields: Punctuated, @@ -1127,7 +1168,7 @@ impl CreateAstNode for TableConstructor { } } -#[derive(LuaUserData)] +#[derive(Clone, LuaUserData)] pub enum UnOp { Minus(ArcLocked), Not(ArcLocked), @@ -1145,7 +1186,7 @@ impl UnOp { } } -#[derive(LuaUserData)] +#[derive(Clone, LuaUserData)] pub enum Value { #[lua( create_ast_node = "ast::Value::Function((_0.create_ast_node()?, _1.create_ast_node()?))" @@ -1192,7 +1233,7 @@ impl Value { } } -#[derive(LuaUserData)] +#[derive(Clone, LuaUserData)] pub enum Var { Expression(ArcLocked), Name(ArcLocked), @@ -1208,6 +1249,7 @@ impl Var { } } +#[derive(Clone)] pub struct VarExpression { prefix: Prefix, suffixes: Vec, @@ -1246,6 +1288,7 @@ impl CreateAstNode for VarExpression { } } +#[derive(Clone)] pub struct While { while_token: TokenReference, condition: Expression, diff --git a/full-moon-lua-types/src/shared.rs b/full-moon-lua-types/src/shared.rs index cb2a0821..d838f648 100644 --- a/full-moon-lua-types/src/shared.rs +++ b/full-moon-lua-types/src/shared.rs @@ -12,6 +12,7 @@ use crate::{ mlua_util::{add_core_meta_methods, add_print, add_to_string_display}, }; +#[derive(Clone)] pub struct ContainedSpan { start: TokenReference, end: TokenReference, @@ -45,8 +46,10 @@ impl CreateAstNode for ContainedSpan { } } +#[derive(Clone)] pub struct Position(tokenizer::Position); +#[derive(Clone)] pub struct Punctuated(ast::punctuated::Punctuated); impl Punctuated { @@ -98,6 +101,10 @@ impl UserData for Punctuated { methods.add_meta_method(MetaMethod::Len, |_, Punctuated(punctuated), _: ()| { Ok(punctuated.len()) }); + + methods.add_method("to_table", |lua, this, _: ()| { + this.to_table(lua).map_err(mlua::Error::external) + }); } } @@ -122,8 +129,10 @@ impl CreateAstNode for Punctuated { } } +#[derive(Clone)] pub struct TokenType(tokenizer::TokenType); +#[derive(Clone)] pub struct Token { start_position: Position, end_position: Position, @@ -155,6 +164,7 @@ impl UserData for Token { } } +#[derive(Clone)] pub struct TokenReference { leading_trivia: Vec, token: Token, diff --git a/full-moon-lua-types/tests/lua/core.lua b/full-moon-lua-types/tests/lua/core.lua index 9ee59028..ee6a804e 100644 --- a/full-moon-lua-types/tests/lua/core.lua +++ b/full-moon-lua-types/tests/lua/core.lua @@ -71,3 +71,21 @@ stmt:visit({ assertEq(#numbers, 2) assertEq(numbers[1], "1") assertEq(numbers[2], "2") + +assert(not pcall(function() + return stmt:expect("While") +end), "stmt:expect should have thrown") + +local assignment = stmt:expect("Assignment") +assertEq(#assignment.var_list, 2) +assertEq(#assignment.var_list:to_table(), 2) + +local iters = {} + +for i, v in assignment.var_list do + iters[i] = v:print() +end + +assertEq(#iters, 2) +assertEq(iters[1], "x") +assertEq(iters[2], "y ") From f7e5b7ee0d010fa0b105e691971f6c1e93980fc1 Mon Sep 17 00:00:00 2001 From: Kampfkarren Date: Tue, 13 Sep 2022 08:41:06 -0700 Subject: [PATCH 07/19] to_table -> values --- full-moon-lua-types/src/shared.rs | 8 ++++---- full-moon-lua-types/tests/lua/core.lua | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/full-moon-lua-types/src/shared.rs b/full-moon-lua-types/src/shared.rs index d838f648..05ea2ad7 100644 --- a/full-moon-lua-types/src/shared.rs +++ b/full-moon-lua-types/src/shared.rs @@ -70,7 +70,7 @@ impl Punctuated { } impl Punctuated { - fn to_table<'lua>(&self, lua: &'lua mlua::Lua) -> mlua::Result> { + fn values<'lua>(&self, lua: &'lua mlua::Lua) -> mlua::Result> { let table = lua.create_table()?; for (i, item) in self.0.iter().enumerate() { @@ -94,7 +94,7 @@ impl UserData for Punctuated { methods.add_meta_method(MetaMethod::Iter, |lua, this, _: ()| { Ok(( lua.globals().get::<_, mlua::Function>("next")?, - this.to_table(lua)?, + this.values(lua)?, )) }); @@ -102,8 +102,8 @@ impl UserData for Punctuated { Ok(punctuated.len()) }); - methods.add_method("to_table", |lua, this, _: ()| { - this.to_table(lua).map_err(mlua::Error::external) + methods.add_method("values", |lua, this, _: ()| { + this.values(lua).map_err(mlua::Error::external) }); } } diff --git a/full-moon-lua-types/tests/lua/core.lua b/full-moon-lua-types/tests/lua/core.lua index ee6a804e..12d7ec19 100644 --- a/full-moon-lua-types/tests/lua/core.lua +++ b/full-moon-lua-types/tests/lua/core.lua @@ -78,7 +78,7 @@ end), "stmt:expect should have thrown") local assignment = stmt:expect("Assignment") assertEq(#assignment.var_list, 2) -assertEq(#assignment.var_list:to_table(), 2) +assertEq(#assignment.var_list:values(), 2) local iters = {} From eb41ac2284ca2141d604e393820fcf88ef95009f Mon Sep 17 00:00:00 2001 From: Kampfkarren Date: Tue, 13 Sep 2022 21:26:48 -0700 Subject: [PATCH 08/19] ArcLocked everything, create nodes for everything --- full-moon-lua-types/src/core.rs | 626 ++++++++++++++----- full-moon-lua-types/tests/lua/core.lua | 6 +- full-moon-lua-types/tests/lua/everything.lua | 0 full-moon-lua-types/tests/lua_tests.rs | 5 - 4 files changed, 465 insertions(+), 172 deletions(-) delete mode 100644 full-moon-lua-types/tests/lua/everything.lua diff --git a/full-moon-lua-types/src/core.rs b/full-moon-lua-types/src/core.rs index 9cbed6b3..9ac98c65 100644 --- a/full-moon-lua-types/src/core.rs +++ b/full-moon-lua-types/src/core.rs @@ -2,7 +2,7 @@ use std::sync::{Arc, RwLock}; use full_moon::{ast, node::Node, tokenizer}; use full_moon_lua_types_derive::LuaUserData; -use mlua::{Table, UserData}; +use mlua::{Table, ToLua, UserData}; use crate::{ create_ast_node::CreateAstNode, @@ -85,7 +85,7 @@ impl Assignment { impl UserData for Assignment { fn add_fields<'lua, F: mlua::UserDataFields<'lua, Self>>(fields: &mut F) { - fields.add_field_method_get("var_list", |_, Assignment { var_list, .. }| { + fields.add_field_method_get("variables", |_, Assignment { var_list, .. }| { Ok(var_list.clone()) }); @@ -93,7 +93,7 @@ impl UserData for Assignment { Ok(equal_token.clone()) }); - fields.add_field_method_get("expr_list", |_, Assignment { expr_list, .. }| { + fields.add_field_method_get("expressions", |_, Assignment { expr_list, .. }| { Ok(expr_list.clone()) }); } @@ -256,22 +256,30 @@ impl Call { #[derive(Clone)] pub struct Do { - do_token: TokenReference, - block: Block, - end_token: TokenReference, + do_token: ArcLocked, + block: ArcLocked, + end_token: ArcLocked, } impl Do { pub fn new(do_: &ast::Do) -> Self { Do { - do_token: TokenReference::new(do_.do_token()), - block: Block::new(do_.block()), - end_token: TokenReference::new(do_.end_token()), + do_token: l(TokenReference::new(do_.do_token())), + block: l(Block::new(do_.block())), + end_token: l(TokenReference::new(do_.end_token())), } } } impl UserData for Do { + fn add_fields<'lua, F: mlua::UserDataFields<'lua, Self>>(fields: &mut F) { + fields.add_field_method_get("do_token", |_, Do { do_token, .. }| Ok(do_token.clone())); + + fields.add_field_method_get("block", |_, Do { block, .. }| Ok(block.clone())); + + fields.add_field_method_get("end_token", |_, Do { end_token, .. }| Ok(end_token.clone())); + } + fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) { add_to_string_display("Do", methods); } @@ -292,24 +300,40 @@ impl CreateAstNode for Do { #[derive(Clone)] pub struct ElseIf { - else_if_token: TokenReference, - condition: Expression, - then_token: TokenReference, - block: Block, + else_if_token: ArcLocked, + condition: ArcLocked, + then_token: ArcLocked, + block: ArcLocked, } impl ElseIf { pub fn new(else_if: &ast::ElseIf) -> Self { ElseIf { - else_if_token: TokenReference::new(else_if.else_if_token()), - condition: Expression::new(else_if.condition()), - then_token: TokenReference::new(else_if.then_token()), - block: Block::new(else_if.block()), + else_if_token: l(TokenReference::new(else_if.else_if_token())), + condition: l(Expression::new(else_if.condition())), + then_token: l(TokenReference::new(else_if.then_token())), + block: l(Block::new(else_if.block())), } } } impl UserData for ElseIf { + fn add_fields<'lua, F: mlua::UserDataFields<'lua, Self>>(fields: &mut F) { + fields.add_field_method_get("else_if_token", |_, ElseIf { else_if_token, .. }| { + Ok(else_if_token.clone()) + }); + + fields.add_field_method_get("condition", |_, ElseIf { condition, .. }| { + Ok(condition.clone()) + }); + + fields.add_field_method_get("then_token", |_, ElseIf { then_token, .. }| { + Ok(then_token.clone()) + }); + + fields.add_field_method_get("block", |_, ElseIf { block, .. }| Ok(block.clone())); + } + fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) { add_to_string_display("ElseIf", methods); } @@ -418,26 +442,50 @@ impl FunctionArgs { #[derive(Clone)] pub struct FunctionBody { - parameters_parentheses: ContainedSpan, - parameters: Punctuated, - block: Block, - end_token: TokenReference, + parameters_parentheses: ArcLocked, + parameters: ArcLocked>, + block: ArcLocked, + end_token: ArcLocked, } impl FunctionBody { pub fn new(function_body: &ast::FunctionBody) -> Self { FunctionBody { - parameters_parentheses: ContainedSpan::new(function_body.parameters_parentheses()), + parameters_parentheses: l(ContainedSpan::new(function_body.parameters_parentheses())), - parameters: Punctuated::map_from_punctuated(function_body.parameters(), Parameter::new), + parameters: l(Punctuated::map_from_punctuated( + function_body.parameters(), + Parameter::new, + )), - block: Block::new(function_body.block()), - end_token: TokenReference::new(function_body.end_token()), + block: l(Block::new(function_body.block())), + end_token: l(TokenReference::new(function_body.end_token())), } } } impl UserData for FunctionBody { + fn add_fields<'lua, F: mlua::UserDataFields<'lua, Self>>(fields: &mut F) { + fields.add_field_method_get( + "parameters_parentheses", + |_, + FunctionBody { + parameters_parentheses, + .. + }| { Ok(parameters_parentheses.clone()) }, + ); + + fields.add_field_method_get("parameters", |_, FunctionBody { parameters, .. }| { + Ok(parameters.clone()) + }); + + fields.add_field_method_get("block", |_, FunctionBody { block, .. }| Ok(block.clone())); + + fields.add_field_method_get("end_token", |_, FunctionBody { end_token, .. }| { + Ok(end_token.clone()) + }); + } + fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) { add_to_string_display("FunctionBody", methods); } @@ -532,20 +580,31 @@ impl Field { #[derive(Clone)] pub struct FunctionCall { - prefix: Prefix, - suffixes: Vec, + prefix: ArcLocked, + suffixes: Vec>, } impl FunctionCall { pub fn new(function_call: &ast::FunctionCall) -> Self { FunctionCall { - prefix: Prefix::new(function_call.prefix()), - suffixes: function_call.suffixes().map(Suffix::new).collect(), + prefix: l(Prefix::new(function_call.prefix())), + suffixes: function_call.suffixes().map(Suffix::new).map(l).collect(), } } } impl UserData for FunctionCall { + fn add_fields<'lua, F: mlua::UserDataFields<'lua, Self>>(fields: &mut F) { + fields.add_field_method_get( + "prefix", + |_, FunctionCall { prefix, .. }| Ok(prefix.clone()), + ); + + fields.add_field_method_get("suffixes", |_, FunctionCall { suffixes, .. }| { + Ok(suffixes.clone()) + }); + } + fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) { add_to_string_display("FunctionCall", methods); } @@ -559,7 +618,7 @@ impl CreateAstNode for FunctionCall { ast::FunctionCall::new(self.prefix.create_ast_node()?).with_suffixes( self.suffixes .iter() - .map(Suffix::create_ast_node) + .map(|suffix| suffix.read().unwrap().create_ast_node()) .collect::>>()?, ), ) @@ -568,22 +627,37 @@ impl CreateAstNode for FunctionCall { #[derive(Clone)] pub struct FunctionDeclaration { - function_token: TokenReference, - name: FunctionName, - body: FunctionBody, + function_token: ArcLocked, + name: ArcLocked, + body: ArcLocked, } impl FunctionDeclaration { pub fn new(function_declaration: &ast::FunctionDeclaration) -> Self { FunctionDeclaration { - function_token: TokenReference::new(function_declaration.function_token()), - name: FunctionName::new(function_declaration.name()), - body: FunctionBody::new(function_declaration.body()), + function_token: l(TokenReference::new(function_declaration.function_token())), + name: l(FunctionName::new(function_declaration.name())), + body: l(FunctionBody::new(function_declaration.body())), } } } impl UserData for FunctionDeclaration { + fn add_fields<'lua, F: mlua::UserDataFields<'lua, Self>>(fields: &mut F) { + fields.add_field_method_get( + "function_token", + |_, FunctionDeclaration { function_token, .. }| Ok(function_token.clone()), + ); + + fields.add_field_method_get("name", |_, FunctionDeclaration { name, .. }| { + Ok(name.clone()) + }); + + fields.add_field_method_get("body", |_, FunctionDeclaration { body, .. }| { + Ok(body.clone()) + }); + } + fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) { add_to_string_display("FunctionDeclaration", methods); } @@ -603,18 +677,21 @@ impl CreateAstNode for FunctionDeclaration { #[derive(Clone)] pub struct FunctionName { - names: Punctuated, - colon_name: Option<(TokenReference, TokenReference)>, + names: ArcLocked>, + colon_name: Option>, } impl FunctionName { pub fn new(function_name: &ast::FunctionName) -> Self { FunctionName { - names: Punctuated::map_from_punctuated(function_name.names(), TokenReference::new), + names: l(Punctuated::map_from_punctuated( + function_name.names(), + TokenReference::new, + )), colon_name: match (function_name.method_colon(), function_name.method_name()) { (Some(colon), Some(name)) => { - Some((TokenReference::new(colon), TokenReference::new(name))) + Some(l((TokenReference::new(colon), TokenReference::new(name)))) } _ => None, @@ -624,6 +701,22 @@ impl FunctionName { } impl UserData for FunctionName { + fn add_fields<'lua, F: mlua::UserDataFields<'lua, Self>>(fields: &mut F) { + fields.add_field_method_get("names", |_, FunctionName { names, .. }| Ok(names.clone())); + + fields.add_field_method_get("method_colon", |_, FunctionName { colon_name, .. }| { + Ok(colon_name + .as_ref() + .map(|lock| Arc::clone(lock).read().unwrap().0.clone())) + }); + + fields.add_field_method_get("method_name", |_, FunctionName { colon_name, .. }| { + Ok(colon_name + .as_ref() + .map(|lock| Arc::clone(lock).read().unwrap().1.clone())) + }); + } + fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) { add_to_string_display("FunctionName", methods); } @@ -635,10 +728,11 @@ impl CreateAstNode for FunctionName { fn create_ast_node(&self) -> Option { Some( ast::FunctionName::new(self.names.create_ast_node()?).with_method( - self.colon_name - .as_ref() - .map(|(colon, name)| Some((colon.create_ast_node()?, name.create_ast_node()?))) - .flatten(), + self.colon_name.as_ref().and_then(|colon_name_arc| { + let colon_name_arc = Arc::clone(colon_name_arc); + let lock = colon_name_arc.read().unwrap(); + Some((lock.0.create_ast_node()?, lock.1.create_ast_node()?)) + }), ), ) } @@ -646,30 +740,62 @@ impl CreateAstNode for FunctionName { #[derive(Clone)] pub struct GenericFor { - for_token: TokenReference, - names: Punctuated, - in_token: TokenReference, - expr_list: Punctuated, - do_token: TokenReference, - block: Block, - end_token: TokenReference, + for_token: ArcLocked, + names: ArcLocked>, + in_token: ArcLocked, + expr_list: ArcLocked>, + do_token: ArcLocked, + block: ArcLocked, + end_token: ArcLocked, } impl GenericFor { pub fn new(generic_for: &ast::GenericFor) -> Self { GenericFor { - for_token: TokenReference::new(generic_for.for_token()), - names: Punctuated::map_from_punctuated(generic_for.names(), TokenReference::new), - in_token: TokenReference::new(generic_for.in_token()), - expr_list: Punctuated::map_from_punctuated(generic_for.expressions(), Expression::new), - do_token: TokenReference::new(generic_for.do_token()), - block: Block::new(generic_for.block()), - end_token: TokenReference::new(generic_for.end_token()), + for_token: l(TokenReference::new(generic_for.for_token())), + names: l(Punctuated::map_from_punctuated( + generic_for.names(), + TokenReference::new, + )), + in_token: l(TokenReference::new(generic_for.in_token())), + expr_list: l(Punctuated::map_from_punctuated( + generic_for.expressions(), + Expression::new, + )), + do_token: l(TokenReference::new(generic_for.do_token())), + block: l(Block::new(generic_for.block())), + end_token: l(TokenReference::new(generic_for.end_token())), } } } impl UserData for GenericFor { + fn add_fields<'lua, F: mlua::UserDataFields<'lua, Self>>(fields: &mut F) { + fields.add_field_method_get("for_token", |_, GenericFor { for_token, .. }| { + Ok(for_token.clone()) + }); + + fields.add_field_method_get("names", |_, GenericFor { names, .. }| Ok(names.clone())); + + fields.add_field_method_get("in_token", |_, GenericFor { in_token, .. }| { + Ok(in_token.clone()) + }); + + fields.add_field_method_get("expressions", |_, GenericFor { expr_list, .. }| { + Ok(expr_list.clone()) + }); + + fields.add_field_method_get("do_token", |_, GenericFor { do_token, .. }| { + Ok(do_token.clone()) + }); + + fields.add_field_method_get("block", |_, GenericFor { block, .. }| Ok(block.clone())); + + fields.add_field_method_get("end_token", |_, GenericFor { end_token, .. }| { + Ok(end_token.clone()) + }); + } + fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) { add_to_string_display("GenericFor", methods); } @@ -695,34 +821,62 @@ impl CreateAstNode for GenericFor { #[derive(Clone)] pub struct If { - if_token: TokenReference, - condition: Expression, - then_token: TokenReference, - block: Block, - else_if: Option>, - else_token: Option, - else_block: Option, - end_token: TokenReference, + if_token: ArcLocked, + condition: ArcLocked, + then_token: ArcLocked, + block: ArcLocked, + else_if: Option>>, + else_token: Option>, + else_block: Option>, + end_token: ArcLocked, } impl If { pub fn new(if_node: &ast::If) -> Self { If { - if_token: TokenReference::new(if_node.if_token()), - condition: Expression::new(if_node.condition()), - then_token: TokenReference::new(if_node.then_token()), - block: Block::new(if_node.block()), + if_token: l(TokenReference::new(if_node.if_token())), + condition: l(Expression::new(if_node.condition())), + then_token: l(TokenReference::new(if_node.then_token())), + block: l(Block::new(if_node.block())), else_if: if_node .else_if() - .map(|else_if| else_if.iter().map(ElseIf::new).collect()), - else_token: if_node.else_token().map(TokenReference::new), - else_block: if_node.else_block().map(Block::new), - end_token: TokenReference::new(if_node.end_token()), + .map(|else_if| else_if.iter().map(ElseIf::new).map(l).collect()), + else_token: if_node.else_token().map(TokenReference::new).map(l), + else_block: if_node.else_block().map(Block::new).map(l), + end_token: l(TokenReference::new(if_node.end_token())), } } } impl UserData for If { + fn add_fields<'lua, F: mlua::UserDataFields<'lua, Self>>(fields: &mut F) { + fields.add_field_method_get("if_token", |_, If { if_token, .. }| Ok(if_token.clone())); + + fields.add_field_method_get("condition", |_, If { condition, .. }| Ok(condition.clone())); + + fields.add_field_method_get("then_token", |_, If { then_token, .. }| { + Ok(then_token.clone()) + }); + + fields.add_field_method_get("block", |_, If { block, .. }| Ok(block.clone())); + + fields.add_field_method_get("else_if", |lua, If { else_if, .. }| { + Ok(else_if + .as_ref() + .map(|else_if| else_if.iter().map(Arc::clone).collect::>())) + }); + + fields.add_field_method_get("else_token", |_, If { else_token, .. }| { + Ok(else_token.clone()) + }); + + fields.add_field_method_get("else_block", |_, If { else_block, .. }| { + Ok(else_block.clone()) + }); + + fields.add_field_method_get("end_token", |_, If { end_token, .. }| Ok(end_token.clone())); + } + fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) { add_to_string_display("If", methods); } @@ -737,17 +891,12 @@ impl CreateAstNode for If { .with_if_token(self.if_token.create_ast_node()?) .with_then_token(self.then_token.create_ast_node()?) .with_block(self.block.create_ast_node()?) - .with_else_if( - self.else_if - .as_ref() - .map(|else_if| { - else_if - .iter() - .map(ElseIf::create_ast_node) - .collect::>>() - }) - .flatten(), - ) + .with_else_if(self.else_if.as_ref().and_then(|else_if| { + else_if + .iter() + .map(|else_if| else_if.read().unwrap().create_ast_node()) + .collect::>>() + })) .with_else_token(self.else_token.create_ast_node()) .with_else(self.else_block.create_ast_node()) .with_end_token(self.end_token.create_ast_node()?), @@ -791,30 +940,51 @@ impl Index { #[derive(Clone)] pub struct LocalAssignment { - local_token: TokenReference, - name_list: Punctuated, - equal_token: Option, - expr_list: Punctuated, + local_token: ArcLocked, + name_list: ArcLocked>, + equal_token: Option>, + expr_list: ArcLocked>, } impl LocalAssignment { pub fn new(local_assignment: &ast::LocalAssignment) -> Self { LocalAssignment { - local_token: TokenReference::new(local_assignment.local_token()), - name_list: Punctuated::map_from_punctuated( + local_token: l(TokenReference::new(local_assignment.local_token())), + name_list: l(Punctuated::map_from_punctuated( local_assignment.names(), TokenReference::new, - ), - equal_token: local_assignment.equal_token().map(TokenReference::new), - expr_list: Punctuated::map_from_punctuated( + )), + equal_token: local_assignment + .equal_token() + .map(TokenReference::new) + .map(l), + expr_list: l(Punctuated::map_from_punctuated( local_assignment.expressions(), Expression::new, - ), + )), } } } impl UserData for LocalAssignment { + fn add_fields<'lua, F: mlua::UserDataFields<'lua, Self>>(fields: &mut F) { + fields.add_field_method_get("local_token", |_, LocalAssignment { local_token, .. }| { + Ok(local_token.clone()) + }); + + fields.add_field_method_get("names", |_, LocalAssignment { name_list, .. }| { + Ok(name_list.clone()) + }); + + fields.add_field_method_get("equal_token", |_, LocalAssignment { equal_token, .. }| { + Ok(equal_token.clone()) + }); + + fields.add_field_method_get("expressions", |_, LocalAssignment { expr_list, .. }| { + Ok(expr_list.clone()) + }); + } + fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) { add_to_string_display("LocalAssignment", methods); } @@ -835,24 +1005,39 @@ impl CreateAstNode for LocalAssignment { #[derive(Clone)] pub struct LocalFunction { - local_token: TokenReference, - function_token: TokenReference, - name: TokenReference, - body: FunctionBody, + local_token: ArcLocked, + function_token: ArcLocked, + name: ArcLocked, + body: ArcLocked, } impl LocalFunction { pub fn new(local_function: &ast::LocalFunction) -> Self { LocalFunction { - local_token: TokenReference::new(local_function.local_token()), - function_token: TokenReference::new(local_function.function_token()), - name: TokenReference::new(local_function.name()), - body: FunctionBody::new(local_function.body()), + local_token: l(TokenReference::new(local_function.local_token())), + function_token: l(TokenReference::new(local_function.function_token())), + name: l(TokenReference::new(local_function.name())), + body: l(FunctionBody::new(local_function.body())), } } } impl UserData for LocalFunction { + fn add_fields<'lua, F: mlua::UserDataFields<'lua, Self>>(fields: &mut F) { + fields.add_field_method_get("local_token", |_, LocalFunction { local_token, .. }| { + Ok(local_token.clone()) + }); + + fields.add_field_method_get( + "function_token", + |_, LocalFunction { function_token, .. }| Ok(function_token.clone()), + ); + + fields.add_field_method_get("name", |_, LocalFunction { name, .. }| Ok(name.clone())); + + fields.add_field_method_get("body", |_, LocalFunction { body, .. }| Ok(body.clone())); + } + fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) { add_to_string_display("LocalFunction", methods); } @@ -873,22 +1058,32 @@ impl CreateAstNode for LocalFunction { #[derive(Clone)] pub struct MethodCall { - colon_token: TokenReference, - name: TokenReference, - args: FunctionArgs, + colon_token: ArcLocked, + name: ArcLocked, + args: ArcLocked, } impl MethodCall { pub fn new(method_call: &ast::MethodCall) -> Self { MethodCall { - colon_token: TokenReference::new(method_call.colon_token()), - name: TokenReference::new(method_call.name()), - args: FunctionArgs::new(method_call.args()), + colon_token: l(TokenReference::new(method_call.colon_token())), + name: l(TokenReference::new(method_call.name())), + args: l(FunctionArgs::new(method_call.args())), } } } impl UserData for MethodCall { + fn add_fields<'lua, F: mlua::UserDataFields<'lua, Self>>(fields: &mut F) { + fields.add_field_method_get("colon_token", |_, MethodCall { colon_token, .. }| { + Ok(colon_token.clone()) + }); + + fields.add_field_method_get("name", |_, MethodCall { name, .. }| Ok(name.clone())); + + fields.add_field_method_get("args", |_, MethodCall { args, .. }| Ok(args.clone())); + } + fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) { add_to_string_display("MethodCall", methods); } @@ -907,38 +1102,80 @@ impl CreateAstNode for MethodCall { #[derive(Clone)] pub struct NumericFor { - for_token: TokenReference, - index_variable: TokenReference, - equal_token: TokenReference, - start: Expression, - start_end_comma: TokenReference, - end: Expression, - end_step_comma: Option, - step: Option, - do_token: TokenReference, - block: Block, - end_token: TokenReference, + for_token: ArcLocked, + index_variable: ArcLocked, + equal_token: ArcLocked, + start: ArcLocked, + start_end_comma: ArcLocked, + end: ArcLocked, + end_step_comma: Option>, + step: Option>, + do_token: ArcLocked, + block: ArcLocked, + end_token: ArcLocked, } impl NumericFor { pub fn new(numeric_for: &ast::NumericFor) -> Self { NumericFor { - for_token: TokenReference::new(numeric_for.for_token()), - index_variable: TokenReference::new(numeric_for.index_variable()), - equal_token: TokenReference::new(numeric_for.equal_token()), - start: Expression::new(numeric_for.start()), - start_end_comma: TokenReference::new(numeric_for.start_end_comma()), - end: Expression::new(numeric_for.end()), - end_step_comma: numeric_for.end_step_comma().map(TokenReference::new), - step: numeric_for.step().map(Expression::new), - do_token: TokenReference::new(numeric_for.do_token()), - block: Block::new(numeric_for.block()), - end_token: TokenReference::new(numeric_for.end_token()), + for_token: l(TokenReference::new(numeric_for.for_token())), + index_variable: l(TokenReference::new(numeric_for.index_variable())), + equal_token: l(TokenReference::new(numeric_for.equal_token())), + start: l(Expression::new(numeric_for.start())), + start_end_comma: l(TokenReference::new(numeric_for.start_end_comma())), + end: l(Expression::new(numeric_for.end())), + end_step_comma: numeric_for.end_step_comma().map(TokenReference::new).map(l), + step: numeric_for.step().map(Expression::new).map(l), + do_token: l(TokenReference::new(numeric_for.do_token())), + block: l(Block::new(numeric_for.block())), + end_token: l(TokenReference::new(numeric_for.end_token())), } } } impl UserData for NumericFor { + fn add_fields<'lua, F: mlua::UserDataFields<'lua, Self>>(fields: &mut F) { + fields.add_field_method_get("for_token", |_, NumericFor { for_token, .. }| { + Ok(for_token.clone()) + }); + + fields.add_field_method_get("index_variable", |_, NumericFor { index_variable, .. }| { + Ok(index_variable.clone()) + }); + + fields.add_field_method_get("equal_token", |_, NumericFor { equal_token, .. }| { + Ok(equal_token.clone()) + }); + + fields.add_field_method_get("start", |_, NumericFor { start, .. }| Ok(start.clone())); + + fields.add_field_method_get( + "start_end_comma", + |_, + NumericFor { + start_end_comma, .. + }| Ok(start_end_comma.clone()), + ); + + fields.add_field_method_get("end", |_, NumericFor { end, .. }| Ok(end.clone())); + + fields.add_field_method_get("end_step_comma", |_, NumericFor { end_step_comma, .. }| { + Ok(end_step_comma.clone()) + }); + + fields.add_field_method_get("step", |_, NumericFor { step, .. }| Ok(step.clone())); + + fields.add_field_method_get("do_token", |_, NumericFor { do_token, .. }| { + Ok(do_token.clone()) + }); + + fields.add_field_method_get("block", |_, NumericFor { block, .. }| Ok(block.clone())); + + fields.add_field_method_get("end_token", |_, NumericFor { end_token, .. }| { + Ok(end_token.clone()) + }); + } + fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) { add_to_string_display("NumericFor", methods); } @@ -1004,20 +1241,29 @@ impl Prefix { #[derive(Clone)] pub struct Return { - token: TokenReference, - returns: Punctuated, + token: ArcLocked, + returns: ArcLocked>, } impl Return { pub fn new(return_token: &ast::Return) -> Self { Return { - token: TokenReference::new(return_token.token()), - returns: Punctuated::map_from_punctuated(return_token.returns(), Expression::new), + token: l(TokenReference::new(return_token.token())), + returns: l(Punctuated::map_from_punctuated( + return_token.returns(), + Expression::new, + )), } } } impl UserData for Return { + fn add_fields<'lua, F: mlua::UserDataFields<'lua, Self>>(fields: &mut F) { + fields.add_field_method_get("token", |_, Return { token, .. }| Ok(token.clone())); + + fields.add_field_method_get("returns", |_, Return { returns, .. }| Ok(returns.clone())); + } + fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) { add_to_string_display("Return", methods); } @@ -1037,24 +1283,38 @@ impl CreateAstNode for Return { #[derive(Clone)] pub struct Repeat { - repeat_token: TokenReference, - block: Block, - until_token: TokenReference, - until: Expression, + repeat_token: ArcLocked, + block: ArcLocked, + until_token: ArcLocked, + until: ArcLocked, } impl Repeat { pub fn new(repeat: &ast::Repeat) -> Self { Repeat { - repeat_token: TokenReference::new(repeat.repeat_token()), - block: Block::new(repeat.block()), - until_token: TokenReference::new(repeat.until_token()), - until: Expression::new(repeat.until()), + repeat_token: l(TokenReference::new(repeat.repeat_token())), + block: l(Block::new(repeat.block())), + until_token: l(TokenReference::new(repeat.until_token())), + until: l(Expression::new(repeat.until())), } } } impl UserData for Repeat { + fn add_fields<'lua, F: mlua::UserDataFields<'lua, Self>>(fields: &mut F) { + fields.add_field_method_get("repeat_token", |_, Repeat { repeat_token, .. }| { + Ok(repeat_token.clone()) + }); + + fields.add_field_method_get("block", |_, Repeat { block, .. }| Ok(block.clone())); + + fields.add_field_method_get("until_token", |_, Repeat { until_token, .. }| { + Ok(until_token.clone()) + }); + + fields.add_field_method_get("until", |_, Repeat { until, .. }| Ok(until.clone())); + } + fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) { add_to_string_display("Repeat", methods); } @@ -1137,20 +1397,33 @@ impl Suffix { #[derive(Clone)] pub struct TableConstructor { - braces: ContainedSpan, - fields: Punctuated, + braces: ArcLocked, + fields: ArcLocked>, } impl TableConstructor { pub fn new(table_constructor: &ast::TableConstructor) -> Self { TableConstructor { - braces: ContainedSpan::new(table_constructor.braces()), - fields: Punctuated::map_from_punctuated(table_constructor.fields(), Field::new), + braces: l(ContainedSpan::new(table_constructor.braces())), + fields: l(Punctuated::map_from_punctuated( + table_constructor.fields(), + Field::new, + )), } } } impl UserData for TableConstructor { + fn add_fields<'lua, F: mlua::UserDataFields<'lua, Self>>(fields: &mut F) { + fields.add_field_method_get("braces", |_, TableConstructor { braces, .. }| { + Ok(braces.clone()) + }); + + fields.add_field_method_get("fields", |_, TableConstructor { fields, .. }| { + Ok(fields.clone()) + }); + } + fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) { add_to_string_display("TableConstructor", methods); } @@ -1251,23 +1524,30 @@ impl Var { #[derive(Clone)] pub struct VarExpression { - prefix: Prefix, - suffixes: Vec, + prefix: ArcLocked, + suffixes: Vec>, } impl VarExpression { pub fn new(var_expression: &ast::VarExpression) -> Self { VarExpression { - prefix: Prefix::new(var_expression.prefix()), - suffixes: var_expression - .suffixes() - .map(|suffix| Suffix::new(suffix)) - .collect(), + prefix: l(Prefix::new(var_expression.prefix())), + suffixes: var_expression.suffixes().map(Suffix::new).map(l).collect(), } } } impl UserData for VarExpression { + fn add_fields<'lua, F: mlua::UserDataFields<'lua, Self>>(fields: &mut F) { + fields.add_field_method_get("prefix", |_, VarExpression { prefix, .. }| { + Ok(prefix.clone()) + }); + + fields.add_field_method_get("suffixes", |_, VarExpression { suffixes, .. }| { + Ok(suffixes.clone()) + }); + } + fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) { add_to_string_display("VarExpression", methods); } @@ -1290,26 +1570,44 @@ impl CreateAstNode for VarExpression { #[derive(Clone)] pub struct While { - while_token: TokenReference, - condition: Expression, - do_token: TokenReference, - block: Block, - end_token: TokenReference, + while_token: ArcLocked, + condition: ArcLocked, + do_token: ArcLocked, + block: ArcLocked, + end_token: ArcLocked, } impl While { pub fn new(while_token: &ast::While) -> Self { While { - while_token: TokenReference::new(while_token.while_token()), - condition: Expression::new(while_token.condition()), - do_token: TokenReference::new(while_token.do_token()), - block: Block::new(while_token.block()), - end_token: TokenReference::new(while_token.end_token()), + while_token: l(TokenReference::new(while_token.while_token())), + condition: l(Expression::new(while_token.condition())), + do_token: l(TokenReference::new(while_token.do_token())), + block: l(Block::new(while_token.block())), + end_token: l(TokenReference::new(while_token.end_token())), } } } impl UserData for While { + fn add_fields<'lua, F: mlua::UserDataFields<'lua, Self>>(fields: &mut F) { + fields.add_field_method_get("while_token", |_, While { while_token, .. }| { + Ok(while_token.clone()) + }); + + fields.add_field_method_get("condition", |_, While { condition, .. }| { + Ok(condition.clone()) + }); + + fields.add_field_method_get("do_token", |_, While { do_token, .. }| Ok(do_token.clone())); + + fields.add_field_method_get("block", |_, While { block, .. }| Ok(block.clone())); + + fields.add_field_method_get("end_token", |_, While { end_token, .. }| { + Ok(end_token.clone()) + }); + } + fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) { add_to_string_display("While", methods); } diff --git a/full-moon-lua-types/tests/lua/core.lua b/full-moon-lua-types/tests/lua/core.lua index 12d7ec19..d7c763e6 100644 --- a/full-moon-lua-types/tests/lua/core.lua +++ b/full-moon-lua-types/tests/lua/core.lua @@ -77,12 +77,12 @@ assert(not pcall(function() end), "stmt:expect should have thrown") local assignment = stmt:expect("Assignment") -assertEq(#assignment.var_list, 2) -assertEq(#assignment.var_list:values(), 2) +assertEq(#assignment.variables, 2) +assertEq(#assignment.variables:values(), 2) local iters = {} -for i, v in assignment.var_list do +for i, v in assignment.variables do iters[i] = v:print() end diff --git a/full-moon-lua-types/tests/lua/everything.lua b/full-moon-lua-types/tests/lua/everything.lua deleted file mode 100644 index e69de29b..00000000 diff --git a/full-moon-lua-types/tests/lua_tests.rs b/full-moon-lua-types/tests/lua_tests.rs index 2aa28283..a6835858 100644 --- a/full-moon-lua-types/tests/lua_tests.rs +++ b/full-moon-lua-types/tests/lua_tests.rs @@ -10,8 +10,3 @@ fn test_lua_code(code: &str) { fn core() { test_lua_code(include_str!("lua/core.lua")); } - -#[test] -fn everything() { - test_lua_code(include_str!("lua/everything.lua")); -} From 689cee480dd74b47af6760ee9ec4e596868b0074 Mon Sep 17 00:00:00 2001 From: Kampfkarren Date: Tue, 13 Sep 2022 21:32:46 -0700 Subject: [PATCH 09/19] Add core metamethods on everything --- full-moon-lua-types/src/core.rs | 59 +++++++++++++++++++++------------ 1 file changed, 37 insertions(+), 22 deletions(-) diff --git a/full-moon-lua-types/src/core.rs b/full-moon-lua-types/src/core.rs index 9ac98c65..1bafd615 100644 --- a/full-moon-lua-types/src/core.rs +++ b/full-moon-lua-types/src/core.rs @@ -6,10 +6,7 @@ use mlua::{Table, ToLua, UserData}; use crate::{ create_ast_node::CreateAstNode, - mlua_util::{ - add_core_meta_methods, add_newindex_block, add_print, add_to_string_display, add_visit, - ArcLocked, - }, + mlua_util::{add_core_meta_methods, add_newindex_block, add_print, add_visit, ArcLocked}, prepare_for_lua::PrepareForLua, shared::*, }; @@ -99,7 +96,7 @@ impl UserData for Assignment { } fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) { - add_to_string_display("Assignment", methods); + add_core_meta_methods("Assignment", methods); add_print(methods); } } @@ -212,6 +209,7 @@ impl UserData for Block { fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) { add_core_meta_methods("Block", methods); + add_print(methods); } } @@ -281,7 +279,8 @@ impl UserData for Do { } fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) { - add_to_string_display("Do", methods); + add_core_meta_methods("Do", methods); + add_print(methods); } } @@ -335,7 +334,8 @@ impl UserData for ElseIf { } fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) { - add_to_string_display("ElseIf", methods); + add_core_meta_methods("ElseIf", methods); + add_print(methods); } } @@ -487,7 +487,8 @@ impl UserData for FunctionBody { } fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) { - add_to_string_display("FunctionBody", methods); + add_core_meta_methods("FunctionBody", methods); + add_print(methods); } } @@ -606,7 +607,8 @@ impl UserData for FunctionCall { } fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) { - add_to_string_display("FunctionCall", methods); + add_core_meta_methods("FunctionCall", methods); + add_print(methods); } } @@ -659,7 +661,8 @@ impl UserData for FunctionDeclaration { } fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) { - add_to_string_display("FunctionDeclaration", methods); + add_core_meta_methods("FunctionDeclaration", methods); + add_print(methods); } } @@ -718,7 +721,8 @@ impl UserData for FunctionName { } fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) { - add_to_string_display("FunctionName", methods); + add_core_meta_methods("FunctionName", methods); + add_print(methods); } } @@ -797,7 +801,8 @@ impl UserData for GenericFor { } fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) { - add_to_string_display("GenericFor", methods); + add_core_meta_methods("GenericFor", methods); + add_print(methods); } } @@ -878,7 +883,8 @@ impl UserData for If { } fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) { - add_to_string_display("If", methods); + add_core_meta_methods("If", methods); + add_print(methods); } } @@ -986,7 +992,8 @@ impl UserData for LocalAssignment { } fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) { - add_to_string_display("LocalAssignment", methods); + add_core_meta_methods("LocalAssignment", methods); + add_print(methods); } } @@ -1039,7 +1046,8 @@ impl UserData for LocalFunction { } fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) { - add_to_string_display("LocalFunction", methods); + add_core_meta_methods("LocalFunction", methods); + add_print(methods); } } @@ -1085,7 +1093,8 @@ impl UserData for MethodCall { } fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) { - add_to_string_display("MethodCall", methods); + add_core_meta_methods("MethodCall", methods); + add_print(methods); } } @@ -1177,7 +1186,8 @@ impl UserData for NumericFor { } fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) { - add_to_string_display("NumericFor", methods); + add_core_meta_methods("NumericFor", methods); + add_print(methods); } } @@ -1265,7 +1275,8 @@ impl UserData for Return { } fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) { - add_to_string_display("Return", methods); + add_core_meta_methods("Return", methods); + add_print(methods); } } @@ -1316,7 +1327,8 @@ impl UserData for Repeat { } fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) { - add_to_string_display("Repeat", methods); + add_core_meta_methods("Repeat", methods); + add_print(methods); } } @@ -1425,7 +1437,8 @@ impl UserData for TableConstructor { } fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) { - add_to_string_display("TableConstructor", methods); + add_core_meta_methods("TableConstructor", methods); + add_print(methods); } } @@ -1549,7 +1562,8 @@ impl UserData for VarExpression { } fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) { - add_to_string_display("VarExpression", methods); + add_core_meta_methods("VarExpression", methods); + add_print(methods); } } @@ -1609,7 +1623,8 @@ impl UserData for While { } fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) { - add_to_string_display("While", methods); + add_core_meta_methods("While", methods); + add_print(methods); } } From e5067506a292dfb6432b696fe16b7570a63e7148 Mon Sep 17 00:00:00 2001 From: Kampfkarren Date: Wed, 14 Sep 2022 07:51:00 -0700 Subject: [PATCH 10/19] Tabs -> spaces --- .../src/lua_user_data.rs | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/full-moon-lua-types-derive/src/lua_user_data.rs b/full-moon-lua-types-derive/src/lua_user_data.rs index c478a952..be408568 100644 --- a/full-moon-lua-types-derive/src/lua_user_data.rs +++ b/full-moon-lua-types-derive/src/lua_user_data.rs @@ -335,28 +335,28 @@ pub fn derive(input: TokenStream) -> TokenStream { quote! { impl mlua::UserData for #input_ident { - fn add_fields<'lua, F: mlua::UserDataFields<'lua, Self>>(fields: &mut F) { - fields.add_field_method_get("kind", |_, this| { - Ok(#match_kind) - }); - } + fn add_fields<'lua, F: mlua::UserDataFields<'lua, Self>>(fields: &mut F) { + fields.add_field_method_get("kind", |_, this| { + Ok(#match_kind) + }); + } fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) { - crate::mlua_util::add_core_metamethods_no_tostring(stringify!(#input_ident), methods); + crate::mlua_util::add_core_metamethods_no_tostring(stringify!(#input_ident), methods); crate::mlua_util::add_print(methods); crate::mlua_util::add_visit(methods); - methods.add_meta_method(mlua::MetaMethod::ToString, |_, this, _: ()| { - Ok(#match_to_string) - }); + methods.add_meta_method(mlua::MetaMethod::ToString, |_, this, _: ()| { + Ok(#match_to_string) + }); methods.add_method("expect", |lua, this, variant: String| { #match_expect }); - methods.add_method("match", |lua, this, table: mlua::Table| { - #match_match - }); + methods.add_method("match", |lua, this, table: mlua::Table| { + #match_match + }); } } From 9a250630dc3472ceb1c2c9e11cafb99d960a2580 Mon Sep 17 00:00:00 2001 From: Kampfkarren Date: Wed, 14 Sep 2022 08:13:45 -0700 Subject: [PATCH 11/19] Split full_moon table --- full-moon-lua-types/src/lua.rs | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/full-moon-lua-types/src/lua.rs b/full-moon-lua-types/src/lua.rs index 2af133d9..b359aa6c 100644 --- a/full-moon-lua-types/src/lua.rs +++ b/full-moon-lua-types/src/lua.rs @@ -1,4 +1,4 @@ -use crate::{core, create_ast_node::CreateAstNode}; +use crate::core; pub fn create_lua() -> mlua::Result { let lua = mlua::Lua::new(); @@ -8,9 +8,7 @@ pub fn create_lua() -> mlua::Result { Ok(lua) } -fn assign_globals(lua: &mlua::Lua) -> mlua::Result<()> { - let globals = lua.globals(); - +pub fn full_moon_table(lua: &mlua::Lua) -> mlua::Result { let full_moon = lua.create_table()?; full_moon.set( @@ -22,7 +20,13 @@ fn assign_globals(lua: &mlua::Lua) -> mlua::Result<()> { })?, )?; - globals.set("full_moon", full_moon)?; + Ok(full_moon) +} + +fn assign_globals(lua: &mlua::Lua) -> mlua::Result<()> { + let globals = lua.globals(); + + globals.set("full_moon", full_moon_table(lua)?)?; Ok(()) } From c79d1231e25a7c1c4fcbf89ed6813b65f5e6b761 Mon Sep 17 00:00:00 2001 From: Kampfkarren Date: Thu, 15 Sep 2022 07:19:35 -0700 Subject: [PATCH 12/19] :range(), Send --- .../src/lua_user_data.rs | 31 ++++++++++++++-- full-moon-lua-types/Cargo.toml | 2 +- full-moon-lua-types/src/core.rs | 35 +++++++++++++++---- full-moon-lua-types/src/lib.rs | 5 ++- full-moon-lua-types/src/lua.rs | 2 +- full-moon-lua-types/src/mlua_util.rs | 26 +++++++++++++- full-moon-lua-types/src/prepare_for_lua.rs | 6 ++-- full-moon-lua-types/src/shared.rs | 22 +++++++++--- full-moon-lua-types/src/visitor.rs | 4 +-- full-moon/src/tokenizer.rs | 10 ++++++ 10 files changed, 120 insertions(+), 23 deletions(-) diff --git a/full-moon-lua-types-derive/src/lua_user_data.rs b/full-moon-lua-types-derive/src/lua_user_data.rs index be408568..1b2a4a18 100644 --- a/full-moon-lua-types-derive/src/lua_user_data.rs +++ b/full-moon-lua-types-derive/src/lua_user_data.rs @@ -175,13 +175,39 @@ pub fn derive(input: TokenStream) -> TokenStream { let fields = field .named .iter() - .map(|field| &field.ident) + .filter_map(|field| field.ident.as_ref()) + .map(quote::ToTokens::to_token_stream) .collect::>(); + let mut added_fields: Vec = Vec::new(); + + for attr in &variant.attrs { + if !attr.path.is_ident("lua") { + continue; + } + + let name_value = attr + .parse_args::() + .expect("expected name value for lua attribute"); + + if !name_value.path.is_ident("add_field") { + continue; + } + + added_fields.push( + syn::parse_str(&match name_value.lit { + syn::Lit::Str(lit_str) => lit_str.value(), + _ => panic!("expected string for add_field"), + }) + .unwrap(), + ); + } + cases.push(quote! { #input_ident::#variant_ident { #(#fields),* } => { Some(full_moon::ast::#input_ident::#variant_ident { - #(#fields: #fields.create_ast_node()?),* + #(#fields: #fields.create_ast_node()?,)* + #(#added_fields,)* }) } }); @@ -343,6 +369,7 @@ pub fn derive(input: TokenStream) -> TokenStream { fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) { crate::mlua_util::add_core_metamethods_no_tostring(stringify!(#input_ident), methods); + crate::mlua_util::add_create_ast_node_methods(methods); crate::mlua_util::add_print(methods); crate::mlua_util::add_visit(methods); diff --git a/full-moon-lua-types/Cargo.toml b/full-moon-lua-types/Cargo.toml index 45266b9a..629164ec 100644 --- a/full-moon-lua-types/Cargo.toml +++ b/full-moon-lua-types/Cargo.toml @@ -8,7 +8,7 @@ edition = "2021" [dependencies] full_moon = { version = "0.15.1", path = "../full-moon" } full_moon_lua_types_derive = { path = "../full-moon-lua-types-derive" } -mlua = { version = "0.8.3", features = ["luau"] } +mlua = { version = "0.8.3", features = ["luau", "send"] } paste = "1.0.9" [features] diff --git a/full-moon-lua-types/src/core.rs b/full-moon-lua-types/src/core.rs index 1bafd615..117009e3 100644 --- a/full-moon-lua-types/src/core.rs +++ b/full-moon-lua-types/src/core.rs @@ -6,7 +6,10 @@ use mlua::{Table, ToLua, UserData}; use crate::{ create_ast_node::CreateAstNode, - mlua_util::{add_core_meta_methods, add_newindex_block, add_print, add_visit, ArcLocked}, + mlua_util::{ + add_core_meta_methods, add_create_ast_node_methods, add_newindex_block, add_print, + add_visit, ArcLocked, + }, prepare_for_lua::PrepareForLua, shared::*, }; @@ -20,8 +23,8 @@ pub struct Ast { eof: ArcLocked, } -impl From for Ast { - fn from(ast: ast::Ast) -> Self { +impl From<&ast::Ast> for Ast { + fn from(ast: &ast::Ast) -> Self { Ast { nodes: l(Block::new(ast.nodes())), eof: l(TokenReference::new(ast.eof())), @@ -97,6 +100,7 @@ impl UserData for Assignment { fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) { add_core_meta_methods("Assignment", methods); + add_create_ast_node_methods(methods); add_print(methods); } } @@ -209,6 +213,7 @@ impl UserData for Block { fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) { add_core_meta_methods("Block", methods); + add_create_ast_node_methods(methods); add_print(methods); } } @@ -280,6 +285,7 @@ impl UserData for Do { fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) { add_core_meta_methods("Do", methods); + add_create_ast_node_methods(methods); add_print(methods); } } @@ -335,6 +341,7 @@ impl UserData for ElseIf { fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) { add_core_meta_methods("ElseIf", methods); + add_create_ast_node_methods(methods); add_print(methods); } } @@ -370,9 +377,8 @@ pub enum Expression { expression: Box>, }, - Value { - value: Box>, - }, + #[cfg_attr(feature = "luau", lua(add_field = "type_assertion: None"))] + Value { value: Box> }, } impl Expression { @@ -397,7 +403,7 @@ impl Expression { expression: Box::new(l(Expression::new(expression))), }, - ast::Expression::Value { value } => Expression::Value { + ast::Expression::Value { value, .. } => Expression::Value { value: Box::new(l(Value::new(value))), }, @@ -488,6 +494,7 @@ impl UserData for FunctionBody { fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) { add_core_meta_methods("FunctionBody", methods); + add_create_ast_node_methods(methods); add_print(methods); } } @@ -608,6 +615,7 @@ impl UserData for FunctionCall { fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) { add_core_meta_methods("FunctionCall", methods); + add_create_ast_node_methods(methods); add_print(methods); } } @@ -662,6 +670,7 @@ impl UserData for FunctionDeclaration { fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) { add_core_meta_methods("FunctionDeclaration", methods); + add_create_ast_node_methods(methods); add_print(methods); } } @@ -722,6 +731,7 @@ impl UserData for FunctionName { fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) { add_core_meta_methods("FunctionName", methods); + add_create_ast_node_methods(methods); add_print(methods); } } @@ -802,6 +812,7 @@ impl UserData for GenericFor { fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) { add_core_meta_methods("GenericFor", methods); + add_create_ast_node_methods(methods); add_print(methods); } } @@ -884,6 +895,7 @@ impl UserData for If { fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) { add_core_meta_methods("If", methods); + add_create_ast_node_methods(methods); add_print(methods); } } @@ -993,6 +1005,7 @@ impl UserData for LocalAssignment { fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) { add_core_meta_methods("LocalAssignment", methods); + add_create_ast_node_methods(methods); add_print(methods); } } @@ -1047,6 +1060,7 @@ impl UserData for LocalFunction { fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) { add_core_meta_methods("LocalFunction", methods); + add_create_ast_node_methods(methods); add_print(methods); } } @@ -1094,6 +1108,7 @@ impl UserData for MethodCall { fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) { add_core_meta_methods("MethodCall", methods); + add_create_ast_node_methods(methods); add_print(methods); } } @@ -1187,6 +1202,7 @@ impl UserData for NumericFor { fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) { add_core_meta_methods("NumericFor", methods); + add_create_ast_node_methods(methods); add_print(methods); } } @@ -1276,6 +1292,7 @@ impl UserData for Return { fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) { add_core_meta_methods("Return", methods); + add_create_ast_node_methods(methods); add_print(methods); } } @@ -1328,6 +1345,7 @@ impl UserData for Repeat { fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) { add_core_meta_methods("Repeat", methods); + add_create_ast_node_methods(methods); add_print(methods); } } @@ -1438,6 +1456,7 @@ impl UserData for TableConstructor { fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) { add_core_meta_methods("TableConstructor", methods); + add_create_ast_node_methods(methods); add_print(methods); } } @@ -1563,6 +1582,7 @@ impl UserData for VarExpression { fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) { add_core_meta_methods("VarExpression", methods); + add_create_ast_node_methods(methods); add_print(methods); } } @@ -1624,6 +1644,7 @@ impl UserData for While { fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) { add_core_meta_methods("While", methods); + add_create_ast_node_methods(methods); add_print(methods); } } diff --git a/full-moon-lua-types/src/lib.rs b/full-moon-lua-types/src/lib.rs index 1ce66bb5..bec64fd8 100644 --- a/full-moon-lua-types/src/lib.rs +++ b/full-moon-lua-types/src/lib.rs @@ -9,4 +9,7 @@ mod prepare_for_lua; mod shared; mod visitor; -pub use lua::create_lua; +pub use create_ast_node::CreateAstNode; +pub use lua::*; + +pub use crate::core::Ast; diff --git a/full-moon-lua-types/src/lua.rs b/full-moon-lua-types/src/lua.rs index b359aa6c..4ad65367 100644 --- a/full-moon-lua-types/src/lua.rs +++ b/full-moon-lua-types/src/lua.rs @@ -16,7 +16,7 @@ pub fn full_moon_table(lua: &mlua::Lua) -> mlua::Result { lua.create_function(|_, code: String| { let ast = full_moon::parse(&code).expect("NYI: Error on failure"); - Ok(core::Ast::from(ast)) + Ok(core::Ast::from(&ast)) })?, )?; diff --git a/full-moon-lua-types/src/mlua_util.rs b/full-moon-lua-types/src/mlua_util.rs index 6c338c00..4d1a5ca6 100644 --- a/full-moon-lua-types/src/mlua_util.rs +++ b/full-moon-lua-types/src/mlua_util.rs @@ -1,6 +1,7 @@ use std::sync::{Arc, RwLock}; -use mlua::{ToLua, UserData}; +use full_moon::node::Node; +use mlua::{ToLua, ToLuaMulti, UserData}; use crate::create_ast_node::CreateAstNode; @@ -23,6 +24,29 @@ pub fn add_core_metamethods_no_tostring<'lua, T: UserData>( add_newindex_block(name, methods); } +pub fn add_create_ast_node_methods<'lua, T, N>(methods: &mut impl mlua::UserDataMethods<'lua, T>) +where + T: UserData + CreateAstNode, + N: Node, +{ + add_range(methods); +} + +pub fn add_range<'lua, T, N>(methods: &mut impl mlua::UserDataMethods<'lua, T>) +where + T: UserData + CreateAstNode, + N: Node, +{ + methods.add_method("range", |lua, this, ()| { + let node = this.create_ast_node().unwrap(); + + match node.range() { + Some((start, end)) => (start.bytes(), end.bytes()).to_lua_multi(lua), + None => mlua::Value::Nil.to_lua_multi(lua), + } + }); +} + pub fn add_print<'lua, T, N>(methods: &mut impl mlua::UserDataMethods<'lua, T>) where T: UserData + CreateAstNode, diff --git a/full-moon-lua-types/src/prepare_for_lua.rs b/full-moon-lua-types/src/prepare_for_lua.rs index b8ab11b0..77ec4bad 100644 --- a/full-moon-lua-types/src/prepare_for_lua.rs +++ b/full-moon-lua-types/src/prepare_for_lua.rs @@ -8,13 +8,13 @@ pub trait PrepareForLua { fn prepare_for_lua<'lua>(&self, lua: &'lua mlua::Lua) -> mlua::Result>; } -impl PrepareForLua for ArcLocked { +impl PrepareForLua for ArcLocked { fn prepare_for_lua<'lua>(&self, lua: &'lua mlua::Lua) -> mlua::Result> { Arc::clone(self).to_lua(lua) } } -impl PrepareForLua for Vec> { +impl PrepareForLua for Vec> { fn prepare_for_lua<'lua>(&self, lua: &'lua mlua::Lua) -> mlua::Result> { self.iter() .map(Arc::clone) @@ -24,7 +24,7 @@ impl PrepareForLua for Vec> { } } -impl PrepareForLua for Box { +impl PrepareForLua for Box { fn prepare_for_lua<'lua>(&self, lua: &'lua mlua::Lua) -> mlua::Result> { (**self).clone().to_lua(lua) } diff --git a/full-moon-lua-types/src/shared.rs b/full-moon-lua-types/src/shared.rs index 05ea2ad7..62667361 100644 --- a/full-moon-lua-types/src/shared.rs +++ b/full-moon-lua-types/src/shared.rs @@ -2,6 +2,7 @@ use std::iter::FromIterator; use full_moon::{ ast::{self, punctuated::Pair}, + node::Node, tokenizer, }; @@ -9,7 +10,9 @@ use mlua::{MetaMethod, ToLua, UserData}; use crate::{ create_ast_node::CreateAstNode, - mlua_util::{add_core_meta_methods, add_print, add_to_string_display}, + mlua_util::{ + add_core_meta_methods, add_create_ast_node_methods, add_print, add_to_string_display, + }, }; #[derive(Clone)] @@ -32,6 +35,7 @@ impl ContainedSpan { impl UserData for ContainedSpan { fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) { add_core_meta_methods("ContainedSpan", methods); + add_create_ast_node_methods(methods); } } @@ -46,7 +50,7 @@ impl CreateAstNode for ContainedSpan { } } -#[derive(Clone)] +#[derive(Clone, Copy)] pub struct Position(tokenizer::Position); #[derive(Clone)] @@ -69,7 +73,7 @@ impl Punctuated { } } -impl Punctuated { +impl Punctuated { fn values<'lua>(&self, lua: &'lua mlua::Lua) -> mlua::Result> { let table = lua.create_table()?; @@ -87,7 +91,9 @@ impl FromIterator> for Punctuated { } } -impl UserData for Punctuated { +impl + Send + Sync + 'static> UserData + for Punctuated +{ fn add_fields<'lua, F: mlua::UserDataFields<'lua, Self>>(_fields: &mut F) {} fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) { @@ -105,6 +111,8 @@ impl UserData for Punctuated { methods.add_method("values", |lua, this, _: ()| { this.values(lua).map_err(mlua::Error::external) }); + + add_create_ast_node_methods(methods); } } @@ -153,7 +161,11 @@ impl CreateAstNode for Token { type Node = tokenizer::Token; fn create_ast_node(&self) -> Option { - Some(tokenizer::Token::new(self.token_type.0.clone())) + Some( + tokenizer::Token::new(self.token_type.0.clone()) + .with_start_position(self.start_position.0) + .with_end_position(self.end_position.0), + ) } } diff --git a/full-moon-lua-types/src/visitor.rs b/full-moon-lua-types/src/visitor.rs index dfd2acbd..6b38f19e 100644 --- a/full-moon-lua-types/src/visitor.rs +++ b/full-moon-lua-types/src/visitor.rs @@ -224,8 +224,8 @@ pub fn add_visit_with_visitor<'lua, T, N, F>( methods: &mut impl mlua::UserDataMethods<'lua, T>, mut callback: F, ) where - T: UserData + CreateAstNode, - F: 'static + FnMut(N, &mut LuaVisitor<'lua>), + T: UserData + Send + Sync + CreateAstNode, + F: 'static + Send + FnMut(N, &mut LuaVisitor<'lua>), { methods.add_method_mut("visit", move |_, this, visitor: VisitorTable| { let mut visitor = LuaVisitor { diff --git a/full-moon/src/tokenizer.rs b/full-moon/src/tokenizer.rs index d62cb4c3..ac00014b 100644 --- a/full-moon/src/tokenizer.rs +++ b/full-moon/src/tokenizer.rs @@ -565,6 +565,16 @@ impl Token { pub fn token_kind(&self) -> TokenKind { self.token_type().kind() } + + pub fn with_start_position(mut self, start_position: Position) -> Self { + self.start_position = start_position; + self + } + + pub fn with_end_position(mut self, end_position: Position) -> Self { + self.end_position = end_position; + self + } } impl fmt::Display for Token { From 46b6c692c28be6f30e7c9ad8b8bf03cff83b299d Mon Sep 17 00:00:00 2001 From: Kampfkarren Date: Thu, 22 Sep 2022 08:32:33 -0700 Subject: [PATCH 13/19] 0.16.2 --- full-moon-lua-types/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/full-moon-lua-types/Cargo.toml b/full-moon-lua-types/Cargo.toml index 629164ec..966a89d0 100644 --- a/full-moon-lua-types/Cargo.toml +++ b/full-moon-lua-types/Cargo.toml @@ -6,7 +6,7 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -full_moon = { version = "0.15.1", path = "../full-moon" } +full_moon = { version = "0.16.2", path = "../full-moon" } full_moon_lua_types_derive = { path = "../full-moon-lua-types-derive" } mlua = { version = "0.8.3", features = ["luau", "send"] } paste = "1.0.9" From e5c6c916ef205a9a70eefe6ccc92c3be26397202 Mon Sep 17 00:00:00 2001 From: Kampfkarren Date: Thu, 22 Sep 2022 22:09:05 -0700 Subject: [PATCH 14/19] Add string to :match() --- .../src/lua_user_data.rs | 45 +++++++++++++------ full-moon-lua-types/src/either.rs | 30 +++++++++++++ full-moon-lua-types/src/lib.rs | 1 + full-moon-lua-types/tests/lua/core.lua | 3 ++ 4 files changed, 66 insertions(+), 13 deletions(-) create mode 100644 full-moon-lua-types/src/either.rs diff --git a/full-moon-lua-types-derive/src/lua_user_data.rs b/full-moon-lua-types-derive/src/lua_user_data.rs index 1b2a4a18..e5bb10a4 100644 --- a/full-moon-lua-types-derive/src/lua_user_data.rs +++ b/full-moon-lua-types-derive/src/lua_user_data.rs @@ -128,21 +128,33 @@ pub fn derive(input: TokenStream) -> TokenStream { #(#cases,)* }; - match table.get::<_, Option>(function_name)? { - Some(mlua::Value::Function(function)) => { - function.call::<_, mlua::Value>(args) - } + match table_or_name { + crate::either::Either::A(table) => { + match table.get::<_, Option>(function_name)? { + Some(mlua::Value::Function(function)) => { + function.call::<_, mlua::MultiValue>(args) + } - Some(other) => { - Err(mlua::Error::external(format!( - "expected function for {}, got {}", - function_name, - other.type_name(), - ))) + Some(other) => { + Err(mlua::Error::external(format!( + "expected function for {}, got {}", + function_name, + other.type_name(), + ))) + } + + None => { + mlua::Value::Nil.to_lua_multi(lua) + } + } } - None => { - Ok(mlua::Value::Nil) + crate::either::Either::B(name) => { + if name == function_name { + Ok(args) + } else { + mlua::Value::Nil.to_lua_multi(lua) + } } } } @@ -381,7 +393,14 @@ pub fn derive(input: TokenStream) -> TokenStream { #match_expect }); - methods.add_method("match", |lua, this, table: mlua::Table| { + methods.add_method("match", |lua, this, value: mlua::Value| { + let table_or_name = crate::either::take_either::( + lua, + value, + "table of variants to callbacks", + "variant name", + )?; + #match_match }); } diff --git a/full-moon-lua-types/src/either.rs b/full-moon-lua-types/src/either.rs new file mode 100644 index 00000000..32e9e6c3 --- /dev/null +++ b/full-moon-lua-types/src/either.rs @@ -0,0 +1,30 @@ +use mlua::FromLua; + +#[derive(Clone, Debug, PartialEq, Eq)] +pub enum Either { + A(A), + B(B), +} + +pub fn take_either<'lua, A: FromLua<'lua>, B: FromLua<'lua>>( + lua: &'lua mlua::Lua, + lua_value: mlua::Value<'lua>, + a_detail: &str, + b_detail: &str, +) -> mlua::Result> { + let type_name = lua_value.type_name(); + + // Values are cheap to clone, they're mostly just references + if let Ok(a) = A::from_lua(lua_value.clone(), lua) { + return Ok(Either::A(a)); + } + + if let Ok(b) = B::from_lua(lua_value, lua) { + return Ok(Either::B(b)); + } + + Err(mlua::Error::external(format!( + "expected either {a_detail} or {b_detail}, received {}", + type_name, + ))) +} diff --git a/full-moon-lua-types/src/lib.rs b/full-moon-lua-types/src/lib.rs index bec64fd8..40a5e953 100644 --- a/full-moon-lua-types/src/lib.rs +++ b/full-moon-lua-types/src/lib.rs @@ -3,6 +3,7 @@ mod core; mod create_ast_node; +mod either; mod lua; mod mlua_util; mod prepare_for_lua; diff --git a/full-moon-lua-types/tests/lua/core.lua b/full-moon-lua-types/tests/lua/core.lua index d7c763e6..65697c78 100644 --- a/full-moon-lua-types/tests/lua/core.lua +++ b/full-moon-lua-types/tests/lua/core.lua @@ -80,6 +80,9 @@ local assignment = stmt:expect("Assignment") assertEq(#assignment.variables, 2) assertEq(#assignment.variables:values(), 2) +assert(stmt:match("Assignment")) +assertEq(stmt:match("While"), nil) + local iters = {} for i, v in assignment.variables do From b49eb82510166721ee7a4a77641a202621671444 Mon Sep 17 00:00:00 2001 From: Kampfkarren Date: Thu, 22 Sep 2022 22:09:49 -0700 Subject: [PATCH 15/19] More accurate test --- full-moon-lua-types/tests/lua/core.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/full-moon-lua-types/tests/lua/core.lua b/full-moon-lua-types/tests/lua/core.lua index 65697c78..00dbf6fb 100644 --- a/full-moon-lua-types/tests/lua/core.lua +++ b/full-moon-lua-types/tests/lua/core.lua @@ -80,7 +80,7 @@ local assignment = stmt:expect("Assignment") assertEq(#assignment.variables, 2) assertEq(#assignment.variables:values(), 2) -assert(stmt:match("Assignment")) +assertEq(tostring(stmt:match("Assignment")), tostring(assignment)) assertEq(stmt:match("While"), nil) local iters = {} From bc89a1e052d952a72b5b68e814d943f8722d95ce Mon Sep 17 00:00:00 2001 From: Kampfkarren Date: Thu, 22 Sep 2022 23:29:07 -0700 Subject: [PATCH 16/19] TokenReference basics --- full-moon-lua-types/src/shared.rs | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/full-moon-lua-types/src/shared.rs b/full-moon-lua-types/src/shared.rs index 62667361..65d7a366 100644 --- a/full-moon-lua-types/src/shared.rs +++ b/full-moon-lua-types/src/shared.rs @@ -10,9 +10,7 @@ use mlua::{MetaMethod, ToLua, UserData}; use crate::{ create_ast_node::CreateAstNode, - mlua_util::{ - add_core_meta_methods, add_create_ast_node_methods, add_print, add_to_string_display, - }, + mlua_util::{add_core_meta_methods, add_create_ast_node_methods, add_print}, }; #[derive(Clone)] @@ -193,8 +191,13 @@ impl TokenReference { } } -// TODO -impl UserData for TokenReference {} +impl UserData for TokenReference { + fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) { + add_core_meta_methods("TokenReference", methods); + add_create_ast_node_methods(methods); + add_print(methods); + } +} impl CreateAstNode for TokenReference { type Node = tokenizer::TokenReference; From 6d7573e2ae76b0b76573a30a46302d1ff48c4345 Mon Sep 17 00:00:00 2001 From: Kampfkarren Date: Fri, 23 Sep 2022 09:40:44 -0700 Subject: [PATCH 17/19] Token API --- full-moon-lua-types/src/core.rs | 2 +- full-moon-lua-types/src/shared.rs | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/full-moon-lua-types/src/core.rs b/full-moon-lua-types/src/core.rs index 117009e3..51e42d0d 100644 --- a/full-moon-lua-types/src/core.rs +++ b/full-moon-lua-types/src/core.rs @@ -876,7 +876,7 @@ impl UserData for If { fields.add_field_method_get("block", |_, If { block, .. }| Ok(block.clone())); - fields.add_field_method_get("else_if", |lua, If { else_if, .. }| { + fields.add_field_method_get("else_if", |_, If { else_if, .. }| { Ok(else_if .as_ref() .map(|else_if| else_if.iter().map(Arc::clone).collect::>())) diff --git a/full-moon-lua-types/src/shared.rs b/full-moon-lua-types/src/shared.rs index 65d7a366..3b249697 100644 --- a/full-moon-lua-types/src/shared.rs +++ b/full-moon-lua-types/src/shared.rs @@ -192,6 +192,10 @@ impl TokenReference { } impl UserData for TokenReference { + fn add_fields<'lua, F: mlua::UserDataFields<'lua, Self>>(fields: &mut F) { + fields.add_field_method_get("token", |lua, this: &Self| this.token.clone().to_lua(lua)); + } + fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) { add_core_meta_methods("TokenReference", methods); add_create_ast_node_methods(methods); From c51f58ec984c6968837a9c8970b8eaa5d8ac0f69 Mon Sep 17 00:00:00 2001 From: Kampfkarren Date: Fri, 23 Sep 2022 19:58:13 -0700 Subject: [PATCH 18/19] More traits --- .../src/{create_ast_node.rs => ast_traits.rs} | 6 + full-moon-lua-types/src/core.rs | 207 +++++++++++++++++- full-moon-lua-types/src/extract_node.rs | 82 +++++++ full-moon-lua-types/src/lib.rs | 9 +- full-moon-lua-types/src/mlua_util.rs | 2 +- full-moon-lua-types/src/shared.rs | 15 +- full-moon-lua-types/src/visitor.rs | 2 +- 7 files changed, 315 insertions(+), 8 deletions(-) rename full-moon-lua-types/src/{create_ast_node.rs => ast_traits.rs} (88%) create mode 100644 full-moon-lua-types/src/extract_node.rs diff --git a/full-moon-lua-types/src/create_ast_node.rs b/full-moon-lua-types/src/ast_traits.rs similarity index 88% rename from full-moon-lua-types/src/create_ast_node.rs rename to full-moon-lua-types/src/ast_traits.rs index 7dc6b12f..28aa5195 100644 --- a/full-moon-lua-types/src/create_ast_node.rs +++ b/full-moon-lua-types/src/ast_traits.rs @@ -1,5 +1,7 @@ use std::sync::Arc; +use mlua::ToLua; + use crate::mlua_util::ArcLocked; pub trait CreateAstNode { @@ -39,3 +41,7 @@ impl CreateAstNode for (T, U) { Some((self.0.create_ast_node()?, self.1.create_ast_node()?)) } } + +pub trait AstToLua { + fn ast_to_lua<'lua>(&self, lua: &'lua mlua::Lua) -> mlua::Result>; +} diff --git a/full-moon-lua-types/src/core.rs b/full-moon-lua-types/src/core.rs index 51e42d0d..eb6c0e05 100644 --- a/full-moon-lua-types/src/core.rs +++ b/full-moon-lua-types/src/core.rs @@ -5,13 +5,14 @@ use full_moon_lua_types_derive::LuaUserData; use mlua::{Table, ToLua, UserData}; use crate::{ - create_ast_node::CreateAstNode, + ast_traits::CreateAstNode, mlua_util::{ add_core_meta_methods, add_create_ast_node_methods, add_newindex_block, add_print, add_visit, ArcLocked, }, prepare_for_lua::PrepareForLua, shared::*, + AstToLua, }; fn l(t: T) -> ArcLocked { @@ -61,6 +62,12 @@ impl CreateAstNode for Ast { } } +impl AstToLua for ast::Ast { + fn ast_to_lua<'lua>(&self, lua: &'lua mlua::Lua) -> mlua::Result> { + Ast::from(self).to_lua(lua) + } +} + pub struct Assignment { var_list: ArcLocked>, equal_token: ArcLocked, @@ -119,6 +126,12 @@ impl CreateAstNode for Assignment { } } +impl AstToLua for ast::Assignment { + fn ast_to_lua<'lua>(&self, lua: &'lua mlua::Lua) -> mlua::Result> { + Assignment::new(self).to_lua(lua) + } +} + #[derive(Clone, LuaUserData)] pub enum BinOp { And(ArcLocked), @@ -165,6 +178,12 @@ impl BinOp { } } +impl AstToLua for ast::BinOp { + fn ast_to_lua<'lua>(&self, lua: &'lua mlua::Lua) -> mlua::Result> { + BinOp::new(self).to_lua(lua) + } +} + #[derive(Clone)] pub struct Block { stmts: Vec<(ArcLocked, Option>)>, @@ -239,6 +258,12 @@ impl CreateAstNode for Block { } } +impl AstToLua for ast::Block { + fn ast_to_lua<'lua>(&self, lua: &'lua mlua::Lua) -> mlua::Result> { + Block::new(self).to_lua(lua) + } +} + #[derive(Clone, LuaUserData)] pub enum Call { AnonymousCall(ArcLocked), @@ -257,6 +282,12 @@ impl Call { } } +impl AstToLua for ast::Call { + fn ast_to_lua<'lua>(&self, lua: &'lua mlua::Lua) -> mlua::Result> { + Call::new(self).to_lua(lua) + } +} + #[derive(Clone)] pub struct Do { do_token: ArcLocked, @@ -303,6 +334,12 @@ impl CreateAstNode for Do { } } +impl AstToLua for ast::Do { + fn ast_to_lua<'lua>(&self, lua: &'lua mlua::Lua) -> mlua::Result> { + Do::new(self).to_lua(lua) + } +} + #[derive(Clone)] pub struct ElseIf { else_if_token: ArcLocked, @@ -359,6 +396,12 @@ impl CreateAstNode for ElseIf { } } +impl AstToLua for ast::ElseIf { + fn ast_to_lua<'lua>(&self, lua: &'lua mlua::Lua) -> mlua::Result> { + ElseIf::new(self).to_lua(lua) + } +} + #[derive(Clone, LuaUserData)] pub enum Expression { BinaryOperator { @@ -412,6 +455,12 @@ impl Expression { } } +impl AstToLua for ast::Expression { + fn ast_to_lua<'lua>(&self, lua: &'lua mlua::Lua) -> mlua::Result> { + Expression::new(self).to_lua(lua) + } +} + #[derive(Clone, LuaUserData)] pub enum FunctionArgs { Parentheses { @@ -446,6 +495,12 @@ impl FunctionArgs { } } +impl AstToLua for ast::FunctionArgs { + fn ast_to_lua<'lua>(&self, lua: &'lua mlua::Lua) -> mlua::Result> { + FunctionArgs::new(self).to_lua(lua) + } +} + #[derive(Clone)] pub struct FunctionBody { parameters_parentheses: ArcLocked, @@ -513,6 +568,12 @@ impl CreateAstNode for FunctionBody { } } +impl AstToLua for ast::FunctionBody { + fn ast_to_lua<'lua>(&self, lua: &'lua mlua::Lua) -> mlua::Result> { + FunctionBody::new(self).to_lua(lua) + } +} + #[derive(Clone, LuaUserData)] pub enum LastStmt { Break(ArcLocked), @@ -540,6 +601,12 @@ impl LastStmt { } } +impl AstToLua for ast::LastStmt { + fn ast_to_lua<'lua>(&self, lua: &'lua mlua::Lua) -> mlua::Result> { + LastStmt::new(self).to_lua(lua) + } +} + #[derive(Clone, LuaUserData)] pub enum Field { ExpressionKey { @@ -586,6 +653,12 @@ impl Field { } } +impl AstToLua for ast::Field { + fn ast_to_lua<'lua>(&self, lua: &'lua mlua::Lua) -> mlua::Result> { + Field::new(self).to_lua(lua) + } +} + #[derive(Clone)] pub struct FunctionCall { prefix: ArcLocked, @@ -635,6 +708,12 @@ impl CreateAstNode for FunctionCall { } } +impl AstToLua for ast::FunctionCall { + fn ast_to_lua<'lua>(&self, lua: &'lua mlua::Lua) -> mlua::Result> { + FunctionCall::new(self).to_lua(lua) + } +} + #[derive(Clone)] pub struct FunctionDeclaration { function_token: ArcLocked, @@ -687,6 +766,12 @@ impl CreateAstNode for FunctionDeclaration { } } +impl AstToLua for ast::FunctionDeclaration { + fn ast_to_lua<'lua>(&self, lua: &'lua mlua::Lua) -> mlua::Result> { + FunctionDeclaration::new(self).to_lua(lua) + } +} + #[derive(Clone)] pub struct FunctionName { names: ArcLocked>, @@ -752,6 +837,12 @@ impl CreateAstNode for FunctionName { } } +impl AstToLua for ast::FunctionName { + fn ast_to_lua<'lua>(&self, lua: &'lua mlua::Lua) -> mlua::Result> { + FunctionName::new(self).to_lua(lua) + } +} + #[derive(Clone)] pub struct GenericFor { for_token: ArcLocked, @@ -835,6 +926,12 @@ impl CreateAstNode for GenericFor { } } +impl AstToLua for ast::GenericFor { + fn ast_to_lua<'lua>(&self, lua: &'lua mlua::Lua) -> mlua::Result> { + GenericFor::new(self).to_lua(lua) + } +} + #[derive(Clone)] pub struct If { if_token: ArcLocked, @@ -922,6 +1019,12 @@ impl CreateAstNode for If { } } +impl AstToLua for ast::If { + fn ast_to_lua<'lua>(&self, lua: &'lua mlua::Lua) -> mlua::Result> { + If::new(self).to_lua(lua) + } +} + #[derive(Clone, LuaUserData)] pub enum Index { Brackets { @@ -956,6 +1059,12 @@ impl Index { } } +impl AstToLua for ast::Index { + fn ast_to_lua<'lua>(&self, lua: &'lua mlua::Lua) -> mlua::Result> { + Index::new(self).to_lua(lua) + } +} + #[derive(Clone)] pub struct LocalAssignment { local_token: ArcLocked, @@ -1023,6 +1132,12 @@ impl CreateAstNode for LocalAssignment { } } +impl AstToLua for ast::LocalAssignment { + fn ast_to_lua<'lua>(&self, lua: &'lua mlua::Lua) -> mlua::Result> { + LocalAssignment::new(self).to_lua(lua) + } +} + #[derive(Clone)] pub struct LocalFunction { local_token: ArcLocked, @@ -1078,6 +1193,12 @@ impl CreateAstNode for LocalFunction { } } +impl AstToLua for ast::LocalFunction { + fn ast_to_lua<'lua>(&self, lua: &'lua mlua::Lua) -> mlua::Result> { + LocalFunction::new(self).to_lua(lua) + } +} + #[derive(Clone)] pub struct MethodCall { colon_token: ArcLocked, @@ -1124,6 +1245,12 @@ impl CreateAstNode for MethodCall { } } +impl AstToLua for ast::MethodCall { + fn ast_to_lua<'lua>(&self, lua: &'lua mlua::Lua) -> mlua::Result> { + MethodCall::new(self).to_lua(lua) + } +} + #[derive(Clone)] pub struct NumericFor { for_token: ArcLocked, @@ -1229,6 +1356,12 @@ impl CreateAstNode for NumericFor { } } +impl AstToLua for ast::NumericFor { + fn ast_to_lua<'lua>(&self, lua: &'lua mlua::Lua) -> mlua::Result> { + NumericFor::new(self).to_lua(lua) + } +} + #[derive(Clone, LuaUserData)] pub enum Parameter { Ellipse(ArcLocked), @@ -1249,6 +1382,12 @@ impl Parameter { } } +impl AstToLua for ast::Parameter { + fn ast_to_lua<'lua>(&self, lua: &'lua mlua::Lua) -> mlua::Result> { + Parameter::new(self).to_lua(lua) + } +} + #[derive(Clone, LuaUserData)] pub enum Prefix { Expression(ArcLocked), @@ -1265,6 +1404,12 @@ impl Prefix { } } +impl AstToLua for ast::Prefix { + fn ast_to_lua<'lua>(&self, lua: &'lua mlua::Lua) -> mlua::Result> { + Prefix::new(self).to_lua(lua) + } +} + #[derive(Clone)] pub struct Return { token: ArcLocked, @@ -1309,6 +1454,12 @@ impl CreateAstNode for Return { } } +impl AstToLua for ast::Return { + fn ast_to_lua<'lua>(&self, lua: &'lua mlua::Lua) -> mlua::Result> { + Return::new(self).to_lua(lua) + } +} + #[derive(Clone)] pub struct Repeat { repeat_token: ArcLocked, @@ -1363,6 +1514,12 @@ impl CreateAstNode for Repeat { } } +impl AstToLua for ast::Repeat { + fn ast_to_lua<'lua>(&self, lua: &'lua mlua::Lua) -> mlua::Result> { + Repeat::new(self).to_lua(lua) + } +} + #[derive(Clone, LuaUserData)] pub enum Stmt { Assignment(ArcLocked), @@ -1409,6 +1566,12 @@ impl Stmt { } } +impl AstToLua for ast::Stmt { + fn ast_to_lua<'lua>(&self, lua: &'lua mlua::Lua) -> mlua::Result> { + Stmt::new(self).to_lua(lua) + } +} + #[derive(Clone, LuaUserData)] pub enum Suffix { Call(ArcLocked), @@ -1425,6 +1588,12 @@ impl Suffix { } } +impl AstToLua for ast::Suffix { + fn ast_to_lua<'lua>(&self, lua: &'lua mlua::Lua) -> mlua::Result> { + Suffix::new(self).to_lua(lua) + } +} + #[derive(Clone)] pub struct TableConstructor { braces: ArcLocked, @@ -1473,6 +1642,12 @@ impl CreateAstNode for TableConstructor { } } +impl AstToLua for ast::TableConstructor { + fn ast_to_lua<'lua>(&self, lua: &'lua mlua::Lua) -> mlua::Result> { + TableConstructor::new(self).to_lua(lua) + } +} + #[derive(Clone, LuaUserData)] pub enum UnOp { Minus(ArcLocked), @@ -1491,6 +1666,12 @@ impl UnOp { } } +impl AstToLua for ast::UnOp { + fn ast_to_lua<'lua>(&self, lua: &'lua mlua::Lua) -> mlua::Result> { + UnOp::new(self).to_lua(lua) + } +} + #[derive(Clone, LuaUserData)] pub enum Value { #[lua( @@ -1538,6 +1719,12 @@ impl Value { } } +impl AstToLua for ast::Value { + fn ast_to_lua<'lua>(&self, lua: &'lua mlua::Lua) -> mlua::Result> { + Value::new(self).to_lua(lua) + } +} + #[derive(Clone, LuaUserData)] pub enum Var { Expression(ArcLocked), @@ -1554,6 +1741,12 @@ impl Var { } } +impl AstToLua for ast::Var { + fn ast_to_lua<'lua>(&self, lua: &'lua mlua::Lua) -> mlua::Result> { + Var::new(self).to_lua(lua) + } +} + #[derive(Clone)] pub struct VarExpression { prefix: ArcLocked, @@ -1602,6 +1795,12 @@ impl CreateAstNode for VarExpression { } } +impl AstToLua for ast::VarExpression { + fn ast_to_lua<'lua>(&self, lua: &'lua mlua::Lua) -> mlua::Result> { + VarExpression::new(self).to_lua(lua) + } +} + #[derive(Clone)] pub struct While { while_token: ArcLocked, @@ -1662,3 +1861,9 @@ impl CreateAstNode for While { ) } } + +impl AstToLua for ast::While { + fn ast_to_lua<'lua>(&self, lua: &'lua mlua::Lua) -> mlua::Result> { + While::new(self).to_lua(lua) + } +} diff --git a/full-moon-lua-types/src/extract_node.rs b/full-moon-lua-types/src/extract_node.rs new file mode 100644 index 00000000..f834a890 --- /dev/null +++ b/full-moon-lua-types/src/extract_node.rs @@ -0,0 +1,82 @@ +use crate::{core, mlua_util::ArcLocked, shared, CreateAstNode}; + +use full_moon::{ast, node::Node, tokenizer, visitors::Visit}; +use mlua::FromLua; + +macro_rules! all_nodes { + (pub enum AnyNode { + $( + $name:ident: $lua_type:ty => $ast_type:ty, + )+ + }) => { + pub enum AnyNode { + $( + $name($ast_type), + )+ + } + + impl<'lua> FromLua<'lua> for AnyNode { + fn from_lua(value: mlua::Value, _: &mlua::Lua) -> mlua::Result { + if let mlua::Value::UserData(user_data) = &value { + $( + if let Ok(lua_node) = user_data.borrow::<$lua_type>() { + return Ok(AnyNode::$name(match lua_node.create_ast_node() { + Some(ast_node) => ast_node, + None => return Err(mlua::Error::external(format!("could not convert {} to an AST node", stringify!($name)))), + })); + } + + if let Ok(lua_node) = user_data.borrow::>() { + return Ok(AnyNode::$name(match lua_node.create_ast_node() { + Some(ast_node) => ast_node, + None => return Err(mlua::Error::external(format!("could not convert {} to an AST node", stringify!($name)))), + })); + } + )+ + } + + Err(mlua::Error::external(format!("Expected a node, received {}", value.type_name()))) + } + } + }; +} + +all_nodes!(pub enum AnyNode { + Ast: core::Ast => ast::Ast, + Assignment: core::Assignment => ast::Assignment, + BinOp: core::BinOp => ast::BinOp, + Block: core::Block => ast::Block, + Call: core::Call => ast::Call, + Do: core::Do => ast::Do, + ElseIf: core::ElseIf => ast::ElseIf, + Expression: core::Expression => ast::Expression, + Field: core::Field => ast::Field, + FunctionArgs: core::FunctionArgs => ast::FunctionArgs, + FunctionBody: core::FunctionBody => ast::FunctionBody, + FunctionCall: core::FunctionCall => ast::FunctionCall, + FunctionDeclaration: core::FunctionDeclaration => ast::FunctionDeclaration, + FunctionName: core::FunctionName => ast::FunctionName, + GenericFor: core::GenericFor => ast::GenericFor, + If: core::If => ast::If, + Index: core::Index => ast::Index, + LastStmt: core::LastStmt => ast::LastStmt, + LocalAssignment: core::LocalAssignment => ast::LocalAssignment, + LocalFunction: core::LocalFunction => ast::LocalFunction, + MethodCall: core::MethodCall => ast::MethodCall, + NumericFor: core::NumericFor => ast::NumericFor, + Parameter: core::Parameter => ast::Parameter, + Prefix: core::Prefix => ast::Prefix, + Repeat: core::Repeat => ast::Repeat, + Return: core::Return => ast::Return, + Stmt: core::Stmt => ast::Stmt, + Suffix: core::Suffix => ast::Suffix, + TableConstructor: core::TableConstructor => ast::TableConstructor, + UnOp: core::UnOp => ast::UnOp, + Value: core::Value => ast::Value, + Var: core::Var => ast::Var, + VarExpression: core::VarExpression => ast::VarExpression, + While: core::While => ast::While, + + ContainedSpan: shared::ContainedSpan => ast::span::ContainedSpan, + TokenReference: shared::TokenReference => tokenizer::TokenReference, +}); diff --git a/full-moon-lua-types/src/lib.rs b/full-moon-lua-types/src/lib.rs index 40a5e953..6920d065 100644 --- a/full-moon-lua-types/src/lib.rs +++ b/full-moon-lua-types/src/lib.rs @@ -1,16 +1,17 @@ // fix this later? #![allow(clippy::large_enum_variant)] +mod ast_traits; mod core; -mod create_ast_node; mod either; +mod extract_node; mod lua; mod mlua_util; mod prepare_for_lua; mod shared; mod visitor; -pub use create_ast_node::CreateAstNode; -pub use lua::*; - pub use crate::core::Ast; +pub use ast_traits::*; +pub use extract_node::AnyNode; +pub use lua::*; diff --git a/full-moon-lua-types/src/mlua_util.rs b/full-moon-lua-types/src/mlua_util.rs index 4d1a5ca6..a1146eda 100644 --- a/full-moon-lua-types/src/mlua_util.rs +++ b/full-moon-lua-types/src/mlua_util.rs @@ -3,7 +3,7 @@ use std::sync::{Arc, RwLock}; use full_moon::node::Node; use mlua::{ToLua, ToLuaMulti, UserData}; -use crate::create_ast_node::CreateAstNode; +use crate::ast_traits::CreateAstNode; pub use crate::visitor::add_visit; diff --git a/full-moon-lua-types/src/shared.rs b/full-moon-lua-types/src/shared.rs index 3b249697..3aab9ac4 100644 --- a/full-moon-lua-types/src/shared.rs +++ b/full-moon-lua-types/src/shared.rs @@ -9,8 +9,9 @@ use full_moon::{ use mlua::{MetaMethod, ToLua, UserData}; use crate::{ - create_ast_node::CreateAstNode, + ast_traits::CreateAstNode, mlua_util::{add_core_meta_methods, add_create_ast_node_methods, add_print}, + AstToLua, }; #[derive(Clone)] @@ -48,6 +49,12 @@ impl CreateAstNode for ContainedSpan { } } +impl AstToLua for ast::span::ContainedSpan { + fn ast_to_lua<'lua>(&self, lua: &'lua mlua::Lua) -> mlua::Result> { + ContainedSpan::new(self).to_lua(lua) + } +} + #[derive(Clone, Copy)] pub struct Position(tokenizer::Position); @@ -220,3 +227,9 @@ impl CreateAstNode for TokenReference { )) } } + +impl AstToLua for tokenizer::TokenReference { + fn ast_to_lua<'lua>(&self, lua: &'lua mlua::Lua) -> mlua::Result> { + TokenReference::new(self).to_lua(lua) + } +} diff --git a/full-moon-lua-types/src/visitor.rs b/full-moon-lua-types/src/visitor.rs index 6b38f19e..66ed1fd7 100644 --- a/full-moon-lua-types/src/visitor.rs +++ b/full-moon-lua-types/src/visitor.rs @@ -1,4 +1,4 @@ -use crate::{core, create_ast_node::CreateAstNode, shared}; +use crate::{ast_traits::CreateAstNode, core, shared}; use full_moon::{ ast, node::Node, From 9e1c3b468e150d3347fffbac810c5c4775856cb4 Mon Sep 17 00:00:00 2001 From: Kampfkarren Date: Sat, 24 Sep 2022 18:08:48 -0700 Subject: [PATCH 19/19] Include the derive --- full-moon-lua-types-derive/src/lua_user_data.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/full-moon-lua-types-derive/src/lua_user_data.rs b/full-moon-lua-types-derive/src/lua_user_data.rs index e5bb10a4..4408c276 100644 --- a/full-moon-lua-types-derive/src/lua_user_data.rs +++ b/full-moon-lua-types-derive/src/lua_user_data.rs @@ -406,7 +406,7 @@ pub fn derive(input: TokenStream) -> TokenStream { } } - impl crate::create_ast_node::CreateAstNode for #input_ident { + impl crate::ast_traits::CreateAstNode for #input_ident { type Node = full_moon::ast::#input_ident; fn create_ast_node(&self) -> Option {