Tau is the Interface Definition Language (IDL) for the KAI distributed object model. It defines service interfaces and generates the necessary proxy and agent code for network communication. This document details the code generation architecture and how to use it.
The Tau code generation system is built on a hierarchy of specialized generators:
- Location:
Include/KAI/Language/Tau/Generate/GenerateProcess.h - Purpose: Base class providing common functionality for all code generators
- Key Methods:
Generate()- Main entry point for code generationParse()- Parses Tau IDL inputModule(),Namespace(),Class()- AST traversal methodsStartBlock(),EndBlock()- Code formatting utilities
- Location:
Include/KAI/Language/Tau/Generate/GenerateProxy.h - Purpose: Generates client-side proxy classes for remote procedure calls
- Output: C++ proxy classes that forward method calls over the network
- Key Features:
- Generates proxy methods that serialize arguments
- Handles return values via futures
- Supports event registration/unregistration
- Creates type-safe RPC interfaces
- Location:
Include/KAI/Language/Tau/Generate/GenerateAgent.h - Purpose: Generates server-side agent classes for handling incoming requests
- Output: C++ agent classes that receive and process network requests
- Key Features:
- Generates handler methods for each interface method
- Deserializes incoming arguments
- Invokes implementation methods
- Sends responses for non-void methods
- Location:
Include/KAI/Language/Tau/Generate/GenerateStruct.h - Purpose: Generates plain C++ struct definitions from Tau IDL
- Output: Simple struct definitions for data transfer objects
- Key Features:
- Creates POD structures
- Preserves field ordering
- Supports nested structures
- Can include method declarations
namespace MyApp {
struct UserData {
int id;
string name;
string email;
}
interface IUserService {
UserData GetUser(int id);
void UpdateUser(UserData user);
bool DeleteUser(int id);
event OnUserChanged(int userId);
}
}
#include <KAI/Language/Tau/Generate/GenerateProxy.h>
#include <KAI/Language/Tau/Generate/GenerateAgent.h>
#include <KAI/Language/Tau/Generate/GenerateStruct.h>
// Generate proxy code
string proxyCode;
TAU_NS(Generate::GenerateProxy) proxyGen(idlSource, proxyCode);
// Generate agent code
string agentCode;
TAU_NS(Generate::GenerateAgent) agentGen(idlSource, agentCode);
// Generate struct definitions
string structCode;
TAU_NS(Generate::GenerateStruct) structGen(idlSource, structCode);namespace MyApp {
class IUserServiceProxy : public ProxyBase {
using ProxyBase::StreamType;
IUserServiceProxy(Node &node, NetHandle handle) : ProxyBase(node, handle) { }
UserData GetUser(const int& id) {
ENet::BitStream args;
args << id;
auto future = _node->SendWithResponse("GetUser", args);
return future.get();
}
void UpdateUser(const UserData& user) {
ENet::BitStream args;
args << user;
_node->Send("UpdateUser", args);
}
void RegisterOnUserChangedHandler(std::function<void(int)> handler) {
RegisterEventHandler("OnUserChanged", handler);
}
};
}namespace MyApp {
class IUserServiceAgent : public AgentBase<IUserService> {
IUserServiceAgent(Node &node, NetHandle handle) : AgentBase(node, handle) { }
void Handle_GetUser(ENet::BitStream& bs, ENet::SystemAddress& sender) {
int id;
bs >> id;
UserData result = _impl->GetUser(id);
ENet::BitStream response;
response << result;
_node->SendResponse(sender, response);
}
void Handle_UpdateUser(ENet::BitStream& bs, ENet::SystemAddress& sender) {
UserData user;
bs >> user;
_impl->UpdateUser(user);
}
};
}- Proxy: Handles client-side networking, serialization, and futures
- Agent: Handles server-side deserialization and method dispatch
- Struct: Defines pure data structures without behavior
- Generated code maintains full C++ type safety
- Compile-time errors for interface mismatches
- No runtime type casting required
- Clients use proxies exactly like local objects
- All networking complexity is hidden
- Automatic serialization/deserialization
The generated code integrates seamlessly with KAI's network infrastructure:
- Proxies use the Node's
Send()andSendWithResponse()methods - Agents register handlers with the Node's message dispatcher
- Structs are serializable via ENet BitStreams
- Events use the Node's event system for multicast notifications
- Keep interfaces focused and cohesive
- Use structs for complex parameter types
- Prefer simple types for better interoperability
- Document your interfaces thoroughly
- Generate code into separate files for each component
- Use consistent naming:
IFoo→FooProxy,FooAgent - Keep generated code separate from hand-written code
- Regenerate on IDL changes, don't edit generated code
- Generated proxies throw on network errors
- Agents should validate inputs before processing
- Use events for asynchronous error notifications
- Implement timeouts for long-running operations
The KAI test suite includes comprehensive tests for code generation:
TauGenerateStructTests.cpp- Tests struct generationTauSeparateGenerationTests.cpp- Tests separation of proxy/agent generationTauCodeGenerationTests.cpp- Tests various generation scenarios
Run tests with:
./build/Bin/Test/TestTau --gtest_filter="*Generate*"Planned improvements to the code generation system:
- Versioning Support - Handle interface evolution
- Streaming Interfaces - Support for large data transfers
- Custom Serializers - Plugin architecture for type serialization
- Code Optimization - Reduce generated code size
- Better Error Messages - More helpful generation diagnostics
- Tau Tutorial - General Tau language tutorial
- Network Architecture - KAI networking overview
- Testing Guide - How to test generated code