diff --git a/docs/config/events.md b/docs/config/events.md
index e63e9bf1..c35f9bac 100644
--- a/docs/config/events.md
+++ b/docs/config/events.md
@@ -3,17 +3,21 @@ const example = `event MyEvent = {
from: Server,
type: Reliable,
call: ManyAsync,
- data: struct {
- foo: string,
- bar: u8,
- },
+ data: (Foo: boolean, Bar: u32, Baz: string)
}`
-const dataExample = `event MyEvent = {
+const dataExample = `event OneUnnamedParameter = {
from: Server,
type: Reliable,
call: ManyAsync,
- data: (boolean, u32, string)
+ data: boolean
+}
+
+event TwoUnnamedParameters = {
+ from: Server,
+ type: Reliable,
+ call: ManyAsync,
+ data: (boolean, u32)
}`
@@ -65,6 +69,6 @@ Use synchronous events with extreme caution.
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:
+- Parameter names and parentheses are optional to preserve backwards compatibility. If parantheses are excluded, the event can only have one unnamed parameter.
diff --git a/docs/config/functions.md b/docs/config/functions.md
index 1b9132c5..1d73b917 100644
--- a/docs/config/functions.md
+++ b/docs/config/functions.md
@@ -1,17 +1,27 @@
@@ -48,15 +58,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:
+- Parameter names and parentheses are optional to preserve backwards compatibility. If parantheses are excluded, the function can only have one unnamed parameter.
-
+
### `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.
+- Unlike `args`, `rets` cannot be named.
- The function can return multiple values by separating each type with a comma and wrapping them all in parentheses:
-
+
diff --git a/docs/intro/getting-started.md b/docs/intro/getting-started.md
index d92a2e55..e7170a70 100644
--- a/docs/intro/getting-started.md
+++ b/docs/intro/getting-started.md
@@ -7,25 +7,19 @@ event MyEvent = {
from: Server,
type: Reliable,
call: ManyAsync,
- data: struct {
- foo: u32,
- bar: string,
- },
+ data: (Foo: u32, Bar: string),
}`
const apiExample = `-- Server
local Zap = require(path.to.server.output)
-Zap.MyEvent.FireAll({
- foo = 123,
- bar = "hello world",
-})
+Zap.MyEvent.FireAll(123, "hello world")
-- Client
local Zap = require(path.to.client.output)
-Zap.MyEvent.On(function(data)
- print(data.foo, data.bar)
+Zap.MyEvent.On(function(Foo, Bar)
+ print(Foo, Bar)
end)`
diff --git a/docs/usage/events.md b/docs/usage/events.md
index 79f3f481..8dd5580b 100644
--- a/docs/usage/events.md
+++ b/docs/usage/events.md
@@ -3,17 +3,17 @@ const configFile = `event MyEvent = {
from: Server,
type: Reliable,
call: ManyAsync,
- data: struct {
+ data: (Options: struct {
foo: string,
bar: u8,
- },
+ }),
}
event AnotherEvent = {
from: Client,
type: Reliable,
call: SingleAsync,
- data: (boolean, u8)
+ data: (Foo: boolean, Bar: u8)
}`
@@ -48,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, Bool, Number)
+Zap.AnotherEvent.SetCallback(function(Player, Foo, Bar)
-- Do something with the player and data
end)
```
@@ -58,7 +58,7 @@ If your event's [call field](../config/events.md#call) is `ManyAsync` or `ManySy
```lua
local Zap = require(Path.To.Zap)
-local Disconnect = Zap.MyEvent.On(function(Data)
+local Disconnect = Zap.MyEvent.On(function(Options)
-- Do something with the data
end)
diff --git a/zap/src/config.rs b/zap/src/config.rs
index b88383fa..c79b2f35 100644
--- a/zap/src/config.rs
+++ b/zap/src/config.rs
@@ -76,7 +76,7 @@ impl std::fmt::Display for YieldType {
pub struct FnDecl<'src> {
pub name: &'src str,
pub call: FnCall,
- pub args: Option>>,
+ pub args: Vec>,
pub rets: Option>>,
pub id: usize,
}
@@ -93,10 +93,16 @@ pub struct EvDecl<'src> {
pub from: EvSource,
pub evty: EvType,
pub call: EvCall,
- pub data: Option>>,
+ pub data: Vec>,
pub id: usize,
}
+#[derive(Debug, Clone)]
+pub struct Parameter<'src> {
+ pub name: Option<&'src str>,
+ pub ty: Ty<'src>,
+}
+
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum EvSource {
Server,
diff --git a/zap/src/irgen/des.rs b/zap/src/irgen/des.rs
index 860ccb74..189487a1 100644
--- a/zap/src/irgen/des.rs
+++ b/zap/src/irgen/des.rs
@@ -14,18 +14,12 @@ impl Gen for Des {
self.buf.push(stmt);
}
- 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);
+ fn gen<'a, I>(mut self, names: &[String], types: I) -> Vec
+ where
+ I: Iterator- >,
+ {
+ for (ty, name) in types.zip(names) {
+ self.push_ty(ty, Var::Name(name.to_string()));
}
self.buf
@@ -431,11 +425,14 @@ impl Des {
}
}
-pub fn gen(types: &[Ty], var: &str, checks: bool) -> Vec {
+pub fn gen<'a, I>(types: I, names: &[String], checks: bool) -> Vec
+where
+ I: IntoIterator
- >,
+{
Des {
checks,
buf: vec![],
var_occurrences: HashMap::new(),
}
- .gen(var.into(), types)
+ .gen(names, types.into_iter())
}
diff --git a/zap/src/irgen/mod.rs b/zap/src/irgen/mod.rs
index 88c16014..03786021 100644
--- a/zap/src/irgen/mod.rs
+++ b/zap/src/irgen/mod.rs
@@ -9,7 +9,9 @@ pub mod ser;
pub trait Gen {
fn push_stmt(&mut self, stmt: Stmt);
- fn gen(self, var: Var, types: &[Ty]) -> Vec;
+ fn gen<'a, I>(self, names: &[String], types: I) -> Vec
+ where
+ I: Iterator
- >;
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 5fcadaf0..dda6d70f 100644
--- a/zap/src/irgen/ser.rs
+++ b/zap/src/irgen/ser.rs
@@ -14,18 +14,12 @@ impl Gen for Ser {
self.buf.push(stmt);
}
- 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);
+ fn gen<'a, I>(mut self, names: &[String], types: I) -> Vec
+ where
+ I: Iterator
- >,
+ {
+ for (ty, name) in types.zip(names) {
+ self.push_ty(ty, Var::Name(name.to_string()));
}
self.buf
@@ -369,11 +363,14 @@ impl Ser {
}
}
-pub fn gen(types: &[Ty], var: &str, checks: bool) -> Vec {
+pub fn gen<'a, I>(types: I, names: &[String], checks: bool) -> Vec
+where
+ I: IntoIterator
- >,
+{
Ser {
checks,
buf: vec![],
var_occurrences: HashMap::new(),
}
- .gen(var.into(), types)
+ .gen(names, types.into_iter())
}
diff --git a/zap/src/output/luau/client.rs b/zap/src/output/luau/client.rs
index 0e89e6ae..3a9f10af 100644
--- a/zap/src/output/luau/client.rs
+++ b/zap/src/output/luau/client.rs
@@ -1,6 +1,7 @@
use crate::{
- config::{Config, EvCall, EvDecl, EvSource, EvType, FnDecl, Ty, TyDecl, YieldType},
+ config::{Config, EvCall, EvDecl, EvSource, EvType, FnDecl, Parameter, TyDecl, YieldType},
irgen::{des, ser},
+ output::{get_named_values, get_unnamed_values},
};
use super::Output;
@@ -103,14 +104,18 @@ impl<'src> ClientOutput<'src> {
self.push_line(&format!("function types.write_{name}(value: {name})"));
self.indent();
- self.push_stmts(&ser::gen(&[ty.clone()], "value", self.config.write_checks));
+ self.push_stmts(&ser::gen(
+ &[ty.clone()],
+ &["value".to_string()],
+ 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.clone()], "value", false));
+ self.push_stmts(&des::gen(&[ty.clone()], &["value".to_string()], false));
self.push_line("return value");
self.dedent();
self.push_line("end");
@@ -174,9 +179,9 @@ impl<'src> ClientOutput<'src> {
));
}
- fn get_values(&self, data: &Option>) -> String {
- if let Some(types) = data {
- (1..=types.len())
+ fn get_values(&self, count: usize) -> String {
+ if count > 0 {
+ (1..=count)
.map(|i| {
if i == 1 {
"value".to_string()
@@ -210,12 +215,16 @@ impl<'src> ClientOutput<'src> {
self.indent();
- let values = self.get_values(&ev.data);
+ let values = self.get_values(ev.data.len());
self.push_line(&format!("local {values}"));
- if let Some(data) = &ev.data {
- self.push_stmts(&des::gen(data, "value", true));
+ if !ev.data.is_empty() {
+ self.push_stmts(&des::gen(
+ ev.data.iter().map(|parameter| ¶meter.ty),
+ &get_unnamed_values("value", ev.data.len()),
+ true,
+ ));
}
if ev.call == EvCall::SingleSync || ev.call == EvCall::SingleAsync {
@@ -247,8 +256,8 @@ impl<'src> ClientOutput<'src> {
self.push_line("else");
self.indent();
- if let Some(types) = &ev.data {
- if types.len() > 1 {
+ if !ev.data.is_empty() {
+ if ev.data.len() > 1 {
self.push_line(&format!("table.insert(event_queue[{id}], {{ {values} }})"));
} else {
self.push_line(&format!("table.insert(event_queue[{id}], value)"));
@@ -265,7 +274,7 @@ impl<'src> ClientOutput<'src> {
self.push("warn(`[ZAP] {");
- if ev.data.is_some() {
+ if !ev.data.is_empty() {
self.push("#")
}
@@ -304,12 +313,12 @@ impl<'src> ClientOutput<'src> {
self.push_line("local call_id = buffer.readu8(incoming_buff, read(1))");
- let values = self.get_values(&fndecl.rets);
+ let values = self.get_values(fndecl.rets.as_ref().map_or(0, |x| x.len()));
self.push_line(&format!("local {values}"));
if let Some(data) = &fndecl.rets {
- self.push_stmts(&des::gen(data, "value", true));
+ self.push_stmts(&des::gen(data, &get_unnamed_values("value", data.len()), true));
}
match self.config.yield_type {
@@ -395,12 +404,16 @@ impl<'src> ClientOutput<'src> {
self.indent();
- let values = self.get_values(&ev.data);
+ let values = self.get_values(ev.data.len());
self.push_line(&format!("local {values}"));
- if let Some(data) = &ev.data {
- self.push_stmts(&des::gen(data, "value", self.config.write_checks));
+ if !ev.data.is_empty() {
+ self.push_stmts(&des::gen(
+ ev.data.iter().map(|parameter| ¶meter.ty),
+ &get_unnamed_values("value", ev.data.len()),
+ self.config.write_checks,
+ ));
}
if ev.call == EvCall::SingleSync || ev.call == EvCall::SingleAsync {
@@ -432,8 +445,8 @@ impl<'src> ClientOutput<'src> {
self.push_line("else");
self.indent();
- if let Some(types) = &ev.data {
- if types.len() > 1 {
+ if !ev.data.is_empty() {
+ if ev.data.len() > 1 {
self.push_line(&format!("table.insert(event_queue[{id}], {{ {values} }})"));
} else {
self.push_line(&format!("table.insert(event_queue[{id}], value)"));
@@ -450,7 +463,7 @@ impl<'src> ClientOutput<'src> {
self.push("warn(`[ZAP] {");
- if ev.data.is_some() {
+ if !ev.data.is_empty() {
self.push("#")
}
@@ -528,7 +541,7 @@ impl<'src> ClientOutput<'src> {
self.push_line(&format!("events[{id}] = {{}}"));
}
- if evdecl.data.is_some() {
+ if !evdecl.data.is_empty() {
self.push_line(&format!("event_queue[{id}] = {{}}"));
} else {
self.push_line(&format!("event_queue[{id}] = 0"));
@@ -548,20 +561,25 @@ 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() }
- );
-
+ fn push_value_parameters(&mut self, parameters: &[Parameter]) {
+ for (i, parameter) in parameters.iter().enumerate() {
if i > 0 {
self.push(", ");
}
- self.push(&format!("{value}: "));
- self.push_ty(ty);
+ if let Some(name) = parameter.name {
+ self.push(&format!("{name}: "));
+ } else {
+ let value = format!(
+ "{}{}",
+ self.config.casing.with("Value", "value", "value"),
+ if i == 0 { "".to_string() } else { (i + 1).to_string() }
+ );
+
+ self.push(&format!("{value}: "));
+ }
+
+ self.push_ty(¶meter.ty);
}
}
@@ -572,8 +590,8 @@ impl<'src> ClientOutput<'src> {
self.push_indent();
self.push(&format!("{fire} = function("));
- if let Some(types) = &ev.data {
- self.push_value_parameters(types);
+ if !ev.data.is_empty() {
+ self.push_value_parameters(&ev.data);
}
self.push(")\n");
@@ -586,8 +604,12 @@ impl<'src> ClientOutput<'src> {
self.push_write_event_id(ev.id);
- if let Some(data) = &ev.data {
- self.push_stmts(&ser::gen(data, value, self.config.write_checks));
+ if !ev.data.is_empty() {
+ self.push_stmts(&ser::gen(
+ ev.data.iter().map(|parameter| ¶meter.ty),
+ &get_named_values(value, &ev.data),
+ self.config.write_checks,
+ ));
}
if ev.evty == EvType::Unreliable {
@@ -618,8 +640,8 @@ impl<'src> ClientOutput<'src> {
}
}
- fn push_queued_value(&mut self, types: &[Ty]) {
- if types.len() > 1 {
+ fn push_queued_value(&mut self, parameters: &[Parameter]) {
+ if parameters.len() > 1 {
self.push("unpack(value)");
} else {
self.push("value");
@@ -635,8 +657,8 @@ impl<'src> ClientOutput<'src> {
self.push_indent();
self.push(&format!("{set_callback} = function({callback}: ("));
- if let Some(types) = &ev.data {
- self.push_value_parameters(types);
+ if !ev.data.is_empty() {
+ self.push_value_parameters(&ev.data);
}
self.push(") -> ()): () -> ()\n");
@@ -644,19 +666,19 @@ impl<'src> ClientOutput<'src> {
self.push_line(&format!("events[{id}] = {callback}"));
- if let Some(types) = &ev.data {
+ if !ev.data.is_empty() {
self.push_line(&format!("for _, value in event_queue[{id}] do"));
self.indent();
if ev.call == EvCall::SingleSync {
self.push_indent();
self.push(&format!("{callback}("));
- self.push_queued_value(types);
+ self.push_queued_value(&ev.data);
self.push_line(")\n");
} else {
self.push_indent();
self.push(&format!("task.spawn({callback}, "));
- self.push_queued_value(types);
+ self.push_queued_value(&ev.data);
self.push(")\n");
}
@@ -701,8 +723,8 @@ impl<'src> ClientOutput<'src> {
self.push_indent();
self.push(&format!("{on} = function({callback}: ("));
- if let Some(types) = &ev.data {
- self.push_value_parameters(types);
+ if !ev.data.is_empty() {
+ self.push_value_parameters(&ev.data);
}
self.push(") -> ())\n");
@@ -710,19 +732,19 @@ impl<'src> ClientOutput<'src> {
self.push_line(&format!("table.insert(events[{id}], {callback})"));
- if let Some(types) = &ev.data {
+ if !ev.data.is_empty() {
self.push_line(&format!("for _, value in event_queue[{id}] do"));
self.indent();
if ev.call == EvCall::ManySync {
self.push_indent();
self.push(&format!("{callback}("));
- self.push_queued_value(types);
+ self.push_queued_value(&ev.data);
self.push_line(")\n");
} else {
self.push_indent();
self.push(&format!("task.spawn({callback}, "));
- self.push_queued_value(types);
+ self.push_queued_value(&ev.data);
self.push(")\n");
}
@@ -793,8 +815,8 @@ impl<'src> ClientOutput<'src> {
self.push_indent();
self.push(&format!("{call} = function("));
- if let Some(types) = &fndecl.args {
- self.push_value_parameters(types);
+ if !fndecl.args.is_empty() {
+ self.push_value_parameters(&fndecl.args);
}
self.push(")");
@@ -848,8 +870,12 @@ impl<'src> ClientOutput<'src> {
self.push_line("alloc(1)");
self.push_line("buffer.writeu8(outgoing_buff, outgoing_apos, function_call_id)");
- if let Some(data) = &fndecl.args {
- self.push_stmts(&ser::gen(data, value, self.config.write_checks));
+ if !fndecl.args.is_empty() {
+ self.push_stmts(&ser::gen(
+ fndecl.args.iter().map(|parameter| ¶meter.ty),
+ &get_named_values(value, &fndecl.args),
+ self.config.write_checks,
+ ));
}
match self.config.yield_type {
diff --git a/zap/src/output/luau/server.rs b/zap/src/output/luau/server.rs
index 3e0557e5..5ea4fefd 100644
--- a/zap/src/output/luau/server.rs
+++ b/zap/src/output/luau/server.rs
@@ -1,6 +1,7 @@
use crate::{
- config::{Config, EvCall, EvDecl, EvSource, EvType, FnCall, FnDecl, Ty, TyDecl},
+ config::{Config, EvCall, EvDecl, EvSource, EvType, FnCall, FnDecl, Parameter, TyDecl},
irgen::{des, ser},
+ output::{get_named_values, get_unnamed_values},
};
use super::Output;
@@ -115,14 +116,18 @@ impl<'a> ServerOutput<'a> {
self.push_line(&format!("function types.write_{name}(value: {name})"));
self.indent();
- self.push_stmts(&ser::gen(&[ty.clone()], "value", self.config.write_checks));
+ self.push_stmts(&ser::gen(
+ &[ty.clone()],
+ &["value".to_string()],
+ 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.clone()], "value", true));
+ self.push_stmts(&des::gen(&[ty.clone()], &["value".to_string()], true));
self.push_line("return value");
self.dedent();
self.push_line("end");
@@ -186,9 +191,9 @@ impl<'a> ServerOutput<'a> {
));
}
- fn get_values(&self, data: &Option>) -> String {
- if let Some(types) = data {
- (1..=types.len())
+ fn get_values(&self, parameters: &[Parameter]) -> String {
+ if !parameters.is_empty() {
+ (1..=parameters.len())
.map(|i| {
if i == 1 {
"value".to_string()
@@ -226,8 +231,12 @@ impl<'a> ServerOutput<'a> {
self.push_line(&format!("local {values}"));
- if let Some(data) = &ev.data {
- self.push_stmts(&des::gen(data, "value", true));
+ if !ev.data.is_empty() {
+ self.push_stmts(&des::gen(
+ ev.data.iter().map(|parameter| ¶meter.ty),
+ &get_unnamed_values("value", ev.data.len()),
+ true,
+ ));
}
if ev.call == EvCall::SingleSync || ev.call == EvCall::SingleAsync {
@@ -273,16 +282,20 @@ impl<'a> ServerOutput<'a> {
self.push_line(&format!("local {values}"));
- if let Some(data) = &fndecl.args {
- self.push_stmts(&des::gen(data, "value", true));
+ if !fndecl.args.is_empty() {
+ self.push_stmts(&des::gen(
+ fndecl.args.iter().map(|parameter| ¶meter.ty),
+ &get_unnamed_values("value", fndecl.args.len()),
+ true,
+ ));
}
self.push_line(&format!("if events[{id}] then"));
self.indent();
- let rets = if let Some(types) = &fndecl.args {
- (1..=types.len())
+ let rets = if !fndecl.args.is_empty() {
+ (1..=fndecl.args.len())
.map(|i| {
if i > 1 {
format!("rets{}", i)
@@ -297,8 +310,8 @@ impl<'a> ServerOutput<'a> {
};
if fndecl.call == FnCall::Async {
- let args = if let Some(types) = &fndecl.args {
- (1..=types.len())
+ let args = if !fndecl.args.is_empty() {
+ (1..=fndecl.args.len())
.map(|i| format!("value_{}", i))
.collect::>()
.join(", ")
@@ -318,8 +331,12 @@ impl<'a> ServerOutput<'a> {
self.push_line("alloc(1)");
self.push_line("buffer.writeu8(outgoing_buff, outgoing_apos, call_id_2)");
- if let Some(ty) = &fndecl.rets {
- self.push_stmts(&ser::gen(ty, "rets", self.config.write_checks));
+ if let Some(types) = &fndecl.rets {
+ self.push_stmts(&ser::gen(
+ types,
+ &get_unnamed_values("rets", types.len()),
+ self.config.write_checks,
+ ));
}
self.push_line("player_map[player_2] = save()");
@@ -335,8 +352,12 @@ impl<'a> ServerOutput<'a> {
self.push_line("alloc(1)");
self.push_line("buffer.writeu8(outgoing_buff, outgoing_apos, call_id)");
- if let Some(ty) = &fndecl.rets {
- self.push_stmts(&ser::gen(ty, "rets", self.config.write_checks));
+ if let Some(types) = &fndecl.rets {
+ self.push_stmts(&ser::gen(
+ types,
+ &get_unnamed_values("rets", types.len()),
+ self.config.write_checks,
+ ));
}
self.push_line("player_map[player] = save()");
@@ -421,8 +442,12 @@ impl<'a> ServerOutput<'a> {
self.push_line(&format!("local {}", values));
- if let Some(data) = &ev.data {
- self.push_stmts(&des::gen(data, "value", true));
+ if !ev.data.is_empty() {
+ self.push_stmts(&des::gen(
+ ev.data.iter().map(|parameter| ¶meter.ty),
+ &get_unnamed_values("value", ev.data.len()),
+ true,
+ ));
}
if ev.call == EvCall::SingleSync || ev.call == EvCall::SingleAsync {
@@ -495,25 +520,30 @@ 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() }
- );
-
+ fn push_value_parameters(&mut self, parameters: &[Parameter]) {
+ for (i, parameter) in parameters.iter().enumerate() {
if i > 0 {
self.push(", ");
}
- self.push(&format!("{value}: "));
- self.push_ty(ty);
+ if let Some(name) = parameter.name {
+ self.push(&format!("{name}: "));
+ } else {
+ let value = format!(
+ "{}{}",
+ self.config.casing.with("Value", "value", "value"),
+ if i == 0 { "".to_string() } else { (i + 1).to_string() }
+ );
+
+ self.push(&format!("{value}: "));
+ }
+
+ self.push_ty(¶meter.ty);
}
}
fn push_return_fire(&mut self, ev: &EvDecl) {
- let types = &ev.data;
+ let parameters = &ev.data;
let fire = self.config.casing.with("Fire", "fire", "fire");
let player = self.config.casing.with("Player", "player", "player");
@@ -522,9 +552,9 @@ impl<'a> ServerOutput<'a> {
self.push_indent();
self.push(&format!("{fire} = function({player}: Player"));
- if let Some(types) = types {
+ if !parameters.is_empty() {
self.push(", ");
- self.push_value_parameters(types);
+ self.push_value_parameters(parameters);
}
self.push(")\n");
@@ -537,8 +567,12 @@ impl<'a> ServerOutput<'a> {
self.push_write_event_id(ev.id);
- if let Some(types) = types {
- self.push_stmts(&ser::gen(types, value, self.config.write_checks));
+ if !parameters.is_empty() {
+ self.push_stmts(&ser::gen(
+ parameters.iter().map(|parameter| ¶meter.ty),
+ &get_named_values(value, parameters),
+ self.config.write_checks,
+ ));
}
match ev.evty {
@@ -555,7 +589,7 @@ impl<'a> ServerOutput<'a> {
}
fn push_return_fire_all(&mut self, ev: &EvDecl) {
- let types = &ev.data;
+ let parameters = &ev.data;
let fire_all = self.config.casing.with("FireAll", "fireAll", "fire_all");
let value = self.config.casing.with("Value", "value", "value");
@@ -563,8 +597,8 @@ impl<'a> ServerOutput<'a> {
self.push_indent();
self.push(&format!("{fire_all} = function("));
- if let Some(types) = types {
- self.push_value_parameters(types);
+ if !parameters.is_empty() {
+ self.push_value_parameters(parameters);
}
self.push(")\n");
@@ -574,8 +608,12 @@ impl<'a> ServerOutput<'a> {
self.push_write_event_id(ev.id);
- if let Some(types) = types {
- self.push_stmts(&ser::gen(types, value, self.config.write_checks));
+ if !parameters.is_empty() {
+ self.push_stmts(&ser::gen(
+ parameters.iter().map(|parameter| ¶meter.ty),
+ &get_named_values(value, parameters),
+ self.config.write_checks,
+ ));
}
match ev.evty {
@@ -604,7 +642,7 @@ impl<'a> ServerOutput<'a> {
}
fn push_return_fire_except(&mut self, ev: &EvDecl) {
- let types = &ev.data;
+ let parameters = &ev.data;
let fire_except = self.config.casing.with("FireExcept", "fireExcept", "fire_except");
let except = self.config.casing.with("Except", "except", "except");
@@ -613,9 +651,9 @@ impl<'a> ServerOutput<'a> {
self.push_indent();
self.push(&format!("{fire_except} = function({except}: Player"));
- if let Some(types) = types {
+ if !parameters.is_empty() {
self.push(", ");
- self.push_value_parameters(types);
+ self.push_value_parameters(parameters);
}
self.push(")\n");
@@ -625,8 +663,12 @@ impl<'a> ServerOutput<'a> {
self.push_write_event_id(ev.id);
- if let Some(types) = types {
- self.push_stmts(&ser::gen(types, value, self.config.write_checks));
+ if !parameters.is_empty() {
+ self.push_stmts(&ser::gen(
+ parameters.iter().map(|paramater| ¶mater.ty),
+ &get_named_values(value, parameters),
+ self.config.write_checks,
+ ));
}
match ev.evty {
@@ -667,7 +709,7 @@ impl<'a> ServerOutput<'a> {
}
fn push_return_fire_list(&mut self, ev: &EvDecl) {
- let types = &ev.data;
+ let parameters = &ev.data;
let fire_list = self.config.casing.with("FireList", "fireList", "fire_list");
let list = self.config.casing.with("List", "list", "list");
@@ -676,9 +718,9 @@ impl<'a> ServerOutput<'a> {
self.push_indent();
self.push(&format!("{fire_list} = function({list}: {{ Player }}"));
- if let Some(types) = types {
+ if !parameters.is_empty() {
self.push(", ");
- self.push_value_parameters(types);
+ self.push_value_parameters(parameters);
}
self.push(")\n");
@@ -688,8 +730,12 @@ impl<'a> ServerOutput<'a> {
self.push_write_event_id(ev.id);
- if let Some(ty) = types {
- self.push_stmts(&ser::gen(ty, value, self.config.write_checks));
+ if !parameters.is_empty() {
+ self.push_stmts(&ser::gen(
+ parameters.iter().map(|parameter| ¶meter.ty),
+ &get_named_values(value, parameters),
+ self.config.write_checks,
+ ));
}
match ev.evty {
@@ -722,7 +768,7 @@ impl<'a> ServerOutput<'a> {
}
fn push_return_fire_set(&mut self, ev: &EvDecl) {
- let types = &ev.data;
+ let parameters = &ev.data;
let fire_set = self.config.casing.with("FireSet", "fireSet", "fire_set");
let set = self.config.casing.with("Set", "set", "set");
@@ -731,9 +777,9 @@ impl<'a> ServerOutput<'a> {
self.push_indent();
self.push(&format!("{fire_set} = function({set}: {{ [Player]: true }}"));
- if let Some(types) = types {
+ if !parameters.is_empty() {
self.push(", ");
- self.push_value_parameters(types);
+ self.push_value_parameters(parameters);
}
self.push(")\n");
@@ -743,8 +789,12 @@ impl<'a> ServerOutput<'a> {
self.push_write_event_id(ev.id);
- if let Some(ty) = types {
- self.push_stmts(&ser::gen(ty, value, self.config.write_checks));
+ if !parameters.is_empty() {
+ self.push_stmts(&ser::gen(
+ parameters.iter().map(|parameter| ¶meter.ty),
+ &get_named_values(value, parameters),
+ self.config.write_checks,
+ ));
}
match ev.evty {
@@ -811,9 +861,9 @@ impl<'a> ServerOutput<'a> {
self.push_indent();
self.push(&format!("{set_callback} = function({callback}: ({player}: Player"));
- if let Some(types) = &ev.data {
+ if !ev.data.is_empty() {
self.push(", ");
- self.push_value_parameters(types);
+ self.push_value_parameters(&ev.data);
}
self.push(") -> ()): () -> ()\n");
@@ -843,9 +893,9 @@ impl<'a> ServerOutput<'a> {
self.push_indent();
self.push(&format!("{on} = function({callback}: ({player}: Player"));
- if let Some(types) = &ev.data {
+ if !ev.data.is_empty() {
self.push(", ");
- self.push_value_parameters(types);
+ self.push_value_parameters(&ev.data);
}
self.push(") -> ()): () -> ()\n");
@@ -877,9 +927,9 @@ impl<'a> ServerOutput<'a> {
self.push_indent();
self.push(&format!("{set_callback} = function({callback}: ({player}: Player"));
- if let Some(types) = &fndecl.args {
+ if !fndecl.args.is_empty() {
self.push(", ");
- self.push_value_parameters(types);
+ self.push_value_parameters(&fndecl.args);
}
self.push(") -> (");
diff --git a/zap/src/output/mod.rs b/zap/src/output/mod.rs
index 87750f5e..493c1cf2 100644
--- a/zap/src/output/mod.rs
+++ b/zap/src/output/mod.rs
@@ -1,3 +1,34 @@
+use crate::config::Parameter;
+
pub mod luau;
pub mod tooling;
pub mod typescript;
+
+pub fn get_unnamed_values(prefix: &str, count: usize) -> Vec {
+ (0..count)
+ .map(|i| {
+ if i > 0 {
+ format!("{prefix}{}", i + 1)
+ } else {
+ prefix.to_string()
+ }
+ })
+ .collect()
+}
+
+pub fn get_named_values(default_prefix: &str, parameters: &[Parameter]) -> Vec {
+ parameters
+ .iter()
+ .enumerate()
+ .map(|(i, parameter)| match parameter.name {
+ Some(name) => name.to_string(),
+ None => {
+ if i > 0 {
+ format!("{default_prefix}{}", i + 1)
+ } else {
+ default_prefix.to_string()
+ }
+ }
+ })
+ .collect()
+}
diff --git a/zap/src/output/tooling.rs b/zap/src/output/tooling.rs
index 2a228a3d..10ffb5da 100644
--- a/zap/src/output/tooling.rs
+++ b/zap/src/output/tooling.rs
@@ -1,6 +1,7 @@
use crate::{
- config::{Config, EvDecl, FnDecl, Ty, TyDecl},
+ config::{Config, EvDecl, FnDecl, Parameter, TyDecl},
irgen::{des, Stmt},
+ output::get_unnamed_values,
Output,
};
@@ -115,7 +116,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.clone()], "value", true));
+ self.push_stmts(&des::gen(std::iter::once(ty), &get_unnamed_values("value", 1), true));
self.push_line("return value");
self.dedent();
self.push_line("end");
@@ -129,9 +130,9 @@ impl<'src> ToolingOutput<'src> {
}
}
- fn get_values(&self, data: &Option>) -> String {
- if let Some(types) = data {
- (1..=types.len())
+ fn get_values(&self, data: &[Parameter]) -> String {
+ if !data.is_empty() {
+ (1..=data.len())
.map(|i| {
if i == 1 {
"value".to_string()
@@ -168,8 +169,12 @@ impl<'src> ToolingOutput<'src> {
self.push_line(&format!("local {values}"));
- if let Some(data) = &ev.data {
- self.push_stmts(&des::gen(data, "value", true));
+ if !ev.data.is_empty() {
+ self.push_stmts(&des::gen(
+ ev.data.iter().map(|parameter| ¶meter.ty),
+ &get_unnamed_values("value", ev.data.len()),
+ true,
+ ));
}
self.push_line("table.insert(events, {");
@@ -226,8 +231,12 @@ impl<'src> ToolingOutput<'src> {
self.push_line(&format!("local {values}"));
- if let Some(data) = &fn_decl.args {
- self.push_stmts(&des::gen(data, "value", true));
+ if !fn_decl.args.is_empty() {
+ self.push_stmts(&des::gen(
+ fn_decl.args.iter().map(|parameter| ¶meter.ty),
+ &get_unnamed_values("value", fn_decl.args.len()),
+ true,
+ ));
}
self.push_line("table.insert(events, {");
@@ -255,7 +264,7 @@ impl<'src> ToolingOutput<'src> {
self.push_line(&format!("local {values}"));
if let Some(data) = &fn_decl.rets {
- self.push_stmts(&des::gen(data, "value", true));
+ self.push_stmts(&des::gen(data, &get_unnamed_values("value", data.len()), true));
}
self.push_line("table.insert(events, {");
diff --git a/zap/src/output/typescript/client.rs b/zap/src/output/typescript/client.rs
index 2590655b..8dee730b 100644
--- a/zap/src/output/typescript/client.rs
+++ b/zap/src/output/typescript/client.rs
@@ -1,4 +1,3 @@
-use crate::config::Ty;
use crate::config::{Config, EvCall, EvSource, TyDecl, YieldType};
use super::ConfigProvider;
@@ -81,8 +80,8 @@ impl<'src> ClientOutput<'src> {
self.push_indent();
self.push(&format!("{fire}: ("));
- if let Some(types) = &ev.data {
- self.push_parameters(types);
+ if !ev.data.is_empty() {
+ self.push_parameters(&ev.data);
}
self.push(") => void;\n");
@@ -114,8 +113,8 @@ impl<'src> ClientOutput<'src> {
self.push_indent();
self.push(&format!("{set_callback}: ({callback}: ("));
- if let Some(types) = &ev.data {
- self.push_parameters(types);
+ if !ev.data.is_empty() {
+ self.push_parameters(&ev.data);
}
self.push(") => void) => () => void;\n");
@@ -135,8 +134,8 @@ impl<'src> ClientOutput<'src> {
self.push_indent();
self.push(&format!("{call}: ("));
- if let Some(types) = &fndecl.args {
- self.push_parameters(types);
+ if !fndecl.args.is_empty() {
+ self.push_parameters(&fndecl.args);
}
self.push(") => ");
diff --git a/zap/src/output/typescript/mod.rs b/zap/src/output/typescript/mod.rs
index 71a29755..7aa9c9ba 100644
--- a/zap/src/output/typescript/mod.rs
+++ b/zap/src/output/typescript/mod.rs
@@ -1,4 +1,4 @@
-use crate::config::{Config, Enum, Ty};
+use crate::config::{Config, Enum, Parameter, Ty};
pub mod client;
pub mod server;
@@ -224,19 +224,24 @@ pub trait Output: ConfigProvider {
}
}
- fn push_parameters(&mut self, types: &[Ty]) {
+ fn push_parameters(&mut self, parameters: &[Parameter]) {
let value = self.get_config().casing.with("Value", "value", "value");
- for (i, ty) in types.iter().enumerate() {
+ for (i, parameter) in parameters.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);
+ if let Some(name) = parameter.name {
+ self.push(name);
+ } else {
+ self.push(&format!(
+ "{value}{}",
+ if i > 0 { (i + 1).to_string() } else { "".to_string() },
+ ));
+ }
+
+ self.push_arg_ty(¶meter.ty);
}
}
diff --git a/zap/src/output/typescript/server.rs b/zap/src/output/typescript/server.rs
index 398ff719..7d7cf44b 100644
--- a/zap/src/output/typescript/server.rs
+++ b/zap/src/output/typescript/server.rs
@@ -1,4 +1,3 @@
-use crate::config::Ty;
use crate::config::{Config, EvCall, EvDecl, EvSource, TyDecl};
use super::ConfigProvider;
@@ -72,9 +71,9 @@ impl<'a> ServerOutput<'a> {
self.push_indent();
self.push(&format!("{fire}: ({player}: Player"));
- if let Some(types) = &ev.data {
+ if !ev.data.is_empty() {
self.push(", ");
- self.push_parameters(types);
+ self.push_parameters(&ev.data);
}
self.push(") => void;\n");
@@ -86,8 +85,8 @@ impl<'a> ServerOutput<'a> {
self.push_indent();
self.push(&format!("{fire_all}: ("));
- if let Some(types) = &ev.data {
- self.push_parameters(types);
+ if !ev.data.is_empty() {
+ self.push_parameters(&ev.data);
}
self.push(") => void;\n");
@@ -100,9 +99,9 @@ impl<'a> ServerOutput<'a> {
self.push_indent();
self.push(&format!("{fire_except}: ({except}: Player"));
- if let Some(types) = &ev.data {
+ if !ev.data.is_empty() {
self.push(", ");
- self.push_parameters(types);
+ self.push_parameters(&ev.data);
}
self.push(") => void;\n");
@@ -115,9 +114,9 @@ impl<'a> ServerOutput<'a> {
self.push_indent();
self.push(&format!("{fire_list}: ({list}: Player[]"));
- if let Some(types) = &ev.data {
+ if !ev.data.is_empty() {
self.push(", ");
- self.push_parameters(types);
+ self.push_parameters(&ev.data);
}
self.push(") => void;\n");
@@ -130,9 +129,9 @@ impl<'a> ServerOutput<'a> {
self.push_indent();
self.push(&format!("{fire_set}: ({set}: Set"));
- if let Some(types) = &ev.data {
+ if !ev.data.is_empty() {
self.push(", ");
- self.push_parameters(types);
+ self.push_parameters(&ev.data);
}
self.push(") => void\n");
@@ -187,9 +186,9 @@ impl<'a> ServerOutput<'a> {
self.push_indent();
self.push(&format!("{set_callback}: ({callback}: ({player}: Player"));
- if let Some(types) = &ev.data {
+ if !ev.data.is_empty() {
self.push(", ");
- self.push_parameters(types);
+ self.push_parameters(&ev.data);
}
self.push(") => void) => () => void;\n");
@@ -211,9 +210,9 @@ impl<'a> ServerOutput<'a> {
self.push_indent();
self.push(&format!("{set_callback}: ({callback}: ({player}: Player"));
- if let Some(types) = &fndecl.args {
+ if !fndecl.args.is_empty() {
self.push(", ");
- self.push_parameters(types);
+ self.push_parameters(&fndecl.args);
}
self.push(") => ");
diff --git a/zap/src/parser/convert.rs b/zap/src/parser/convert.rs
index 25d9915f..957be2d1 100644
--- a/zap/src/parser/convert.rs
+++ b/zap/src/parser/convert.rs
@@ -1,6 +1,8 @@
use std::collections::{HashMap, HashSet};
-use crate::config::{Casing, Config, Enum, EvDecl, EvType, FnDecl, NumTy, Range, Struct, Ty, TyDecl, YieldType};
+use crate::config::{
+ Casing, Config, Enum, EvDecl, EvType, FnDecl, NumTy, Parameter, Range, Struct, Ty, TyDecl, YieldType,
+};
use super::{
reports::{Report, Span},
@@ -309,27 +311,55 @@ impl<'src> Converter<'src> {
}
}
+ fn check_duplicate_parameters(&mut self, syntax_parameters: &SyntaxParameters<'src>) {
+ let mut seen: HashMap<_, std::ops::Range> = HashMap::new();
+ for (identifier, _) in &syntax_parameters.parameters {
+ if let Some(identifier) = identifier {
+ if let Some(first_span) = seen.get(identifier.name) {
+ self.report(Report::AnalyzeDuplicateParameter {
+ prev_span: first_span.clone(),
+ dup_span: identifier.span(),
+ name: identifier.name,
+ });
+ } else {
+ seen.insert(identifier.name, identifier.span());
+ }
+ }
+ }
+ }
+
fn evdecl(
&mut self,
evdecl: &SyntaxEvDecl<'src>,
id: usize,
tydecls: &HashMap<&'src str, &Ty<'src>>,
) -> EvDecl<'src> {
+ if let Some(syntax_parameters) = &evdecl.data {
+ self.check_duplicate_parameters(syntax_parameters);
+ }
+
let name = evdecl.name.name;
let from = evdecl.from;
let evty = evdecl.evty;
let call = evdecl.call;
- let data = evdecl
- .data
- .as_ref()
- .map(|types| types.iter().map(|ty| self.ty(ty)).collect::>());
+ let data = evdecl.data.as_ref().map(|parameters| {
+ parameters
+ .parameters
+ .iter()
+ .map(|(identifier, ty)| {
+ let name = identifier.map(|identifier| identifier.name);
+
+ Parameter { name, ty: self.ty(ty) }
+ })
+ .collect::>()
+ });
if data.is_some() && evty == EvType::Unreliable {
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());
+ for parameter in data.as_ref().unwrap() {
+ let (ty_min, ty_max) = parameter.ty.size(tydecls, &mut HashSet::new());
min += ty_min;
@@ -361,26 +391,51 @@ impl<'src> Converter<'src> {
from,
evty,
call,
- data,
+ data: data.unwrap_or_default(),
id,
}
}
fn fndecl(&mut self, fndecl: &SyntaxFnDecl<'src>, id: usize) -> FnDecl<'src> {
+ if let Some(syntax_parameters) = &fndecl.args {
+ self.check_duplicate_parameters(syntax_parameters);
+ }
+
+ if let Some(syntax_parameters) = &fndecl.rets {
+ for parameter in &syntax_parameters.parameters {
+ if let Some(identifier) = parameter.0 {
+ self.report(Report::AnalyzeNamedReturn {
+ name_span: identifier.span(),
+ });
+ }
+ }
+ }
+
let name = fndecl.name.name;
let call = fndecl.call;
- 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::>());
+ let args = fndecl.args.as_ref().map(|parameters| {
+ parameters
+ .parameters
+ .iter()
+ .map(|(identifier, ty)| {
+ let name = identifier.map(|identifier| identifier.name);
+
+ Parameter { name, ty: self.ty(ty) }
+ })
+ .collect::>()
+ });
+
+ let rets = fndecl.rets.as_ref().map(|parameters| {
+ parameters
+ .parameters
+ .iter()
+ .map(|(_, ty)| self.ty(ty))
+ .collect::>()
+ });
FnDecl {
name,
- args,
+ args: args.unwrap_or_default(),
call,
rets,
id,
diff --git a/zap/src/parser/grammar.lalrpop b/zap/src/parser/grammar.lalrpop
index dee0fca0..73abf904 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 },
}
@@ -59,7 +59,7 @@ EvDecl: SyntaxEvDecl<'input> = {
"from" ":"
"," "type" ":"
"," "call" ":"
- )?>
+ )?>
","?
"}" ";"? => SyntaxEvDecl { start, name, from, evty, call, data, end },
}
@@ -116,9 +116,20 @@ TyKind: SyntaxTyKind<'input> = {
"Instance" ")")?> => SyntaxTyKind::Instance(c),
}
-TyList: Vec> = {
- => vec![ty],
- "(" > ")" => tys,
+Parameters: SyntaxParameters<'input> = {
+
+
+ => SyntaxParameters { start, parameters, end },
+}
+
+ParameterList: Vec<(Option>, SyntaxTy<'input>)> = {
+ => vec![(None, ty)],
+ "(" > ")" => tys,
+}
+
+Parameter: (Option>, SyntaxTy<'input>) = {
+ ":" => (Some(name), ty),
+ => (None, ty),
}
Enum: SyntaxEnum<'input> = {
diff --git a/zap/src/parser/reports.rs b/zap/src/parser/reports.rs
index bf02dc38..79e2f376 100644
--- a/zap/src/parser/reports.rs
+++ b/zap/src/parser/reports.rs
@@ -96,6 +96,16 @@ pub enum Report<'src> {
dup_span: Span,
name: &'src str,
},
+
+ AnalyzeDuplicateParameter {
+ prev_span: Span,
+ dup_span: Span,
+ name: &'src str,
+ },
+
+ AnalyzeNamedReturn {
+ name_span: Span,
+ },
}
impl<'src> Report<'src> {
@@ -122,6 +132,8 @@ impl<'src> Report<'src> {
Self::AnalyzeUnboundedRecursiveType { .. } => Severity::Error,
Self::AnalyzeMissingOptValue { .. } => Severity::Error,
Self::AnalyzeDuplicateDecl { .. } => Severity::Error,
+ Self::AnalyzeDuplicateParameter { .. } => Severity::Error,
+ Self::AnalyzeNamedReturn { .. } => Severity::Error,
}
}
@@ -151,6 +163,8 @@ impl<'src> Report<'src> {
Self::AnalyzeUnboundedRecursiveType { .. } => "unbounded recursive type".to_string(),
Self::AnalyzeMissingOptValue { .. } => "missing option expected".to_string(),
Self::AnalyzeDuplicateDecl { name, .. } => format!("duplicate declaration '{}'", name),
+ Self::AnalyzeDuplicateParameter { name, .. } => format!("duplicate parameter '{}'", name),
+ Self::AnalyzeNamedReturn { .. } => "rets cannot be named".to_string(),
}
}
@@ -177,6 +191,8 @@ impl<'src> Report<'src> {
Self::AnalyzeUnboundedRecursiveType { .. } => "3012",
Self::AnalyzeMissingOptValue { .. } => "3013",
Self::AnalyzeDuplicateDecl { .. } => "3014",
+ Self::AnalyzeDuplicateParameter { .. } => "3015",
+ Self::AnalyzeNamedReturn { .. } => "3016",
}
}
@@ -272,6 +288,19 @@ impl<'src> Report<'src> {
Label::primary((), dup_span.clone()).with_message("duplicate declaration"),
]
}
+
+ Self::AnalyzeDuplicateParameter {
+ prev_span, dup_span, ..
+ } => {
+ vec![
+ Label::secondary((), prev_span.clone()).with_message("first parameter"),
+ Label::primary((), dup_span.clone()).with_message("duplicate parameter"),
+ ]
+ }
+
+ Self::AnalyzeNamedReturn { name_span } => {
+ vec![Label::primary((), name_span.clone()).with_message("must be removed")]
+ }
}
}
@@ -335,6 +364,8 @@ impl<'src> Report<'src> {
"the {expected} option should not be empty if {required_when}"
)]),
Self::AnalyzeDuplicateDecl { .. } => None,
+ Self::AnalyzeDuplicateParameter { .. } => None,
+ Self::AnalyzeNamedReturn { .. } => None,
}
}
diff --git a/zap/src/parser/syntax_tree.rs b/zap/src/parser/syntax_tree.rs
index 9acdd38c..0d77b111 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,
}
@@ -106,6 +106,19 @@ impl<'src> Spanned for SyntaxEvDecl<'src> {
}
}
+#[derive(Debug, Clone, PartialEq)]
+pub struct SyntaxParameters<'src> {
+ pub start: usize,
+ pub parameters: Vec<(Option>, SyntaxTy<'src>)>,
+ pub end: usize,
+}
+
+impl<'src> Spanned for SyntaxParameters<'src> {
+ fn span(&self) -> Span {
+ self.start..self.end
+ }
+}
+
#[derive(Debug, Clone, PartialEq)]
pub struct SyntaxTyDecl<'src> {
pub start: usize,