Skip to content

Commit

Permalink
Merge pull request #237 from betwixt-labs/features/streams
Browse files Browse the repository at this point in the history
Stream parsing / generation
  • Loading branch information
andrewmd5 authored May 20, 2023
2 parents 7091470 + 5411d77 commit a2a15d6
Show file tree
Hide file tree
Showing 8 changed files with 189 additions and 71 deletions.
4 changes: 2 additions & 2 deletions .env
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
VERSION="2.6.0"
VERSION="2.6.1"
MAJOR=2
MINOR=6
PATCH=0
PATCH=1
7 changes: 7 additions & 0 deletions Compiler/CommandLineFlags.cs
Original file line number Diff line number Diff line change
Expand Up @@ -441,6 +441,13 @@ public static bool TryParse(string[] args, out CommandLineFlags flagStore, out s

var parsedFlags = GetFlags(args);

// prevent the user from passing both --langserv and --config
// and also for the compiler trying to find a config file when running as a language server
if (parsedFlags.HasFlag("langserv")) {
flagStore.LanguageServer = true;
return true;
}


string? configPath;
if (parsedFlags.HasFlag("config"))
Expand Down
120 changes: 85 additions & 35 deletions Core/Generators/TypeScript/TypeScriptGenerator.cs

Large diffs are not rendered by default.

5 changes: 5 additions & 0 deletions Core/Lexer/Tokenization/TokenKind.cs
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,11 @@ public enum TokenKind : ushort
/// </summary>
[Keyword("service")]
Service,
/// <summary>
/// The 'stream' keyword which is reserved by the compiler
/// </summary>
[Keyword("stream")]
Stream,

#endregion

Expand Down
4 changes: 2 additions & 2 deletions Core/Meta/BebopSchema.cs
Original file line number Diff line number Diff line change
Expand Up @@ -224,9 +224,9 @@ public List<SpanException> Validate()
{
errors.Add(new DuplicateServiceMethodIdException(b.Id, sd.Name, fnd.Name, fnd.Span));
}
if (!fnd.ArgumentDefinition.IsAggregate(this))
if (!fnd.RequestDefinition.IsAggregate(this))
{
errors.Add(new InvalidServiceRequestTypeException(sd.Name, fnd.Name, fnd.ArgumentDefinition, fnd.Span));
errors.Add(new InvalidServiceRequestTypeException(sd.Name, fnd.Name, fnd.RequestDefinition, fnd.Span));
}
if (!fnd.ReturnDefintion.IsAggregate(this))
{
Expand Down
19 changes: 11 additions & 8 deletions Core/Meta/Definition.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using System.Text;
using Core.Lexer.Tokenization.Models;
using Core.Meta.Attributes;
using Core.Parser;

namespace Core.Meta
{
Expand Down Expand Up @@ -213,7 +214,7 @@ public UnionBranch(byte discriminator, RecordDefinition definition)
Definition = definition;
}
}

public readonly struct ServiceMethod
{
public readonly uint Id;
Expand Down Expand Up @@ -243,7 +244,7 @@ override public int MinimalEncodedSize(BebopSchema schema)
return 4 + 1 + (Branches.Count == 0 ? 0 : Branches.Min(b => b.Definition.MinimalEncodedSize(schema)));
}
}

public class ServiceDefinition : Definition
{
public ServiceDefinition(string name, Span span, string documentation, ICollection<ServiceMethod> methods) : base(name, span, documentation)
Expand All @@ -265,9 +266,9 @@ public override string ToString()
var builder = new StringBuilder();
builder.AppendLine($"Service: {Name}");
builder.AppendLine("Methods ->");
foreach(var method in Methods)
foreach (var method in Methods)
{
builder.AppendLine($" {method.Definition.Name}({method.Definition.ArgumentDefinition}): {method.Definition.ReturnDefintion} ({method.Id})");
builder.AppendLine($" {method.Definition.Name}({method.Definition.RequestDefinition}): {method.Definition.ReturnDefintion} ({method.Id})");
}
return builder.ToString();
}
Expand All @@ -278,18 +279,20 @@ public override string ToString()
/// </summary>
public class FunctionDefinition : Definition
{
public FunctionDefinition(string name, Span span, string documentation, TypeBase argumentDefinition, TypeBase returnDefintion, Definition? parent = null)
public FunctionDefinition(string name, Span span, string documentation, TypeBase requestDefinition, TypeBase returnDefintion, MethodType methodType, Definition? parent = null)
: base(name, span, documentation, parent)
{
ArgumentDefinition = argumentDefinition;
RequestDefinition = requestDefinition;
ReturnDefintion = returnDefintion;
Type = methodType;
}

public TypeBase ArgumentDefinition { get; }
public TypeBase RequestDefinition { get; }
public TypeBase ReturnDefintion { get; }
public MethodType Type { get; }

public override IEnumerable<string> Dependencies() =>
ArgumentDefinition.Dependencies().Concat(ReturnDefintion.Dependencies());
RequestDefinition.Dependencies().Concat(ReturnDefintion.Dependencies());
}

public class ConstDefinition : Definition
Expand Down
46 changes: 44 additions & 2 deletions Core/Parser/RpcSchema.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,48 @@
namespace Core.Parser
{
static class RpcSchema
/// <summary>
/// Represents the type of Tempo method.
/// Each method type corresponds to a different communication model.
/// </summary>
public enum MethodType
{
/// <summary>
/// Unary method type.
/// Represents a method where the client sends a single request and receives a single response.
/// </summary>
Unary,

/// <summary>
/// ServerStream method type.
/// Represents a method where the client sends a single request and receives a stream of responses.
/// </summary>
ServerStream,

/// <summary>
/// ClientStream method type.
/// Represents a method where the client sends a stream of requests and receives a single response.
/// </summary>
ClientStream,

/// <summary>
/// DuplexStream method type.
/// Represents a method where the client and server send a stream of messages to each other simultaneously.
/// </summary>
DuplexStream,
}

internal static class RpcSchema
{
public static string GetMethodTypeName(MethodType type) {
return type switch
{
MethodType.Unary => "Unary",
MethodType.ServerStream => "ServerStream",
MethodType.ClientStream => "ClientStream",
MethodType.DuplexStream => "DuplexStream",
_ => throw new System.ArgumentOutOfRangeException(nameof(type), type, null)
};
}

// Constants used in the hash algorithm for good distribution properties.
private const uint Seed = 0x5AFE5EED;
Expand All @@ -15,7 +56,8 @@ static class RpcSchema
/// <param name="serviceName">The name of the service the method is on.</param>
/// <param name="methodName">The name of the method</param>
/// <returns>A unique unsigned 32-bit integer.</returns>
public static uint GetMethodId(string serviceName, string methodName) {
public static uint GetMethodId(string serviceName, string methodName)
{
var path = $"/${serviceName}/${methodName}";
return HashString(path);
}
Expand Down
55 changes: 33 additions & 22 deletions Core/Parser/SchemaParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -55,13 +55,13 @@ public class SchemaParser
/// <param name="definition"></param>
private void AddDefinition(Definition definition)
{

if (_definitions.ContainsKey(definition.Name))
{
_errors.Add(new MultipleDefinitionsException(definition));
return;
}

_definitions.Add(definition.Name, definition);
if (_scopes.Count > 0)
{
Expand Down Expand Up @@ -317,9 +317,9 @@ public async Task<BebopSchema> Parse()
}
}
return new BebopSchema(
nameSpace: _nameSpace,
definitions: _definitions,
typeReferences: _typeReferences,
nameSpace: _nameSpace,
definitions: _definitions,
typeReferences: _typeReferences,
parsingErrors: _errors,
imports: _imports
);
Expand Down Expand Up @@ -403,10 +403,10 @@ _ when Eat(TokenKind.Message) => AggregateKind.Message,
private ConstDefinition ParseConstDefinition(string definitionDocumentation)
{
var definitionStart = CurrentToken.Span;

TypeBase type;
string name = "";
Literal? value = new IntegerLiteral(new ScalarType(BaseType.UInt32, new Span(), ""), new Span(), "") ;
Literal? value = new IntegerLiteral(new ScalarType(BaseType.UInt32, new Span(), ""), new Span(), "");
try
{
type = ParseType(CurrentToken);
Expand All @@ -424,7 +424,7 @@ private ConstDefinition ParseConstDefinition(string definitionDocumentation)
var definition = new ConstDefinition(name, definitionSpan, definitionDocumentation, value);
if (_definitions.ContainsKey(name))
{
_errors.Add(new DuplicateConstDefinitionException(definition));
_errors.Add(new DuplicateConstDefinitionException(definition));
}
else
{
Expand Down Expand Up @@ -505,7 +505,7 @@ private Literal ParseLiteral(TypeBase type)
if (Eat(TokenKind.OpenParenthesis))
{
value = CurrentToken.Lexeme;
if (Eat(TokenKind.String)|| (kind == "opcode" && Eat(TokenKind.Number)))
if (Eat(TokenKind.String) || (kind == "opcode" && Eat(TokenKind.Number)))
{
isNumber = PeekToken(_index - 1).Kind == TokenKind.Number;
}
Expand Down Expand Up @@ -545,7 +545,7 @@ private Literal ParseLiteral(TypeBase type)
BaseAttribute? opcodeAttribute,
BaseAttribute? flagsAttribute)
{

var fields = new List<Field>();
var enumBaseType = BaseType.UInt32;
var kindName = kind switch { AggregateKind.Enum => "enum", AggregateKind.Struct => "struct", _ => "message" };
Expand Down Expand Up @@ -632,7 +632,7 @@ private Literal ParseLiteral(TypeBase type)
try
{


// Parse a type name, if this isn't an enum:
TypeBase type = kind == AggregateKind.Enum
? new ScalarType(enumBaseType, definitionToken.Span, definitionToken.Lexeme)
Expand Down Expand Up @@ -714,7 +714,7 @@ private Literal ParseLiteral(TypeBase type)
}
return definition;
}

/// <summary>
/// Parses an rpc service definition and adds it to the <see cref="_definitions"/> collection.
/// </summary>
Expand All @@ -733,11 +733,11 @@ private Literal ParseLiteral(TypeBase type)
}
StartScope();
var serviceName = $"{definitionToken.Lexeme.ToPascalCase()}Service";


var methods = new List<ServiceMethod>();
var usedMethodIds = new HashSet<uint>(){0};
var usedMethodNames = new HashSet<string>() { string.Empty};
var usedMethodIds = new HashSet<uint>() { 0 };
var usedMethodNames = new HashSet<string>() { string.Empty };

var definitionEnd = CurrentToken.Span;
var errored = false;
Expand Down Expand Up @@ -775,14 +775,24 @@ private Literal ParseLiteral(TypeBase type)
_errors.Add(new DuplicateServiceDiscriminatorException(indexToken, serviceName));
}
Expect(TokenKind.OpenParenthesis, hint);
var paramType = ParseType(CurrentToken);

var isRequestStream = Eat(TokenKind.Stream);
var requestType = ParseType(CurrentToken);
Expect(TokenKind.CloseParenthesis, hint);
Expect(TokenKind.Colon, hint);
var isResponseStream = Eat(TokenKind.Stream);
var returnType = ParseType(CurrentToken);
var returnTypeSpan = functionStart.Combine(CurrentToken.Span);
Expect(TokenKind.Semicolon, "Function definition must end with a ';' semicolon");
var functionSpan = functionStart.Combine(CurrentToken.Span);
var function = new FunctionDefinition(methodName, functionSpan, documentation, paramType, returnType);
MethodType GetMethodType() => (isRequestStream, isResponseStream) switch
{
(true, true) => MethodType.DuplexStream,
(true, false) => MethodType.ClientStream,
(false, true) => MethodType.ServerStream,
_ => MethodType.Unary
};
var function = new FunctionDefinition(methodName, functionSpan, documentation, requestType, returnType, GetMethodType());
if (function is null)
{
// Just escape out of there if there's a parsing error in one of the definitions.
Expand All @@ -802,7 +812,7 @@ private Literal ParseLiteral(TypeBase type)
}

var definitionSpan = definitionToken.Span.Combine(definitionEnd);

// make the service itself
var serviceDefinition = new ServiceDefinition(serviceName, definitionSpan, definitionDocumentation, methods);
CloseScope(serviceDefinition);
Expand Down Expand Up @@ -833,7 +843,7 @@ private Literal ParseLiteral(TypeBase type)
var branches = new List<UnionBranch>();
var usedDiscriminators = new HashSet<uint>();


var definitionEnd = CurrentToken.Span;
var errored = false;
var unionFieldFollowKinds = new HashSet<TokenKind>() { TokenKind.BlockComment, TokenKind.Number, TokenKind.CloseBrace };
Expand Down Expand Up @@ -1000,7 +1010,8 @@ private Expression ParseExpression(Dictionary<string, BigInteger> identifiers)
var output = new Stack<Expression>();

int Precedence(Token token) =>
token.Kind switch {
token.Kind switch
{
TokenKind.OpenCaret => 3,
TokenKind.Ampersand => 2,
TokenKind.VerticalLine => 1,
Expand Down Expand Up @@ -1132,7 +1143,7 @@ private static bool TryParseBigInteger(string lexeme, out BigInteger value)
if (success && negative) value = -value;
return success;
}


/// <summary>
/// Create a text signature of this type. It should include all details which pertain to the binary
Expand Down Expand Up @@ -1179,7 +1190,7 @@ private StringBuilder TypeSignature(StringBuilder builder, Definition type)
{
case StructDefinition sd:
builder.Append('{');

foreach (var (f, i) in sd.Fields.Enumerated())
{
if (i > 0)
Expand Down

0 comments on commit a2a15d6

Please sign in to comment.