diff --git a/docs/config/events.md b/docs/config/events.md
index 81f9ba3f..e63e9bf1 100644
--- a/docs/config/events.md
+++ b/docs/config/events.md
@@ -8,6 +8,13 @@ const example = `event MyEvent = {
bar: u8,
},
}`
+
+const dataExample = `event MyEvent = {
+ from: Server,
+ type: Reliable,
+ call: ManyAsync,
+ data: (boolean, u32, string)
+}`
# Events
@@ -56,3 +63,8 @@ Use synchronous events with extreme caution.
### `data`
This field determines the data that is sent with the event. It can be any [Zap type](./types.md).
+
+- If the event does not require any data, the `data` field should be excluded.
+- You can pass multiple arguments to the event by separating each type with a comma and wrapping them all in parentheses:
+
+
diff --git a/docs/config/functions.md b/docs/config/functions.md
index d7341a5d..1b9132c5 100644
--- a/docs/config/functions.md
+++ b/docs/config/functions.md
@@ -7,6 +7,12 @@ const example = `funct Test = {
},
rets: enum { Success, Fail }
}`
+
+const multiArgsRetsExample = `funct MultipleArgsRets = {
+ call: Async,
+ args: (boolean, u8),
+ rets: (boolean, string)
+}`
# Functions
@@ -41,6 +47,16 @@ Use synchronous functions with extreme caution.
This field determines the data that is sent to the server. It can be any [Zap type](./types.md).
+- If the client doesn't send any data, the `args` field should be excluded.
+- You can pass multiple arguments to the function by separating each type with a comma and wrapping them all in parentheses:
+
+
+
### `rets`
This field determines the data that is sent back to the client from the server. It can be any [Zap type](./types.md).
+
+- If the server doesn't return any data, the `rets` field should be excluded.
+- The function can return multiple values by separating each type with a comma and wrapping them all in parentheses:
+
+
diff --git a/docs/usage/events.md b/docs/usage/events.md
index e7b9b325..79f3f481 100644
--- a/docs/usage/events.md
+++ b/docs/usage/events.md
@@ -13,9 +13,7 @@ event AnotherEvent = {
from: Client,
type: Reliable,
call: SingleAsync,
- data: struct {
- baz: boolean,
- },
+ data: (boolean, u8)
}`
@@ -50,7 +48,7 @@ If your event's [call field](../config/events.md#call) is `SingleAsync` or `Sing
local Zap = require(Path.To.Zap)
-- only server listeners are given the player argument
-Zap.AnotherEvent.SetCallback(function(Player, Data)
+Zap.AnotherEvent.SetCallback(function(Player, Bool, Number)
-- Do something with the player and data
end)
```
@@ -81,14 +79,12 @@ Use `Sync` events only when performance is critical.
## Firing From the Client
-The client only has a single function for firing events, `Fire`. This function takes the event's data as its only argument.
+The client only has a single function for firing events, `Fire`. This function takes the event's data as it arguments.
```lua
local Zap = require(Path.To.Zap)
-Zap.AnotherEvent.Fire({
- baz = true,
-})
+Zap.AnotherEvent.Fire(true, 32)
```
## Firing From the Server
@@ -116,7 +112,7 @@ Zap.MyEvent.Fire(Player, {
### FireAll
-The `FireAll` function takes the event's data as its only argument. It will fire the event to all players.
+The `FireAll` function takes the event's data as its arguments. It will fire the event to all players.
```lua
local Zap = require(Path.To.Zap)
diff --git a/zap/src/config.rs b/zap/src/config.rs
index e8e9d83e..b88383fa 100644
--- a/zap/src/config.rs
+++ b/zap/src/config.rs
@@ -76,8 +76,8 @@ impl std::fmt::Display for YieldType {
pub struct FnDecl<'src> {
pub name: &'src str,
pub call: FnCall,
- pub args: Option>,
- pub rets: Option>,
+ pub args: Option>>,
+ pub rets: Option>>,
pub id: usize,
}
@@ -93,7 +93,7 @@ pub struct EvDecl<'src> {
pub from: EvSource,
pub evty: EvType,
pub call: EvCall,
- pub data: Option>,
+ pub data: Option>>,
pub id: usize,
}
diff --git a/zap/src/irgen/des.rs b/zap/src/irgen/des.rs
index c83caad0..860ccb74 100644
--- a/zap/src/irgen/des.rs
+++ b/zap/src/irgen/des.rs
@@ -14,8 +14,20 @@ impl Gen for Des {
self.buf.push(stmt);
}
- fn gen(mut self, var: Var, ty: &Ty) -> Vec {
- self.push_ty(ty, var);
+ fn gen(mut self, var: Var, types: &[Ty]) -> Vec {
+ for (i, ty) in types.iter().enumerate() {
+ let var = if i > 0 {
+ Var::Name(match &var {
+ Var::Name(name) => format!("{name}{}", i + 1),
+ _ => unreachable!(),
+ })
+ } else {
+ var.clone()
+ };
+
+ self.push_ty(ty, var);
+ }
+
self.buf
}
@@ -419,11 +431,11 @@ impl Des {
}
}
-pub fn gen(ty: &Ty, var: &str, checks: bool) -> Vec {
+pub fn gen(types: &[Ty], var: &str, checks: bool) -> Vec {
Des {
checks,
buf: vec![],
var_occurrences: HashMap::new(),
}
- .gen(var.into(), ty)
+ .gen(var.into(), types)
}
diff --git a/zap/src/irgen/mod.rs b/zap/src/irgen/mod.rs
index 03b3c051..88c16014 100644
--- a/zap/src/irgen/mod.rs
+++ b/zap/src/irgen/mod.rs
@@ -9,7 +9,7 @@ pub mod ser;
pub trait Gen {
fn push_stmt(&mut self, stmt: Stmt);
- fn gen(self, var: Var, ty: &Ty<'_>) -> Vec;
+ fn gen(self, var: Var, types: &[Ty]) -> Vec;
fn push_local(&mut self, name: String, expr: Option) {
self.push_stmt(Stmt::Local(name, expr))
diff --git a/zap/src/irgen/ser.rs b/zap/src/irgen/ser.rs
index 73ca1c1a..5fcadaf0 100644
--- a/zap/src/irgen/ser.rs
+++ b/zap/src/irgen/ser.rs
@@ -14,8 +14,20 @@ impl Gen for Ser {
self.buf.push(stmt);
}
- fn gen(mut self, var: Var, ty: &Ty) -> Vec {
- self.push_ty(ty, var);
+ fn gen(mut self, var: Var, types: &[Ty]) -> Vec {
+ for (i, ty) in types.iter().enumerate() {
+ let var = if i > 0 {
+ Var::Name(match &var {
+ Var::Name(name) => format!("{name}{}", i + 1),
+ _ => unreachable!(),
+ })
+ } else {
+ var.clone()
+ };
+
+ self.push_ty(ty, var);
+ }
+
self.buf
}
@@ -357,11 +369,11 @@ impl Ser {
}
}
-pub fn gen(ty: &Ty, var: &str, checks: bool) -> Vec {
+pub fn gen(types: &[Ty], var: &str, checks: bool) -> Vec {
Ser {
checks,
buf: vec![],
var_occurrences: HashMap::new(),
}
- .gen(var.into(), ty)
+ .gen(var.into(), types)
}
diff --git a/zap/src/output/luau/client.rs b/zap/src/output/luau/client.rs
index a6703919..0e89e6ae 100644
--- a/zap/src/output/luau/client.rs
+++ b/zap/src/output/luau/client.rs
@@ -1,5 +1,5 @@
use crate::{
- config::{Config, EvCall, EvDecl, EvSource, EvType, FnDecl, TyDecl, YieldType},
+ config::{Config, EvCall, EvDecl, EvSource, EvType, FnDecl, Ty, TyDecl, YieldType},
irgen::{des, ser},
};
@@ -103,14 +103,14 @@ impl<'src> ClientOutput<'src> {
self.push_line(&format!("function types.write_{name}(value: {name})"));
self.indent();
- self.push_stmts(&ser::gen(ty, "value", self.config.write_checks));
+ self.push_stmts(&ser::gen(&[ty.clone()], "value", self.config.write_checks));
self.dedent();
self.push_line("end");
self.push_line(&format!("function types.read_{name}()"));
self.indent();
self.push_line("local value;");
- self.push_stmts(&des::gen(ty, "value", false));
+ self.push_stmts(&des::gen(&[ty.clone()], "value", false));
self.push_line("return value");
self.dedent();
self.push_line("end");
@@ -174,6 +174,23 @@ impl<'src> ClientOutput<'src> {
));
}
+ fn get_values(&self, data: &Option>) -> String {
+ if let Some(types) = data {
+ (1..=types.len())
+ .map(|i| {
+ if i == 1 {
+ "value".to_string()
+ } else {
+ format!("value{}", i)
+ }
+ })
+ .collect::>()
+ .join(", ")
+ } else {
+ "value".to_string()
+ }
+ }
+
fn push_reliable_callback(&mut self, first: bool, ev: &EvDecl) {
let id = ev.id;
@@ -193,7 +210,9 @@ impl<'src> ClientOutput<'src> {
self.indent();
- self.push_line("local value");
+ let values = self.get_values(&ev.data);
+
+ self.push_line(&format!("local {values}"));
if let Some(data) = &ev.data {
self.push_stmts(&des::gen(data, "value", true));
@@ -213,10 +232,10 @@ impl<'src> ClientOutput<'src> {
}
match ev.call {
- EvCall::SingleSync => self.push_line(&format!("events[{id}](value)")),
- EvCall::SingleAsync => self.push_line(&format!("task.spawn(events[{id}], value)")),
- EvCall::ManySync => self.push_line("cb(value)"),
- EvCall::ManyAsync => self.push_line("task.spawn(cb, value)"),
+ EvCall::SingleSync => self.push_line(&format!("events[{id}]({values})")),
+ EvCall::SingleAsync => self.push_line(&format!("task.spawn(events[{id}], {values})")),
+ EvCall::ManySync => self.push_line(&format!("cb({values})")),
+ EvCall::ManyAsync => self.push_line(&format!("task.spawn(cb, {values})")),
}
if ev.call == EvCall::ManySync || ev.call == EvCall::ManyAsync {
@@ -228,8 +247,13 @@ impl<'src> ClientOutput<'src> {
self.push_line("else");
self.indent();
- if ev.data.is_some() {
- self.push_line(&format!("table.insert(event_queue[{id}], value)"));
+ if let Some(types) = &ev.data {
+ if types.len() > 1 {
+ self.push_line(&format!("table.insert(event_queue[{id}], {{ {values} }})"));
+ } else {
+ self.push_line(&format!("table.insert(event_queue[{id}], value)"));
+ }
+
self.push_line(&format!("if #event_queue[{id}] > 64 then"));
} else {
self.push_line(&format!("event_queue[{id}] += 1"));
@@ -280,7 +304,9 @@ impl<'src> ClientOutput<'src> {
self.push_line("local call_id = buffer.readu8(incoming_buff, read(1))");
- self.push_line("local value");
+ let values = self.get_values(&fndecl.rets);
+
+ self.push_line(&format!("local {values}"));
if let Some(data) = &fndecl.rets {
self.push_stmts(&des::gen(data, "value", true));
@@ -288,10 +314,10 @@ impl<'src> ClientOutput<'src> {
match self.config.yield_type {
YieldType::Yield | YieldType::Future => {
- self.push_line(&format!("task.spawn(event_queue[{id}][call_id], value)"));
+ self.push_line(&format!("task.spawn(event_queue[{id}][call_id], {values})"));
}
YieldType::Promise => {
- self.push_line(&format!("event_queue[{id}][call_id](value)"));
+ self.push_line(&format!("event_queue[{id}][call_id]({values})"));
}
}
@@ -369,7 +395,9 @@ impl<'src> ClientOutput<'src> {
self.indent();
- self.push_line("local value");
+ let values = self.get_values(&ev.data);
+
+ self.push_line(&format!("local {values}"));
if let Some(data) = &ev.data {
self.push_stmts(&des::gen(data, "value", self.config.write_checks));
@@ -389,10 +417,10 @@ impl<'src> ClientOutput<'src> {
}
match ev.call {
- EvCall::SingleSync => self.push_line(&format!("events[{id}](value)")),
- EvCall::SingleAsync => self.push_line(&format!("task.spawn(events[{id}], value)")),
- EvCall::ManySync => self.push_line("cb(value)"),
- EvCall::ManyAsync => self.push_line("task.spawn(cb, value)"),
+ EvCall::SingleSync => self.push_line(&format!("events[{id}]({values})")),
+ EvCall::SingleAsync => self.push_line(&format!("task.spawn(events[{id}], {values})")),
+ EvCall::ManySync => self.push_line(&format!("cb({values})")),
+ EvCall::ManyAsync => self.push_line(&format!("task.spawn(cb, {values})")),
}
if ev.call == EvCall::ManySync || ev.call == EvCall::ManyAsync {
@@ -404,8 +432,13 @@ impl<'src> ClientOutput<'src> {
self.push_line("else");
self.indent();
- if ev.data.is_some() {
- self.push_line(&format!("table.insert(event_queue[{id}], value)"));
+ if let Some(types) = &ev.data {
+ if types.len() > 1 {
+ self.push_line(&format!("table.insert(event_queue[{id}], {{ {values} }})"));
+ } else {
+ self.push_line(&format!("table.insert(event_queue[{id}], value)"));
+ }
+
self.push_line(&format!("if #event_queue[{id}] > 64 then"));
} else {
self.push_line(&format!("event_queue[{id}] += 1"));
@@ -515,6 +548,23 @@ impl<'src> ClientOutput<'src> {
));
}
+ fn push_value_parameters(&mut self, types: &[Ty]) {
+ for (i, ty) in types.iter().enumerate() {
+ let value = format!(
+ "{}{}",
+ self.config.casing.with("Value", "value", "value"),
+ if i == 0 { "".to_string() } else { (i + 1).to_string() }
+ );
+
+ if i > 0 {
+ self.push(", ");
+ }
+
+ self.push(&format!("{value}: "));
+ self.push_ty(ty);
+ }
+ }
+
fn push_return_fire(&mut self, ev: &EvDecl) {
let fire = self.config.casing.with("Fire", "fire", "fire");
let value = self.config.casing.with("Value", "value", "value");
@@ -522,9 +572,8 @@ impl<'src> ClientOutput<'src> {
self.push_indent();
self.push(&format!("{fire} = function("));
- if let Some(data) = &ev.data {
- self.push(&format!("{value}: "));
- self.push_ty(data);
+ if let Some(types) = &ev.data {
+ self.push_value_parameters(types);
}
self.push(")\n");
@@ -569,6 +618,14 @@ impl<'src> ClientOutput<'src> {
}
}
+ fn push_queued_value(&mut self, types: &[Ty]) {
+ if types.len() > 1 {
+ self.push("unpack(value)");
+ } else {
+ self.push("value");
+ }
+ }
+
fn push_return_setcallback(&mut self, ev: &EvDecl) {
let id = ev.id;
@@ -578,8 +635,8 @@ impl<'src> ClientOutput<'src> {
self.push_indent();
self.push(&format!("{set_callback} = function({callback}: ("));
- if let Some(data) = &ev.data {
- self.push_ty(data);
+ if let Some(types) = &ev.data {
+ self.push_value_parameters(types);
}
self.push(") -> ()): () -> ()\n");
@@ -587,14 +644,20 @@ impl<'src> ClientOutput<'src> {
self.push_line(&format!("events[{id}] = {callback}"));
- if ev.data.is_some() {
+ if let Some(types) = &ev.data {
self.push_line(&format!("for _, value in event_queue[{id}] do"));
self.indent();
if ev.call == EvCall::SingleSync {
- self.push_line(&format!("{callback}(value)"))
+ self.push_indent();
+ self.push(&format!("{callback}("));
+ self.push_queued_value(types);
+ self.push_line(")\n");
} else {
- self.push_line(&format!("task.spawn({callback}, value)"))
+ self.push_indent();
+ self.push(&format!("task.spawn({callback}, "));
+ self.push_queued_value(types);
+ self.push(")\n");
}
self.dedent();
@@ -638,8 +701,8 @@ impl<'src> ClientOutput<'src> {
self.push_indent();
self.push(&format!("{on} = function({callback}: ("));
- if let Some(data) = &ev.data {
- self.push_ty(data);
+ if let Some(types) = &ev.data {
+ self.push_value_parameters(types);
}
self.push(") -> ())\n");
@@ -647,14 +710,20 @@ impl<'src> ClientOutput<'src> {
self.push_line(&format!("table.insert(events[{id}], {callback})"));
- if ev.data.is_some() {
+ if let Some(types) = &ev.data {
self.push_line(&format!("for _, value in event_queue[{id}] do"));
self.indent();
if ev.call == EvCall::ManySync {
- self.push_line(&format!("{callback}(value)"))
+ self.push_indent();
+ self.push(&format!("{callback}("));
+ self.push_queued_value(types);
+ self.push_line(")\n");
} else {
- self.push_line(&format!("task.spawn({callback}, value)"))
+ self.push_indent();
+ self.push(&format!("task.spawn({callback}, "));
+ self.push_queued_value(types);
+ self.push(")\n");
}
self.dedent();
@@ -724,23 +793,35 @@ impl<'src> ClientOutput<'src> {
self.push_indent();
self.push(&format!("{call} = function("));
- if let Some(ty) = &fndecl.args {
- self.push(&format!("{value}: "));
- self.push_ty(ty);
+ if let Some(types) = &fndecl.args {
+ self.push_value_parameters(types);
}
self.push(")");
- if let Some(ty) = &fndecl.rets {
+ if let Some(types) = &fndecl.rets {
match self.config.yield_type {
YieldType::Future => {
- self.push(": Future.Future<");
- self.push_ty(ty);
- self.push(">");
+ self.push(": Future.Future<(");
+
+ for (i, ty) in types.iter().enumerate() {
+ if i > 0 {
+ self.push(", ");
+ }
+ self.push_ty(ty);
+ }
+
+ self.push(")>");
}
YieldType::Yield => {
- self.push(": ");
- self.push_ty(ty);
+ self.push(": (");
+ for (i, ty) in types.iter().enumerate() {
+ if i > 0 {
+ self.push(", ");
+ }
+ self.push_ty(ty);
+ }
+ self.push(")");
}
_ => (),
}
@@ -774,10 +855,10 @@ impl<'src> ClientOutput<'src> {
match self.config.yield_type {
YieldType::Yield => {
self.push_line(&format!("event_queue[{id}][function_call_id] = coroutine.running()",));
- self.push_line("local async_value = coroutine.yield()");
+ self.push_line("return coroutine.yield()");
}
YieldType::Future => {
- self.push_line("local async_value = Future.new(function()");
+ self.push_line("return Future.new(function()");
self.indent();
self.push_line(&format!("event_queue[{id}][function_call_id] = coroutine.running()",));
@@ -787,7 +868,7 @@ impl<'src> ClientOutput<'src> {
self.push_line("end)");
}
YieldType::Promise => {
- self.push_line("local async_value = Promise.new(function(resolve)");
+ self.push_line("return Promise.new(function(resolve)");
self.indent();
self.push_line(&format!("event_queue[{id}][function_call_id] = resolve"));
@@ -797,8 +878,6 @@ impl<'src> ClientOutput<'src> {
}
}
- self.push_line("return async_value");
-
self.dedent();
self.push_line("end,");
diff --git a/zap/src/output/luau/server.rs b/zap/src/output/luau/server.rs
index 11754a78..3e0557e5 100644
--- a/zap/src/output/luau/server.rs
+++ b/zap/src/output/luau/server.rs
@@ -1,5 +1,5 @@
use crate::{
- config::{Config, EvCall, EvDecl, EvSource, EvType, FnCall, FnDecl, TyDecl},
+ config::{Config, EvCall, EvDecl, EvSource, EvType, FnCall, FnDecl, Ty, TyDecl},
irgen::{des, ser},
};
@@ -115,14 +115,14 @@ impl<'a> ServerOutput<'a> {
self.push_line(&format!("function types.write_{name}(value: {name})"));
self.indent();
- self.push_stmts(&ser::gen(ty, "value", self.config.write_checks));
+ self.push_stmts(&ser::gen(&[ty.clone()], "value", self.config.write_checks));
self.dedent();
self.push_line("end");
self.push_line(&format!("function types.read_{name}()"));
self.indent();
self.push_line("local value;");
- self.push_stmts(&des::gen(ty, "value", true));
+ self.push_stmts(&des::gen(&[ty.clone()], "value", true));
self.push_line("return value");
self.dedent();
self.push_line("end");
@@ -186,6 +186,23 @@ impl<'a> ServerOutput<'a> {
));
}
+ fn get_values(&self, data: &Option>) -> String {
+ if let Some(types) = data {
+ (1..=types.len())
+ .map(|i| {
+ if i == 1 {
+ "value".to_string()
+ } else {
+ format!("value{}", i)
+ }
+ })
+ .collect::>()
+ .join(", ")
+ } else {
+ "value".to_string()
+ }
+ }
+
fn push_reliable_callback(&mut self, first: bool, ev: &EvDecl) {
let id = ev.id;
@@ -205,7 +222,9 @@ impl<'a> ServerOutput<'a> {
self.indent();
- self.push_line("local value");
+ let values = self.get_values(&ev.data);
+
+ self.push_line(&format!("local {values}"));
if let Some(data) = &ev.data {
self.push_stmts(&des::gen(data, "value", true));
@@ -220,10 +239,10 @@ impl<'a> ServerOutput<'a> {
self.indent();
match ev.call {
- EvCall::SingleSync => self.push_line(&format!("events[{id}](player, value)")),
- EvCall::SingleAsync => self.push_line(&format!("task.spawn(events[{id}], player, value)")),
- EvCall::ManySync => self.push_line("cb(player, value)"),
- EvCall::ManyAsync => self.push_line("task.spawn(cb, player, value)"),
+ EvCall::SingleSync => self.push_line(&format!("events[{id}](player, {values})")),
+ EvCall::SingleAsync => self.push_line(&format!("task.spawn(events[{id}], player, {values})")),
+ EvCall::ManySync => self.push_line(&format!("cb(player, {values})")),
+ EvCall::ManyAsync => self.push_line(&format!("task.spawn(cb, player, {values})")),
}
self.dedent();
@@ -249,7 +268,10 @@ impl<'a> ServerOutput<'a> {
self.indent();
self.push_line("local call_id = buffer.readu8(buff, read(1))");
- self.push_line("local value");
+
+ let values = self.get_values(&fndecl.args);
+
+ self.push_line(&format!("local {values}"));
if let Some(data) = &fndecl.args {
self.push_stmts(&des::gen(data, "value", true));
@@ -259,12 +281,36 @@ impl<'a> ServerOutput<'a> {
self.indent();
+ let rets = if let Some(types) = &fndecl.args {
+ (1..=types.len())
+ .map(|i| {
+ if i > 1 {
+ format!("rets{}", i)
+ } else {
+ "rets".to_string()
+ }
+ })
+ .collect::>()
+ .join(", ")
+ } else {
+ "rets".to_string()
+ };
+
if fndecl.call == FnCall::Async {
+ let args = if let Some(types) = &fndecl.args {
+ (1..=types.len())
+ .map(|i| format!("value_{}", i))
+ .collect::>()
+ .join(", ")
+ } else {
+ "value_1".to_string()
+ };
+
// Avoid using upvalues as an optimization.
- self.push_line("task.spawn(function(player_2, call_id_2, value_2)");
+ self.push_line(&format!("task.spawn(function(player_2, call_id_2, {args})"));
self.indent();
- self.push_line(&format!("local rets = events[{id}](player_2, value_2)"));
+ self.push_line(&format!("local {rets} = events[{id}](player_2, {args})"));
self.push_line("load_player(player_2)");
self.push_write_event_id(fndecl.id);
@@ -279,9 +325,9 @@ impl<'a> ServerOutput<'a> {
self.push_line("player_map[player_2] = save()");
self.dedent();
- self.push_line("end, player, call_id, value)");
+ self.push_line(&format!("end, player, call_id, {values})"));
} else {
- self.push_line(&format!("local rets = events[{id}](player, value)"));
+ self.push_line(&format!("local {rets} = events[{id}](player, {values})"));
self.push_line("load_player(player)");
self.push_write_event_id(fndecl.id);
@@ -371,7 +417,9 @@ impl<'a> ServerOutput<'a> {
self.indent();
- self.push_line("local value");
+ let values = self.get_values(&ev.data);
+
+ self.push_line(&format!("local {}", values));
if let Some(data) = &ev.data {
self.push_stmts(&des::gen(data, "value", true));
@@ -386,10 +434,10 @@ impl<'a> ServerOutput<'a> {
self.indent();
match ev.call {
- EvCall::SingleSync => self.push_line(&format!("events[{id}](player, value)")),
- EvCall::SingleAsync => self.push_line(&format!("task.spawn(events[{id}], player, value)")),
- EvCall::ManySync => self.push_line("cb(player, value)"),
- EvCall::ManyAsync => self.push_line("task.spawn(cb, player, value)"),
+ EvCall::SingleSync => self.push_line(&format!("events[{id}](player, {values})")),
+ EvCall::SingleAsync => self.push_line(&format!("task.spawn(events[{id}], player, {values})")),
+ EvCall::ManySync => self.push_line(&format!("cb(player, {values})")),
+ EvCall::ManyAsync => self.push_line(&format!("task.spawn(cb, player, {values})")),
}
self.dedent();
@@ -447,8 +495,25 @@ impl<'a> ServerOutput<'a> {
));
}
+ fn push_value_parameters(&mut self, types: &[Ty]) {
+ for (i, ty) in types.iter().enumerate() {
+ let value = format!(
+ "{}{}",
+ self.config.casing.with("Value", "value", "value"),
+ if i == 0 { "".to_string() } else { (i + 1).to_string() }
+ );
+
+ if i > 0 {
+ self.push(", ");
+ }
+
+ self.push(&format!("{value}: "));
+ self.push_ty(ty);
+ }
+ }
+
fn push_return_fire(&mut self, ev: &EvDecl) {
- let ty = &ev.data;
+ let types = &ev.data;
let fire = self.config.casing.with("Fire", "fire", "fire");
let player = self.config.casing.with("Player", "player", "player");
@@ -457,9 +522,9 @@ impl<'a> ServerOutput<'a> {
self.push_indent();
self.push(&format!("{fire} = function({player}: Player"));
- if let Some(ty) = ty {
- self.push(&format!(", {value}: "));
- self.push_ty(ty);
+ if let Some(types) = types {
+ self.push(", ");
+ self.push_value_parameters(types);
}
self.push(")\n");
@@ -472,8 +537,8 @@ impl<'a> ServerOutput<'a> {
self.push_write_event_id(ev.id);
- if let Some(ty) = ty {
- self.push_stmts(&ser::gen(ty, value, self.config.write_checks));
+ if let Some(types) = types {
+ self.push_stmts(&ser::gen(types, value, self.config.write_checks));
}
match ev.evty {
@@ -490,7 +555,7 @@ impl<'a> ServerOutput<'a> {
}
fn push_return_fire_all(&mut self, ev: &EvDecl) {
- let ty = &ev.data;
+ let types = &ev.data;
let fire_all = self.config.casing.with("FireAll", "fireAll", "fire_all");
let value = self.config.casing.with("Value", "value", "value");
@@ -498,9 +563,8 @@ impl<'a> ServerOutput<'a> {
self.push_indent();
self.push(&format!("{fire_all} = function("));
- if let Some(ty) = ty {
- self.push(&format!("{value}: "));
- self.push_ty(ty);
+ if let Some(types) = types {
+ self.push_value_parameters(types);
}
self.push(")\n");
@@ -510,8 +574,8 @@ impl<'a> ServerOutput<'a> {
self.push_write_event_id(ev.id);
- if let Some(ty) = ty {
- self.push_stmts(&ser::gen(ty, value, self.config.write_checks));
+ if let Some(types) = types {
+ self.push_stmts(&ser::gen(types, value, self.config.write_checks));
}
match ev.evty {
@@ -540,7 +604,7 @@ impl<'a> ServerOutput<'a> {
}
fn push_return_fire_except(&mut self, ev: &EvDecl) {
- let ty = &ev.data;
+ let types = &ev.data;
let fire_except = self.config.casing.with("FireExcept", "fireExcept", "fire_except");
let except = self.config.casing.with("Except", "except", "except");
@@ -549,9 +613,9 @@ impl<'a> ServerOutput<'a> {
self.push_indent();
self.push(&format!("{fire_except} = function({except}: Player"));
- if let Some(ty) = ty {
- self.push(&format!(", {value}: "));
- self.push_ty(ty);
+ if let Some(types) = types {
+ self.push(", ");
+ self.push_value_parameters(types);
}
self.push(")\n");
@@ -561,8 +625,8 @@ impl<'a> ServerOutput<'a> {
self.push_write_event_id(ev.id);
- if let Some(ty) = ty {
- self.push_stmts(&ser::gen(ty, value, self.config.write_checks));
+ if let Some(types) = types {
+ self.push_stmts(&ser::gen(types, value, self.config.write_checks));
}
match ev.evty {
@@ -603,7 +667,7 @@ impl<'a> ServerOutput<'a> {
}
fn push_return_fire_list(&mut self, ev: &EvDecl) {
- let ty = &ev.data;
+ let types = &ev.data;
let fire_list = self.config.casing.with("FireList", "fireList", "fire_list");
let list = self.config.casing.with("List", "list", "list");
@@ -612,9 +676,9 @@ impl<'a> ServerOutput<'a> {
self.push_indent();
self.push(&format!("{fire_list} = function({list}: {{ Player }}"));
- if let Some(ty) = ty {
- self.push(&format!(", {value}: "));
- self.push_ty(ty);
+ if let Some(types) = types {
+ self.push(", ");
+ self.push_value_parameters(types);
}
self.push(")\n");
@@ -624,7 +688,7 @@ impl<'a> ServerOutput<'a> {
self.push_write_event_id(ev.id);
- if let Some(ty) = ty {
+ if let Some(ty) = types {
self.push_stmts(&ser::gen(ty, value, self.config.write_checks));
}
@@ -658,7 +722,7 @@ impl<'a> ServerOutput<'a> {
}
fn push_return_fire_set(&mut self, ev: &EvDecl) {
- let ty = &ev.data;
+ let types = &ev.data;
let fire_set = self.config.casing.with("FireSet", "fireSet", "fire_set");
let set = self.config.casing.with("Set", "set", "set");
@@ -667,9 +731,9 @@ impl<'a> ServerOutput<'a> {
self.push_indent();
self.push(&format!("{fire_set} = function({set}: {{ [Player]: true }}"));
- if let Some(ty) = ty {
- self.push(&format!(", {value}: "));
- self.push_ty(ty);
+ if let Some(types) = types {
+ self.push(", ");
+ self.push_value_parameters(types);
}
self.push(")\n");
@@ -679,7 +743,7 @@ impl<'a> ServerOutput<'a> {
self.push_write_event_id(ev.id);
- if let Some(ty) = ty {
+ if let Some(ty) = types {
self.push_stmts(&ser::gen(ty, value, self.config.write_checks));
}
@@ -742,13 +806,14 @@ impl<'a> ServerOutput<'a> {
let set_callback = self.config.casing.with("SetCallback", "setCallback", "set_callback");
let callback = self.config.casing.with("Callback", "callback", "callback");
+ let player = self.config.casing.with("Player", "player", "player");
self.push_indent();
- self.push(&format!("{set_callback} = function({callback}: (Player"));
+ self.push(&format!("{set_callback} = function({callback}: ({player}: Player"));
- if let Some(ty) = &ev.data {
+ if let Some(types) = &ev.data {
self.push(", ");
- self.push_ty(ty);
+ self.push_value_parameters(types);
}
self.push(") -> ()): () -> ()\n");
@@ -773,13 +838,14 @@ impl<'a> ServerOutput<'a> {
let on = self.config.casing.with("On", "on", "on");
let callback = self.config.casing.with("Callback", "callback", "callback");
+ let player = self.config.casing.with("Player", "player", "player");
self.push_indent();
- self.push(&format!("{on} = function({callback}: (Player"));
+ self.push(&format!("{on} = function({callback}: ({player}: Player"));
- if let Some(ty) = &ev.data {
+ if let Some(types) = &ev.data {
self.push(", ");
- self.push_ty(ty);
+ self.push_value_parameters(types);
}
self.push(") -> ()): () -> ()\n");
@@ -806,19 +872,25 @@ impl<'a> ServerOutput<'a> {
let set_callback = self.config.casing.with("SetCallback", "setCallback", "set_callback");
let callback = self.config.casing.with("Callback", "callback", "callback");
+ let player = self.config.casing.with("Player", "player", "player");
self.push_indent();
- self.push(&format!("{set_callback} = function({callback}: (Player"));
+ self.push(&format!("{set_callback} = function({callback}: ({player}: Player"));
- if let Some(ty) = &fndecl.args {
+ if let Some(types) = &fndecl.args {
self.push(", ");
- self.push_ty(ty);
+ self.push_value_parameters(types);
}
self.push(") -> (");
- if let Some(ty) = &fndecl.rets {
- self.push_ty(ty);
+ if let Some(types) = &fndecl.rets {
+ for (i, ty) in types.iter().enumerate() {
+ if i > 0 {
+ self.push(", ");
+ }
+ self.push_ty(ty);
+ }
}
self.push(")): () -> ()\n");
diff --git a/zap/src/output/tooling.rs b/zap/src/output/tooling.rs
index ebbf0a2b..2a228a3d 100644
--- a/zap/src/output/tooling.rs
+++ b/zap/src/output/tooling.rs
@@ -1,5 +1,5 @@
use crate::{
- config::{Config, EvDecl, FnDecl, TyDecl},
+ config::{Config, EvDecl, FnDecl, Ty, TyDecl},
irgen::{des, Stmt},
Output,
};
@@ -115,7 +115,7 @@ impl<'src> ToolingOutput<'src> {
self.push_line(&format!("function types.read_{name}()"));
self.indent();
self.push_line("local value;");
- self.push_stmts(&des::gen(ty, "value", true));
+ self.push_stmts(&des::gen(&[ty.clone()], "value", true));
self.push_line("return value");
self.dedent();
self.push_line("end");
@@ -129,6 +129,22 @@ impl<'src> ToolingOutput<'src> {
}
}
+ fn get_values(&self, data: &Option>) -> String {
+ if let Some(types) = data {
+ (1..=types.len())
+ .map(|i| {
+ if i == 1 {
+ "value".to_string()
+ } else {
+ format!("value{}", i)
+ }
+ })
+ .collect::>()
+ .join(", ")
+ } else {
+ "value".to_string()
+ }
+ }
fn push_event_callback(&mut self, first: bool, ev: &EvDecl) {
let id = ev.id;
@@ -148,7 +164,9 @@ impl<'src> ToolingOutput<'src> {
self.indent();
- self.push_line("local value");
+ let values = self.get_values(&ev.data);
+
+ self.push_line(&format!("local {values}"));
if let Some(data) = &ev.data {
self.push_stmts(&des::gen(data, "value", true));
@@ -169,7 +187,7 @@ impl<'src> ToolingOutput<'src> {
));
}
- self.push("value }");
+ self.push(&format!("{values} }}"));
self.push("\n");
self.dedent();
@@ -204,7 +222,9 @@ impl<'src> ToolingOutput<'src> {
self.push_line("if isServer then");
self.indent();
- self.push_line("local value");
+ let values = self.get_values(&fn_decl.args);
+
+ self.push_line(&format!("local {values}"));
if let Some(data) = &fn_decl.args {
self.push_stmts(&des::gen(data, "value", true));
@@ -222,7 +242,7 @@ impl<'src> ToolingOutput<'src> {
self.push(&format!("{{ {} = id, {} = call_id }}, ", event_id, call_id));
}
- self.push("value }");
+ self.push(&format!("{values} }}"));
self.push("\n");
self.dedent();
@@ -232,7 +252,7 @@ impl<'src> ToolingOutput<'src> {
self.push_line("else");
self.indent();
- self.push_line("local value");
+ self.push_line(&format!("local {values}"));
if let Some(data) = &fn_decl.rets {
self.push_stmts(&des::gen(data, "value", true));
@@ -250,7 +270,7 @@ impl<'src> ToolingOutput<'src> {
self.push(&format!("{{ {} = id, {} = call_id }}, ", event_id, call_id));
}
- self.push("value }");
+ self.push(&format!("{values} }}"));
self.push("\n");
self.dedent();
diff --git a/zap/src/output/typescript/client.rs b/zap/src/output/typescript/client.rs
index bc9a4ea9..2590655b 100644
--- a/zap/src/output/typescript/client.rs
+++ b/zap/src/output/typescript/client.rs
@@ -1,3 +1,4 @@
+use crate::config::Ty;
use crate::config::{Config, EvCall, EvSource, TyDecl, YieldType};
use super::ConfigProvider;
@@ -73,7 +74,6 @@ impl<'src> ClientOutput<'src> {
.filter(|(_, ev_decl)| ev_decl.from == EvSource::Client)
{
let fire = self.config.casing.with("Fire", "fire", "fire");
- let value = self.config.casing.with("Value", "value", "value");
self.push_line(&format!("export declare const {name}: {{", name = ev.name));
self.indent();
@@ -81,9 +81,8 @@ impl<'src> ClientOutput<'src> {
self.push_indent();
self.push(&format!("{fire}: ("));
- if let Some(data) = &ev.data {
- self.push(value);
- self.push_arg_ty(data);
+ if let Some(types) = &ev.data {
+ self.push_parameters(types);
}
self.push(") => void;\n");
@@ -108,7 +107,6 @@ impl<'src> ClientOutput<'src> {
EvCall::ManySync | EvCall::ManyAsync => self.config.casing.with("On", "on", "on"),
};
let callback = self.config.casing.with("Callback", "callback", "callback");
- let value = self.config.casing.with("Value", "value", "value");
self.push_line(&format!("export declare const {name}: {{", name = ev.name));
self.indent();
@@ -116,9 +114,8 @@ impl<'src> ClientOutput<'src> {
self.push_indent();
self.push(&format!("{set_callback}: ({callback}: ("));
- if let Some(data) = &ev.data {
- self.push(value);
- self.push_arg_ty(data);
+ if let Some(types) = &ev.data {
+ self.push_parameters(types);
}
self.push(") => void) => () => void;\n");
@@ -130,7 +127,6 @@ impl<'src> ClientOutput<'src> {
fn push_return_functions(&mut self) {
let call = self.config.casing.with("Call", "call", "call");
- let value = self.config.casing.with("Value", "value", "value");
for fndecl in self.config.fndecls.iter() {
self.push_line(&format!("export declare const {}: {{", fndecl.name));
@@ -139,9 +135,8 @@ impl<'src> ClientOutput<'src> {
self.push_indent();
self.push(&format!("{call}: ("));
- if let Some(data) = &fndecl.args {
- self.push(value);
- self.push_arg_ty(data);
+ if let Some(types) = &fndecl.args {
+ self.push_parameters(types);
}
self.push(") => ");
@@ -150,8 +145,22 @@ impl<'src> ClientOutput<'src> {
self.push("Promise<")
}
- if let Some(data) = &fndecl.rets {
- self.push_ty(data);
+ if let Some(types) = &fndecl.rets {
+ if types.len() > 1 {
+ self.push("LuaTuple<[");
+ }
+
+ for (i, ty) in types.iter().enumerate() {
+ if i > 0 {
+ self.push(", ");
+ }
+
+ self.push_ty(ty);
+ }
+
+ if types.len() > 1 {
+ self.push("]>");
+ }
} else {
self.push("void");
}
diff --git a/zap/src/output/typescript/mod.rs b/zap/src/output/typescript/mod.rs
index ca833977..71a29755 100644
--- a/zap/src/output/typescript/mod.rs
+++ b/zap/src/output/typescript/mod.rs
@@ -224,6 +224,22 @@ pub trait Output: ConfigProvider {
}
}
+ fn push_parameters(&mut self, types: &[Ty]) {
+ let value = self.get_config().casing.with("Value", "value", "value");
+
+ for (i, ty) in types.iter().enumerate() {
+ if i > 0 {
+ self.push(", ");
+ }
+
+ self.push(&format!(
+ "{value}{}",
+ if i > 0 { (i + 1).to_string() } else { "".to_string() },
+ ));
+ self.push_arg_ty(ty);
+ }
+ }
+
fn push_file_header(&mut self, scope: &str) {
self.push_line(&format!(
"// {scope} generated by Zap v{} (https://github.com/red-blox/zap)",
diff --git a/zap/src/output/typescript/server.rs b/zap/src/output/typescript/server.rs
index cc0b6fb4..398ff719 100644
--- a/zap/src/output/typescript/server.rs
+++ b/zap/src/output/typescript/server.rs
@@ -1,3 +1,4 @@
+use crate::config::Ty;
use crate::config::{Config, EvCall, EvDecl, EvSource, TyDecl};
use super::ConfigProvider;
@@ -67,14 +68,13 @@ impl<'a> ServerOutput<'a> {
fn push_return_fire(&mut self, ev: &EvDecl) {
let fire = self.config.casing.with("Fire", "fire", "fire");
let player = self.config.casing.with("Player", "player", "player");
- let value = self.config.casing.with("Value", "value", "value");
self.push_indent();
self.push(&format!("{fire}: ({player}: Player"));
- if let Some(data) = &ev.data {
- self.push(&format!(", {value}"));
- self.push_arg_ty(data);
+ if let Some(types) = &ev.data {
+ self.push(", ");
+ self.push_parameters(types);
}
self.push(") => void;\n");
@@ -82,14 +82,12 @@ impl<'a> ServerOutput<'a> {
fn push_return_fire_all(&mut self, ev: &EvDecl) {
let fire_all = self.config.casing.with("FireAll", "fireAll", "fire_all");
- let value = self.config.casing.with("Value", "value", "value");
self.push_indent();
self.push(&format!("{fire_all}: ("));
- if let Some(data) = &ev.data {
- self.push(value);
- self.push_arg_ty(data);
+ if let Some(types) = &ev.data {
+ self.push_parameters(types);
}
self.push(") => void;\n");
@@ -98,14 +96,13 @@ impl<'a> ServerOutput<'a> {
fn push_return_fire_except(&mut self, ev: &EvDecl) {
let fire_except = self.config.casing.with("FireExcept", "fireExcept", "fire_except");
let except = self.config.casing.with("Except", "except", "except");
- let value = self.config.casing.with("Value", "value", "value");
self.push_indent();
self.push(&format!("{fire_except}: ({except}: Player"));
- if let Some(data) = &ev.data {
- self.push(&format!(", {value}"));
- self.push_arg_ty(data);
+ if let Some(types) = &ev.data {
+ self.push(", ");
+ self.push_parameters(types);
}
self.push(") => void;\n");
@@ -114,14 +111,13 @@ impl<'a> ServerOutput<'a> {
fn push_return_fire_list(&mut self, ev: &EvDecl) {
let fire_list = self.config.casing.with("FireList", "fireList", "fire_list");
let list = self.config.casing.with("List", "list", "list");
- let value = self.config.casing.with("Value", "value", "value");
self.push_indent();
self.push(&format!("{fire_list}: ({list}: Player[]"));
- if let Some(data) = &ev.data {
- self.push(&format!(", {value}"));
- self.push_arg_ty(data);
+ if let Some(types) = &ev.data {
+ self.push(", ");
+ self.push_parameters(types);
}
self.push(") => void;\n");
@@ -130,14 +126,13 @@ impl<'a> ServerOutput<'a> {
fn push_return_fire_set(&mut self, ev: &EvDecl) {
let fire_set = self.config.casing.with("FireSet", "fireSet", "fire_set");
let set = self.config.casing.with("Set", "set", "set");
- let value = self.config.casing.with("Value", "value", "value");
self.push_indent();
self.push(&format!("{fire_set}: ({set}: Set"));
- if let Some(data) = &ev.data {
- self.push(&format!(", {value}"));
- self.push_arg_ty(data);
+ if let Some(types) = &ev.data {
+ self.push(", ");
+ self.push_parameters(types);
}
self.push(") => void\n");
@@ -188,14 +183,13 @@ impl<'a> ServerOutput<'a> {
};
let callback = self.config.casing.with("Callback", "callback", "callback");
let player = self.config.casing.with("Player", "player", "player");
- let value = self.config.casing.with("Value", "value", "value");
self.push_indent();
self.push(&format!("{set_callback}: ({callback}: ({player}: Player"));
- if let Some(data) = &ev.data {
- self.push(&format!(", {value}"));
- self.push_arg_ty(data);
+ if let Some(types) = &ev.data {
+ self.push(", ");
+ self.push_parameters(types);
}
self.push(") => void) => () => void;\n");
@@ -213,20 +207,33 @@ impl<'a> ServerOutput<'a> {
let set_callback = self.config.casing.with("SetCallback", "setCallback", "set_callback");
let callback = self.config.casing.with("Callback", "callback", "callback");
let player = self.config.casing.with("Player", "player", "player");
- let value = self.config.casing.with("Value", "value", "value");
self.push_indent();
self.push(&format!("{set_callback}: ({callback}: ({player}: Player"));
- if let Some(data) = &fndecl.args {
- self.push(&format!(", {value}"));
- self.push_arg_ty(data);
+ if let Some(types) = &fndecl.args {
+ self.push(", ");
+ self.push_parameters(types);
}
self.push(") => ");
- if let Some(data) = &fndecl.rets {
- self.push_ty(data);
+ if let Some(types) = &fndecl.rets {
+ if types.len() > 1 {
+ self.push("LuaTuple<[");
+ }
+
+ for (i, ty) in types.iter().enumerate() {
+ if i > 0 {
+ self.push(", ");
+ }
+
+ self.push_ty(ty);
+ }
+
+ if types.len() > 1 {
+ self.push("]>");
+ }
} else {
self.push("void");
}
diff --git a/zap/src/parser/convert.rs b/zap/src/parser/convert.rs
index 54a139f6..25d9915f 100644
--- a/zap/src/parser/convert.rs
+++ b/zap/src/parser/convert.rs
@@ -319,10 +319,26 @@ impl<'src> Converter<'src> {
let from = evdecl.from;
let evty = evdecl.evty;
let call = evdecl.call;
- let data = evdecl.data.as_ref().map(|ty| self.ty(ty));
+ let data = evdecl
+ .data
+ .as_ref()
+ .map(|types| types.iter().map(|ty| self.ty(ty)).collect::>());
if data.is_some() && evty == EvType::Unreliable {
- let (min, max) = data.as_ref().unwrap().size(tydecls, &mut HashSet::new());
+ let mut min = 0;
+ let mut max = Some(0);
+
+ for ty in data.as_ref().unwrap() {
+ let (ty_min, ty_max) = ty.size(tydecls, &mut HashSet::new());
+
+ min += ty_min;
+
+ if let (Some(ty_max), Some(max)) = (ty_max, max.as_mut()) {
+ *max += ty_max;
+ } else {
+ max = None;
+ }
+ }
if min > self.max_unreliable_size {
self.report(Report::AnalyzeOversizeUnreliable {
@@ -353,8 +369,14 @@ impl<'src> Converter<'src> {
fn fndecl(&mut self, fndecl: &SyntaxFnDecl<'src>, id: usize) -> FnDecl<'src> {
let name = fndecl.name.name;
let call = fndecl.call;
- let args = fndecl.args.as_ref().map(|ty| self.ty(ty));
- let rets = fndecl.rets.as_ref().map(|ty| self.ty(ty));
+ let args = fndecl
+ .args
+ .as_ref()
+ .map(|types| types.iter().map(|ty| self.ty(ty)).collect::>());
+ let rets = fndecl
+ .rets
+ .as_ref()
+ .map(|types| types.iter().map(|ty| self.ty(ty)).collect::>());
FnDecl {
name,
diff --git a/zap/src/parser/grammar.lalrpop b/zap/src/parser/grammar.lalrpop
index e98db5c2..dee0fca0 100644
--- a/zap/src/parser/grammar.lalrpop
+++ b/zap/src/parser/grammar.lalrpop
@@ -43,8 +43,8 @@ Decl: SyntaxDecl<'input> = {
FnDecl: SyntaxFnDecl<'input> = {
"funct" "=" "{"
"call" ":"
- )?>
- )?>
+ )?>
+ )?>
","?
"}" ";"? => SyntaxFnDecl { start, name, call, args, rets, end },
}
@@ -58,8 +58,8 @@ EvDecl: SyntaxEvDecl<'input> = {
"event" "=" "{"
"from" ":"
"," "type" ":"
- "," "call" ":"
- )?>
+ "," "call" ":"
+ )?>
","?
"}" ";"? => SyntaxEvDecl { start, name, from, evty, call, data, end },
}
@@ -116,6 +116,11 @@ TyKind: SyntaxTyKind<'input> = {
"Instance" ")")?> => SyntaxTyKind::Instance(c),
}
+TyList: Vec> = {
+ => vec![ty],
+ "(" > ")" => tys,
+}
+
Enum: SyntaxEnum<'input> = {
=> SyntaxEnum { start, kind, end },
}
diff --git a/zap/src/parser/syntax_tree.rs b/zap/src/parser/syntax_tree.rs
index 08dcce24..9acdd38c 100644
--- a/zap/src/parser/syntax_tree.rs
+++ b/zap/src/parser/syntax_tree.rs
@@ -78,8 +78,8 @@ pub struct SyntaxFnDecl<'src> {
pub start: usize,
pub name: SyntaxIdentifier<'src>,
pub call: FnCall,
- pub args: Option>,
- pub rets: Option>,
+ pub args: Option>>,
+ pub rets: Option>>,
pub end: usize,
}
@@ -96,7 +96,7 @@ pub struct SyntaxEvDecl<'src> {
pub from: EvSource,
pub evty: EvType,
pub call: EvCall,
- pub data: Option>,
+ pub data: Option>>,
pub end: usize,
}
@@ -133,6 +133,12 @@ impl<'src> Spanned for SyntaxTy<'src> {
}
}
+impl<'src> Spanned for Vec> {
+ fn span(&self) -> Span {
+ self.first().unwrap().start..self.last().unwrap().end
+ }
+}
+
#[derive(Debug, Clone, PartialEq)]
pub enum SyntaxTyKind<'src> {
Num(NumTy, Option>),