Make #alias work.

This commit is contained in:
Condorra 2024-09-27 21:57:36 +10:00
parent ff840c04c2
commit a215133ea6
4 changed files with 231 additions and 165 deletions

View File

@ -3,9 +3,10 @@ use anyhow::Error;
use piccolo::{
async_callback::{AsyncSequence, Locals},
meta_ops::{self, MetaResult},
stash::Fetchable,
Callback, Closure, Context, Executor, ExternError, FromValue, Function, IntoValue, Lua,
MetaMethod, Stack, StashedError, StashedExecutor, StashedFunction, StashedTable, StashedValue,
Table, Value, Variadic,
MetaMethod, Stack, StashedError, StashedExecutor, StashedFunction, StashedValue, Table, Value,
Variadic,
};
use yew::UseStateSetter;
@ -147,11 +148,21 @@ pub fn install_lua_globals(
.map_err(|_| Error::msg("Can't add command"))?;
};
}
register_command!(alias);
macro_rules! register_stateless_command {
($sym: ident) => {
cmd_table
.set(
ctx,
ctx.intern_static(stringify!($sym).as_bytes()),
$sym(ctx),
)
.map_err(|_| Error::msg("Can't add command"))?;
};
}
register_stateless_command!(alias);
register_command!(close_mud);
register_command!(connect_mud);
register_command!(create_match_table);
register_stateless_command!(create_match_table);
register_command!(delete_mud);
register_command!(echo);
register_command!(echo_frame);
@ -210,6 +221,22 @@ pub fn install_lua_globals(
.map_err(|_| Error::msg("Can't add handler"))?;
};
}
macro_rules! register_stateless_class_function {
($class_table: ident, $sym: ident) => {
$class_table
.set(
ctx,
ctx.intern_static(stringify!($sym).as_bytes()),
$sym(ctx),
)
.map_err(|_| Error::msg("Can't add handler"))?;
};
($class_table: ident, $name: literal, $sym: ident) => {
$class_table
.set(ctx, ctx.intern_static($name.as_bytes()), $sym(ctx))
.map_err(|_| Error::msg("Can't add handler"))?;
};
}
register_class_function!(mud_class_table, mudoutput_line);
register_class_function!(mud_class_table, mudoutput_prompt);
@ -254,9 +281,17 @@ pub fn install_lua_globals(
let match_table_class_table = Table::new(&ctx);
classes_table.set(ctx, "match_table", match_table_class_table)?;
match_table_class_table.set(ctx, MetaMethod::Index, match_table_class_table)?;
register_class_function!(match_table_class_table, "add", match_table_add);
register_class_function!(match_table_class_table, "remove", match_table_remove);
register_class_function!(match_table_class_table, "lua_table", match_table_lua_table);
register_stateless_class_function!(match_table_class_table, "add", match_table_add);
register_stateless_class_function!(
match_table_class_table,
"remove",
match_table_remove
);
register_stateless_class_function!(
match_table_class_table,
"lua_table",
match_table_lua_table
);
register_class_function!(
match_table_class_table,
"try_run_sub",
@ -312,12 +347,15 @@ pub fn prep_metaop_call<'gc, const N: usize>(
}
}
pub async fn call_checking_metatable<'gc, 'a>(
pub async fn call_checking_metatable<'gc, T: Fetchable>(
seq: &mut AsyncSequence,
obj: StashedTable,
obj: T,
func_name: &'static str,
arguments: &[StashedValue],
) -> Result<(), StashedError> {
) -> Result<(), StashedError>
where
for<'gcb> <T as Fetchable>::Fetched<'gcb>: IntoValue<'gcb>,
{
let call = seq.try_enter(|ctx, locals, _execution, mut stack| {
let obj = locals.fetch(&obj);
stack.consume(ctx)?;

View File

@ -1,23 +1,20 @@
use crate::{
echo_to_term_frame, id_intern::intern_id, GlobalLayoutCell, GlobalLayoutState, GlobalMemoCell,
TermFrame,
echo_to_term_frame,
id_intern::intern_id,
match_table::{create_match_table, match_table_add},
GlobalLayoutCell, GlobalLayoutState, GlobalMemoCell, TermFrame,
};
use gc_arena::{Gc, Rootable};
use piccolo::{
self, async_sequence, Callback, CallbackReturn, Context, FromValue, Function, IntoValue,
SequenceReturn, Table, UserData, Value, Variadic,
SequenceReturn, StashedTable, StashedUserData, StashedValue, Table, UserData, Value, Variadic,
};
use regex::Regex;
use std::{rc::Rc, str};
use yew::UseStateSetter;
use super::call_checking_metatable;
pub fn alias<'gc, 'a>(
ctx: Context<'gc>,
_global_memo: &'a GlobalMemoCell,
_global_layout: &'a UseStateSetter<GlobalLayoutCell>,
) -> Callback<'gc> {
pub fn alias<'gc, 'a>(ctx: Context<'gc>) -> Callback<'gc> {
Callback::from_fn(&ctx, move |ctx, _ex, mut stack| {
let info: Table = ctx.get_global("info")?;
let cur_frame: TermFrame =
@ -43,11 +40,20 @@ pub fn alias<'gc, 'a>(
))?;
}
let aliases: Table = cur_frame.get(ctx, "aliases")?;
let aliases: UserData = cur_frame.get(ctx, "aliases")?;
aliases.set(ctx, alias_match, sub_to)?;
stack.push_back(aliases.into_value(ctx));
stack.push_back(alias_match.into_value(ctx));
stack.push_back(sub_to.into_value(ctx));
let seq = async_sequence(&ctx, |locals, mut seq| {
let add_func = locals.stash(&ctx, Function::Callback(match_table_add(ctx)));
async move {
seq.call(&add_func, 0).await?;
Ok(SequenceReturn::Return)
}
});
Ok(piccolo::CallbackReturn::Return)
Ok(piccolo::CallbackReturn::Sequence(seq))
})
}
@ -229,7 +235,8 @@ pub fn ensure_frame_instance<'gc>(ctx: Context<'gc>, frame: &TermFrame) -> Callb
let frame_tab = locals.stash(&ctx, frame_tab);
let frame = locals.stash(&ctx, frame);
async move {
call_checking_metatable(&mut seq, frame_tab, "new", &[frame]).await?;
call_checking_metatable::<StashedTable>(&mut seq, frame_tab, "new", &[frame])
.await?;
Ok(SequenceReturn::Return)
}
});
@ -251,10 +258,21 @@ pub(super) fn new_frame<'gc>(ctx: Context<'gc>, _global_memo: &GlobalMemoCell) -
frame_tab.set(ctx, ctx.intern_static(b"frame"), frame)?;
let aliases_tab: Table = Table::new(&ctx);
frame_tab.set(ctx, ctx.intern_static(b"aliases"), aliases_tab)?;
let seq = async_sequence(&ctx, |locals, mut seq| {
let frame_tab = locals.stash(&ctx, frame_tab);
let create_match_tab = locals.stash(&ctx, Function::Callback(create_match_table(ctx)));
async move {
seq.call(&create_match_tab, 0).await?;
seq.try_enter(|ctx, locals, _exec, mut stack| {
let frame_tab = locals.fetch(&frame_tab);
frame_tab.set(ctx, "aliases", stack.consume::<Value>(ctx)?)?;
Ok(())
})?;
Ok(piccolo::SequenceReturn::Return)
}
});
Ok(piccolo::CallbackReturn::Return)
Ok(piccolo::CallbackReturn::Sequence(seq))
})
}
@ -268,7 +286,7 @@ pub(super) fn send_command_to_frame<'gc>(ctx: Context<'gc>) -> Callback<'gc> {
let frame = locals.stash(&ctx, frame);
let line = locals.stash(&ctx, line.into_value(ctx));
async move {
call_checking_metatable(&mut seq, frame, "input", &[line]).await?;
call_checking_metatable::<StashedTable>(&mut seq, frame, "input", &[line]).await?;
Ok(SequenceReturn::Return)
}
});
@ -278,47 +296,64 @@ pub(super) fn send_command_to_frame<'gc>(ctx: Context<'gc>) -> Callback<'gc> {
pub(super) fn frame_input<'gc>(ctx: Context<'gc>, _global_memo: &GlobalMemoCell) -> Callback<'gc> {
Callback::from_fn(&ctx, move |ctx, _ex, mut stack| {
let frame_tab: Table = Table::from_value(
ctx,
stack
let callback_return = {
let frame_tab: Table = Table::from_value(
ctx,
stack
.pop_front()
.ok_or_else(|| anyhow::Error::msg("classes.frame:input missing object!"))?,
)?;
let line: Value = stack
.pop_front()
.ok_or_else(|| anyhow::Error::msg("classes.frame:new missing object!"))?,
)?;
let line: Value = stack
.pop_front()
.ok_or_else(|| anyhow::Error::msg("classes.frame:new missing line!"))?;
stack.consume(ctx)?;
.ok_or_else(|| anyhow::Error::msg("classes.frame:input missing line!"))?;
stack.consume(ctx)?;
// Check for an alias match...
for (alias_match, alias_sub) in frame_tab.get::<&str, Table>(ctx, "aliases")?.iter() {
if let Some(alias_match) = piccolo::String::from_value(ctx, alias_match)
.ok()
.and_then(|am| am.to_str().ok())
.and_then(|v| Regex::new(v).ok())
{
if let Some(alias_sub) = piccolo::String::from_value(ctx, alias_sub)
.ok()
.and_then(|am| am.to_str().ok())
{}
}
}
let aliases: UserData = frame_tab.get(ctx, "aliases")?;
let frame: Value = frame_tab.get(ctx, "frame")?;
let linked_mud = frame_tab.get_value(ctx, ctx.intern_static(b"linked_mud"));
if linked_mud.is_nil() {
return Ok(piccolo::CallbackReturn::Return);
}
let linked_mud: Table = Table::from_value(ctx, linked_mud)?;
let seq = async_sequence(&ctx, |locals, mut seq| {
let aliases = locals.stash(&ctx, aliases);
let line = locals.stash(&ctx, line);
let frame_tab = locals.stash(&ctx, frame_tab);
let frame = locals.stash(&ctx, frame);
async move {
call_checking_metatable::<StashedUserData>(
&mut seq,
aliases.clone(),
"try_run_sub",
&[line.clone(), frame],
)
.await?;
let (alias_hit, linked_mud, linked_mud_nil) =
seq.try_enter(|ctx, locals, _ex, mut stack| {
let linked_mud = locals
.fetch(&frame_tab)
.get_value(ctx, ctx.intern_static(b"linked_mud"));
Ok((
stack.consume::<bool>(ctx)?,
locals.stash(&ctx, linked_mud),
linked_mud.is_nil(),
))
})?;
// linked_mud:mudinput_line(line)
let seq = async_sequence(&ctx, |locals, mut seq| {
let linked_mud = locals.stash(&ctx, linked_mud);
let line = locals.stash(&ctx, line);
async move {
call_checking_metatable(&mut seq, linked_mud, "mudinput_line", &[line]).await?;
Ok(SequenceReturn::Return)
}
});
if alias_hit || linked_mud_nil {
return Ok(SequenceReturn::Return);
}
Ok(piccolo::CallbackReturn::Sequence(seq))
call_checking_metatable::<StashedValue>(
&mut seq,
linked_mud,
"mudinput_line",
&[line],
)
.await?;
Ok(SequenceReturn::Return)
}
});
Ok(piccolo::CallbackReturn::Sequence(seq))
};
callback_return
})
}

View File

@ -204,7 +204,7 @@ pub(super) fn connect_mud<'gc>(
let seq = async_sequence(&ctx, |locals, mut seq| {
let conntab = locals.stash(&ctx, conntab);
async move {
call_checking_metatable(&mut seq, conntab, "new", &[]).await?;
call_checking_metatable::<StashedTable>(&mut seq, conntab, "new", &[]).await?;
Ok(SequenceReturn::Return)
}
});
@ -319,7 +319,7 @@ pub(super) fn mudoutput<'gc>(ctx: Context<'gc>, _global_memo: &GlobalMemoCell) -
.collect();
async move {
for (func_name, params) in fns {
call_checking_metatable(
call_checking_metatable::<StashedTable>(
&mut seq,
conntab.clone(),
func_name,
@ -401,7 +401,13 @@ pub(super) fn mudoutput_line<'gc>(
let line = locals.stash(&ctx, line.into_value(ctx));
async move {
for frameroute in frameroutes {
call_checking_metatable(&mut seq, frameroute, "route", &[line.clone()]).await?;
call_checking_metatable::<StashedTable>(
&mut seq,
frameroute,
"route",
&[line.clone()],
)
.await?;
}
Ok(SequenceReturn::Return)
}
@ -494,7 +500,8 @@ pub(super) fn new_mud<'gc>(ctx: Context<'gc>, _global_memo: &GlobalMemoCell) ->
let curr_frame = locals.stash(&ctx, curr_frame);
async move {
call_checking_metatable(&mut seq, frameroute, "new", &[curr_frame]).await?;
call_checking_metatable::<StashedTable>(&mut seq, frameroute, "new", &[curr_frame])
.await?;
Ok(SequenceReturn::Return)
}
});

View File

@ -8,12 +8,11 @@ use gc_arena::{Collect, GcRefLock, Rootable};
use itertools::Itertools;
use piccolo::{Callback, Context, IntoValue, Table, UserData, Value};
use regex::Regex;
use yew::UseStateSetter;
use crate::{
lua_engine::frames::try_unwrap_frame,
parsing::{parse_commands, quote_string, ArgumentGuard, ParsedArgument, ParsedCommand},
GlobalLayoutCell, GlobalMemoCell,
GlobalMemoCell,
};
#[derive(Default, Debug, Collect)]
@ -251,6 +250,87 @@ pub enum SubTextPart {
Variable(String),
}
pub fn create_match_table<'gc, 'a>(ctx: Context<'gc>) -> Callback<'gc> {
Callback::from_fn(&ctx, move |ctx, _ex, mut stack| {
let _: () = stack.consume(ctx)?;
let user_data = UserData::<'gc>::new::<Rootable!['gcb => GcRefLock<'gcb, MatchSubTable>]>(
&ctx,
GcRefLock::new(&ctx, <MatchSubTable as Default>::default().into()),
);
let match_table_class: Table = ctx
.get_global::<Table>("classes")?
.get(ctx, "match_table")?;
user_data.set_metatable(&ctx, Some(match_table_class));
stack.push_back(user_data.into_value(ctx));
Ok(piccolo::CallbackReturn::Return)
})
}
pub fn match_table_add<'gc, 'a>(ctx: Context<'gc>) -> Callback<'gc> {
Callback::from_fn(&ctx, move |ctx, _ex, mut stack| {
let (match_table, match_text, sub_text): (UserData, piccolo::String, piccolo::String) =
stack.consume(ctx)?;
match_table
.downcast::<Rootable!['gcb => GcRefLock<'gcb, MatchSubTable>]>()?
.borrow_mut(&ctx)
.add_record(match_text.to_str()?, sub_text.to_str()?)?;
Ok(piccolo::CallbackReturn::Return)
})
}
pub fn match_table_remove<'gc, 'a>(ctx: Context<'gc>) -> Callback<'gc> {
Callback::from_fn(&ctx, move |ctx, _ex, mut stack| {
let (match_table, match_text): (UserData, piccolo::String) = stack.consume(ctx)?;
match_table
.downcast::<Rootable!['gcb => GcRefLock<'gcb, MatchSubTable>]>()?
.borrow_mut(&ctx)
.remove_record(match_text.to_str()?)?;
Ok(piccolo::CallbackReturn::Return)
})
}
pub fn match_table_lua_table<'gc, 'a>(ctx: Context<'gc>) -> Callback<'gc> {
Callback::from_fn(&ctx, move |ctx, _ex, mut stack| {
let match_table: UserData = stack.consume(ctx)?;
stack.push_back(
match_table
.downcast::<Rootable!['gcb => GcRefLock<'gcb, MatchSubTable>]>()?
.borrow_mut(&ctx)
.to_value(ctx)?,
);
Ok(piccolo::CallbackReturn::Return)
})
}
pub fn match_table_try_run_sub<'gc, 'a>(
ctx: Context<'gc>,
global_memo: &'a GlobalMemoCell,
) -> Callback<'gc> {
let global_memo = global_memo.clone();
Callback::from_fn(&ctx, move |ctx, _ex, mut stack| {
let (match_table, sub, frame): (UserData, piccolo::String, Value) = stack.consume(ctx)?;
let frame = try_unwrap_frame(ctx, &frame)?;
let cmds = match_table
.downcast::<Rootable!['gcb => GcRefLock<'gcb, MatchSubTable>]>()?
.borrow()
.try_sub(sub.to_str()?);
match cmds {
None => stack.push_back(false.into_value(ctx)),
Some(cmds) => {
let mut cq = global_memo.command_queue.borrow_mut();
for cmd in cmds.into_iter().rev() {
cq.push_front((frame.clone(), cmd));
}
stack.push_back(Value::Boolean(true))
}
}
Ok(piccolo::CallbackReturn::Return)
})
}
#[cfg(test)]
mod tests {
use super::*;
@ -452,97 +532,3 @@ mod tests {
.is_err())
}
}
pub fn create_match_table<'gc, 'a>(
ctx: Context<'gc>,
_global_memo: &'a GlobalMemoCell,
_global_layout: &'a UseStateSetter<GlobalLayoutCell>,
) -> Callback<'gc> {
Callback::from_fn(&ctx, move |ctx, _ex, mut stack| {
let _: () = stack.consume(ctx)?;
let user_data = UserData::<'gc>::new::<Rootable!['gcb => GcRefLock<'gcb, MatchSubTable>]>(
&ctx,
GcRefLock::new(&ctx, <MatchSubTable as Default>::default().into()),
);
let match_table_class: Table = ctx
.get_global::<Table>("classes")?
.get(ctx, "match_table")?;
user_data.set_metatable(&ctx, Some(match_table_class));
stack.push_back(user_data.into_value(ctx));
Ok(piccolo::CallbackReturn::Return)
})
}
pub fn match_table_add<'gc, 'a>(
ctx: Context<'gc>,
_global_memo: &'a GlobalMemoCell,
) -> Callback<'gc> {
Callback::from_fn(&ctx, move |ctx, _ex, mut stack| {
let (match_table, match_text, sub_text): (UserData, piccolo::String, piccolo::String) =
stack.consume(ctx)?;
match_table
.downcast::<Rootable!['gcb => GcRefLock<'gcb, MatchSubTable>]>()?
.borrow_mut(&ctx)
.add_record(match_text.to_str()?, sub_text.to_str()?)?;
Ok(piccolo::CallbackReturn::Return)
})
}
pub fn match_table_remove<'gc, 'a>(
ctx: Context<'gc>,
_global_memo: &'a GlobalMemoCell,
) -> Callback<'gc> {
Callback::from_fn(&ctx, move |ctx, _ex, mut stack| {
let (match_table, match_text): (UserData, piccolo::String) = stack.consume(ctx)?;
match_table
.downcast::<Rootable!['gcb => GcRefLock<'gcb, MatchSubTable>]>()?
.borrow_mut(&ctx)
.remove_record(match_text.to_str()?)?;
Ok(piccolo::CallbackReturn::Return)
})
}
pub fn match_table_lua_table<'gc, 'a>(
ctx: Context<'gc>,
_global_memo: &'a GlobalMemoCell,
) -> Callback<'gc> {
Callback::from_fn(&ctx, move |ctx, _ex, mut stack| {
let match_table: UserData = stack.consume(ctx)?;
stack.push_back(
match_table
.downcast::<Rootable!['gcb => GcRefLock<'gcb, MatchSubTable>]>()?
.borrow_mut(&ctx)
.to_value(ctx)?,
);
Ok(piccolo::CallbackReturn::Return)
})
}
pub fn match_table_try_run_sub<'gc, 'a>(
ctx: Context<'gc>,
global_memo: &'a GlobalMemoCell,
) -> Callback<'gc> {
let global_memo = global_memo.clone();
Callback::from_fn(&ctx, move |ctx, _ex, mut stack| {
let (match_table, sub, frame): (UserData, piccolo::String, Value) = stack.consume(ctx)?;
let frame = try_unwrap_frame(ctx, &frame)?;
let cmds = match_table
.downcast::<Rootable!['gcb => GcRefLock<'gcb, MatchSubTable>]>()?
.borrow()
.try_sub(sub.to_str()?);
match cmds {
None => stack.push_back(false.into_value(ctx)),
Some(cmds) => {
let mut cq = global_memo.command_queue.borrow_mut();
for cmd in cmds.into_iter().rev() {
cq.push_front((frame.clone(), cmd));
}
stack.push_back(Value::Boolean(true))
}
}
Ok(piccolo::CallbackReturn::Return)
})
}