Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions compiler/fory_compiler/frontend/fbs/ast.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,29 @@ class FbsStruct:
column: int = 0


@dataclass
class FbsRpcMethod:
"""An RPC method declaration."""

name: str
request_type: str
response_type: str
attributes: Dict[str, object] = field(default_factory=dict)
line: int = 0
column: int = 0


@dataclass
class FbsService:
"""A FlatBuffers service declaration."""

name: str
methods: List[FbsRpcMethod] = field(default_factory=list)
attributes: Dict[str, object] = field(default_factory=dict)
line: int = 0
column: int = 0


@dataclass
class FbsSchema:
"""The root node representing a FlatBuffers schema."""
Expand All @@ -120,5 +143,6 @@ class FbsSchema:
unions: List[FbsUnion] = field(default_factory=list)
tables: List[FbsTable] = field(default_factory=list)
structs: List[FbsStruct] = field(default_factory=list)
services: List[FbsService] = field(default_factory=list)
root_type: Optional[str] = None
source_file: Optional[str] = None
9 changes: 9 additions & 0 deletions compiler/fory_compiler/frontend/fbs/lexer.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ class TokenType(Enum):
FILE_EXTENSION = auto()
TRUE = auto()
FALSE = auto()
SERVICE = auto()
RPC = auto()
RETURNS = auto()
STREAM = auto()

# Literals
IDENT = auto()
Expand Down Expand Up @@ -97,6 +101,11 @@ class Lexer:
"file_extension": TokenType.FILE_EXTENSION,
"true": TokenType.TRUE,
"false": TokenType.FALSE,
"service": TokenType.SERVICE,
"rpc_service": TokenType.SERVICE,
"rpc": TokenType.RPC,
"returns": TokenType.RETURNS,
"stream": TokenType.STREAM,
}

PUNCTUATION = {
Expand Down
75 changes: 74 additions & 1 deletion compiler/fory_compiler/frontend/fbs/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@
FbsTypeName,
FbsTypeRef,
FbsVectorType,
FbsService,
FbsRpcMethod,
)
from fory_compiler.frontend.fbs.lexer import Token, TokenType

Expand Down Expand Up @@ -96,7 +98,9 @@ def parse(self) -> FbsSchema:
enums: List[FbsEnum] = []
unions: List[FbsUnion] = []
tables: List[FbsTable] = []
tables: List[FbsTable] = []
structs: List[FbsStruct] = []
services: List[FbsService] = []
root_type: Optional[str] = None

while not self.at_end():
Expand All @@ -122,6 +126,8 @@ def parse(self) -> FbsSchema:
self.parse_file_extension()
elif self.check(TokenType.UNION):
unions.append(self.parse_union())
elif self.check(TokenType.SERVICE) or self.check(TokenType.RPC):
services.append(self.parse_service())
elif self.check(TokenType.SEMI):
self.advance()
else:
Expand All @@ -135,6 +141,7 @@ def parse(self) -> FbsSchema:
unions=unions,
tables=tables,
structs=structs,
services=services,
root_type=root_type,
source_file=self.filename,
)
Expand Down Expand Up @@ -369,11 +376,77 @@ def parse_value(self) -> object:
if self.match(TokenType.FALSE):
return False
if self.check(TokenType.INT):
return int(self.advance().value, 0)
value = self.advance().value
try:
return int(value, 0)
except ValueError:
return int(value)
if self.check(TokenType.FLOAT):
return float(self.advance().value)
if self.check(TokenType.STRING):
return self.advance().value
if self.check(TokenType.IDENT):
return self.advance().value
raise self.error("Expected value")

def parse_service(self) -> FbsService:
start = self.current()
# Support both 'service' and 'rpc_service' keywords for defining services.
if self.check(TokenType.SERVICE):
self.advance()
elif self.check(TokenType.RPC):
# 'rpc_service' is mapped to TokenType.SERVICE in the lexer,
# but we also check for separate 'rpc' token just in case.
self.advance()
if self.check(TokenType.SERVICE):
self.advance()
else:
raise self.error("Expected 'service' or 'rpc_service'")

name = self.consume(TokenType.IDENT, "Expected service name").value
attributes = self.parse_metadata()
self.consume(TokenType.LBRACE, "Expected '{' after service name")

methods: List[FbsRpcMethod] = []
while not self.check(TokenType.RBRACE):
if self.check(TokenType.SEMI):
self.advance()
continue
methods.append(self.parse_rpc_method())

self.consume(TokenType.RBRACE, "Expected '}' after service body")
if self.check(TokenType.SEMI):
self.advance()

return FbsService(
name=name,
methods=methods,
attributes=attributes,
line=start.line,
column=start.column,
)

def parse_rpc_method(self) -> FbsRpcMethod:
# Parse method signature: name(RequestType):ResponseType;
start = self.current()
name = self.consume(TokenType.IDENT, "Expected method name").value

self.consume(TokenType.LPAREN, "Expected '(' after method name")
# Parsing request type. FBS allows type name here.
req_type = self.parse_qualified_ident()
self.consume(TokenType.RPAREN, "Expected ')' after request type")

self.consume(TokenType.COLON, "Expected ':' before response type")
res_type = self.parse_qualified_ident()

attributes = self.parse_metadata()
self.consume(TokenType.SEMI, "Expected ';' after method declaration")

return FbsRpcMethod(
name=name,
request_type=req_type,
response_type=res_type,
attributes=attributes,
line=start.line,
column=start.column,
)
51 changes: 51 additions & 0 deletions compiler/fory_compiler/frontend/fbs/translator.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@
FbsTypeRef,
FbsVectorType,
FbsUnion,
FbsService,
FbsRpcMethod,
)
from fory_compiler.ir.ast import (
Enum,
Expand All @@ -39,6 +41,8 @@
NamedType,
PrimitiveType,
Schema,
Service,
RpcMethod,
SourceLocation,
Union,
)
Expand Down Expand Up @@ -82,6 +86,7 @@ def translate(self) -> Schema:
enums=[self._translate_enum(e) for e in self.schema.enums],
unions=[self._translate_union(u) for u in self.schema.unions],
messages=self._translate_messages(),
services=[self._translate_service(s) for s in self.schema.services],
options={},
source_file=self.schema.source_file,
source_format="fbs",
Expand Down Expand Up @@ -278,3 +283,49 @@ def _translate_type(self, fbs_type: FbsTypeRef):
fbs_type.name, location=self._location(fbs_type.line, fbs_type.column)
)
raise ValueError("Unknown FlatBuffers type")

def _translate_service(self, fbs_service: FbsService) -> Service:
return Service(
name=fbs_service.name,
methods=[self._translate_rpc_method(m) for m in fbs_service.methods],
options=dict(fbs_service.attributes),
line=fbs_service.line,
column=fbs_service.column,
location=self._location(fbs_service.line, fbs_service.column),
)

def _translate_rpc_method(self, fbs_method: FbsRpcMethod) -> RpcMethod:
# Map FBS 'streaming' attribute to Fory's client_streaming/server_streaming flags.
# Expected 'streaming' values: "client", "server", "bidi".
# Default is unary (no streaming).

attributes = dict(fbs_method.attributes)
client_streaming = False
server_streaming = False

# Check for streaming attributes if any (convention)
if attributes.get("streaming") == "client":
client_streaming = True
elif attributes.get("streaming") == "server":
server_streaming = True
elif attributes.get("streaming") == "bidi":
client_streaming = True
server_streaming = True

return RpcMethod(
name=fbs_method.name,
request_type=NamedType(
name=fbs_method.request_type,
location=self._location(fbs_method.line, fbs_method.column),
),
response_type=NamedType(
name=fbs_method.response_type,
location=self._location(fbs_method.line, fbs_method.column),
),
client_streaming=client_streaming,
server_streaming=server_streaming,
options=attributes,
line=fbs_method.line,
column=fbs_method.column,
location=self._location(fbs_method.line, fbs_method.column),
)
8 changes: 8 additions & 0 deletions compiler/fory_compiler/frontend/fdl/lexer.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,10 @@ class TokenType(Enum):
RESERVED = auto()
TO = auto()
MAX = auto()
SERVICE = auto()
RPC = auto()
RETURNS = auto()
STREAM = auto()

# Literals
IDENT = auto()
Expand Down Expand Up @@ -112,6 +116,10 @@ class Lexer:
"reserved": TokenType.RESERVED,
"to": TokenType.TO,
"max": TokenType.MAX,
"service": TokenType.SERVICE,
"rpc": TokenType.RPC,
"returns": TokenType.RETURNS,
"stream": TokenType.STREAM,
}

PUNCTUATION = {
Expand Down
Loading
Loading