Skip to content

Commit

Permalink
Add tuples
Browse files Browse the repository at this point in the history
  • Loading branch information
nezuo committed Nov 23, 2024
1 parent 93543cc commit 2ef3122
Show file tree
Hide file tree
Showing 11 changed files with 372 additions and 69 deletions.
22 changes: 22 additions & 0 deletions zap/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ pub enum Ty<'src> {
Arr(Box<Ty<'src>>, Range),
Map(Box<Ty<'src>>, Box<Ty<'src>>),
Set(Box<Ty<'src>>),
Tup(Vec<Ty<'src>>),
Opt(Box<Ty<'src>>),
Ref(&'src str),

Expand Down Expand Up @@ -206,6 +207,27 @@ impl<'src> Ty<'src> {

Self::Set(..) => (2, None),

Self::Tup(types) => {
let mut min_size = 0;
let mut max_size = Some(0);

for ty in types {
let (ty_min, ty_max) = ty.size(tydecls, recursed);

min_size += ty_min;

if let Some(ty_max) = ty_max {
if let Some(ref mut max_size) = max_size {
*max_size += ty_max;
}
} else {
max_size = None;
}
}

(min_size, None)
}

Self::Opt(ty) => {
let (_, ty_max) = ty.size(tydecls, recursed);

Expand Down
16 changes: 16 additions & 0 deletions zap/src/irgen/des.rs
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,22 @@ impl Des {
self.push_stmt(Stmt::End);
}

Ty::Tup(types) => {
for (i, ty) in types.iter().enumerate() {
let var = if i > 0 {
if let Var::Name(ref name) = into {
Var::Name(format!("{name}{}", i + 1))
} else {
unreachable!()
}
} else {
into.clone()
};

self.push_ty(ty, var);
}
}

Ty::Opt(ty) => {
self.push_stmt(Stmt::If(self.readu8().eq(1.0.into())));

Expand Down
16 changes: 16 additions & 0 deletions zap/src/irgen/ser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,22 @@ impl Ser {
));
}

Ty::Tup(types) => {
for (i, ty) in types.iter().enumerate() {
let var = if i > 0 {
if let Var::Name(ref name) = from {
Var::Name(format!("{name}{}", i + 1))
} else {
unreachable!()
}
} else {
from.clone()
};

self.push_ty(ty, var);
}
}

Ty::Opt(ty) => {
self.push_stmt(Stmt::If(from_expr.clone().eq(Expr::Nil)));

Expand Down
155 changes: 120 additions & 35 deletions zap/src/output/luau/client.rs
Original file line number Diff line number Diff line change
@@ -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},
};

Expand Down Expand Up @@ -174,6 +174,43 @@ impl<'src> ClientOutput<'src> {
));
}

fn push_values_args(&mut self, data: &Ty) {
let value = self.config.casing.with("Value", "value", "value");

if let Ty::Tup(types) = data {
for (i, ty) in types.iter().enumerate() {
self.push(&format!(
"{value}{}: ",
if i > 0 { (i + 1).to_string() } else { "".to_string() }
));
self.push_ty(ty);
if i != types.len() - 1 {
self.push(", ");
}
}
} else {
self.push(&format!("{value}: "));
self.push_ty(data);
}
}

fn get_values(&self, data: &Option<Ty>) -> String {
if let Some(Ty::Tup(types)) = data {
(1..=types.len())
.map(|i| {
if i == 1 {
"value".to_string()
} else {
format!("value{}", i)
}
})
.collect::<Vec<_>>()
.join(", ")
} else {
"value".to_string()
}
}

fn push_reliable_callback(&mut self, first: bool, ev: &EvDecl) {
let id = ev.id;

Expand All @@ -193,7 +230,13 @@ impl<'src> ClientOutput<'src> {

self.indent();

self.push_line("local value");
let values = self.get_values(&ev.data);

if let Some(Ty::Tup(_)) = &ev.data {
self.push_line(&format!("local {values}",));
} else {
self.push_line("local value");
}

if let Some(data) = &ev.data {
self.push_stmts(&des::gen(data, "value", true));
Expand All @@ -213,10 +256,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 {
Expand All @@ -228,8 +271,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(data) = &ev.data {
if matches!(data, Ty::Tup(_)) {
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"));
Expand Down Expand Up @@ -280,18 +328,24 @@ 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);

if let Some(Ty::Tup(_)) = &fndecl.rets {
self.push_line(&format!("local {values}",));
} else {
self.push_line("local value");
}

if let Some(data) = &fndecl.rets {
self.push_stmts(&des::gen(data, "value", true));
}

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})"));
}
}

Expand Down Expand Up @@ -369,7 +423,13 @@ impl<'src> ClientOutput<'src> {

self.indent();

self.push_line("local value");
let values = self.get_values(&ev.data);

if let Some(Ty::Tup(_)) = &ev.data {
self.push_line(&format!("local {values}",));
} else {
self.push_line("local value");
}

if let Some(data) = &ev.data {
self.push_stmts(&des::gen(data, "value", self.config.write_checks));
Expand All @@ -389,10 +449,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 {
Expand All @@ -404,8 +464,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(data) = &ev.data {
if matches!(data, Ty::Tup(_)) {
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"));
Expand Down Expand Up @@ -523,8 +588,7 @@ impl<'src> ClientOutput<'src> {
self.push(&format!("{fire} = function("));

if let Some(data) = &ev.data {
self.push(&format!("{value}: "));
self.push_ty(data);
self.push_values_args(data);
}

self.push(")\n");
Expand Down Expand Up @@ -587,14 +651,20 @@ impl<'src> ClientOutput<'src> {

self.push_line(&format!("events[{id}] = {callback}"));

if ev.data.is_some() {
if let Some(data) = &ev.data {
self.push_line(&format!("for _, value in event_queue[{id}] do"));
self.indent();

let value = if let Ty::Tup(_) = data {
"unpack(value)".to_string()
} else {
"value".to_string()
};

if ev.call == EvCall::SingleSync {
self.push_line(&format!("{callback}(value)"))
self.push_line(&format!("{callback}({value})"))
} else {
self.push_line(&format!("task.spawn({callback}, value)"))
self.push_line(&format!("task.spawn({callback}, {value})"))
}

self.dedent();
Expand Down Expand Up @@ -647,14 +717,20 @@ impl<'src> ClientOutput<'src> {

self.push_line(&format!("table.insert(events[{id}], {callback})"));

if ev.data.is_some() {
if let Some(data) = &ev.data {
self.push_line(&format!("for _, value in event_queue[{id}] do"));
self.indent();

let value = if let Ty::Tup(_) = data {
"unpack(value)".to_string()
} else {
"value".to_string()
};

if ev.call == EvCall::ManySync {
self.push_line(&format!("{callback}(value)"))
self.push_line(&format!("{callback}({value})"))
} else {
self.push_line(&format!("task.spawn({callback}, value)"))
self.push_line(&format!("task.spawn({callback}, {value})"))
}

self.dedent();
Expand Down Expand Up @@ -725,8 +801,7 @@ impl<'src> ClientOutput<'src> {
self.push(&format!("{call} = function("));

if let Some(ty) = &fndecl.args {
self.push(&format!("{value}: "));
self.push_ty(ty);
self.push_values_args(ty);
}

self.push(")");
Expand All @@ -735,12 +810,24 @@ impl<'src> ClientOutput<'src> {
match self.config.yield_type {
YieldType::Future => {
self.push(": Future.Future<");
self.push_ty(ty);
if matches!(ty, Ty::Tup(_)) {
self.push("(");
self.push_ty(ty);
self.push(")");
} else {
self.push_ty(ty);
}
self.push(">");
}
YieldType::Yield => {
self.push(": ");
self.push_ty(ty);
if matches!(ty, Ty::Tup(_)) {
self.push("(");
self.push_ty(ty);
self.push(")");
} else {
self.push_ty(ty);
}
}
_ => (),
}
Expand Down Expand Up @@ -774,10 +861,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()",));
Expand All @@ -787,7 +874,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"));
Expand All @@ -797,8 +884,6 @@ impl<'src> ClientOutput<'src> {
}
}

self.push_line("return async_value");

self.dedent();
self.push_line("end,");

Expand Down
Loading

0 comments on commit 2ef3122

Please sign in to comment.