void ParseTestCaseHeading(Actor actor, TokenRange toks) { actor.isStatic = true; // The parameter(s) to the TEST_CASE macro are opaque to the actor compiler TokenRange paramRange = toks.Last(NonWhitespace) .Assert("Unexpected tokens after test case parameter list.", t => t.Value == ")" && t.ParenDepth == toks.First().ParenDepth) .GetMatchingRangeIn(toks); actor.testCaseParameters = str(paramRange); actor.name = "flowTestCase" + toks.First().SourceLine; actor.parameters = new VarDeclaration[] { }; actor.returnType = "Void"; }
void ParseActorHeading(Actor actor, TokenRange toks) { var template = toks.First(NonWhitespace); if (template.Value == "template") { var templateParams = range(template.Position + 1, toks.End) .First(NonWhitespace) .Assert("Invalid template declaration", t => t.Value == "<") .GetMatchingRangeIn(toks); actor.templateFormals = SplitParameterList(templateParams, ",") .Select(p => ParseVarDeclaration(p)) //< SOMEDAY: ? .ToArray(); toks = range(templateParams.End + 1, toks.End); } var staticKeyword = toks.First(NonWhitespace); if (staticKeyword.Value == "static") { actor.isStatic = true; toks = range(staticKeyword.Position + 1, toks.End); } var uncancellableKeyword = toks.First(NonWhitespace); if (uncancellableKeyword.Value == "UNCANCELLABLE") { actor.isUncancellable = true; toks = range(uncancellableKeyword.Position + 1, toks.End); } // Find the parameter list TokenRange paramRange = toks.Last(NonWhitespace) .Assert("Unexpected tokens after actor parameter list.", t => t.Value == ")" && t.ParenDepth == toks.First().ParenDepth) .GetMatchingRangeIn(toks); actor.parameters = SplitParameterList(paramRange, ",") .Select(p => ParseVarDeclaration(p)) .ToArray(); var name = range(toks.Begin, paramRange.Begin - 1).Last(NonWhitespace); actor.name = name.Value; // SOMEDAY: refactor? var returnType = range(toks.First().Position + 1, name.Position).SkipWhile(Whitespace); var retToken = returnType.First(); if (retToken.Value == "Future") { var ofType = returnType.Skip(1).First(NonWhitespace).Assert("Expected <", tok => tok.Value == "<").GetMatchingRangeIn(returnType); actor.returnType = str(NormalizeWhitespace(ofType)); toks = range(ofType.End + 1, returnType.End); } else if (retToken.Value == "void" /* && !returnType.Skip(1).Any(NonWhitespace)*/) { actor.returnType = null; toks = returnType.Skip(1); } else { throw new Error(actor.SourceLine, "Actor apparently does not return Future<T>"); } toks = toks.SkipWhile(Whitespace); if (!toks.IsEmpty) { if (toks.Last().Value == "::") { actor.nameSpace = str(range(toks.Begin, toks.End - 1)); } else { Console.WriteLine("Tokens: '{0}' {1} '{2}'", str(toks), toks.Count(), toks.Last().Value); throw new Error(actor.SourceLine, "Unrecognized tokens preceding parameter list in actor declaration"); } } }
IEnumerable <Token> NormalizeWhitespace(IEnumerable <Token> tokens) { bool inWhitespace = false; bool leading = true; foreach (var tok in tokens) { if (!tok.IsWhitespace) { if (inWhitespace && !leading) { yield return new Token { Value = " " } } ; inWhitespace = false; yield return(tok); leading = false; } else { inWhitespace = true; } } } void ParseDeclaration(TokenRange tokens, out Token name, out TokenRange type, out TokenRange initializer, out bool constructorSyntax) { initializer = null; TokenRange beforeInitializer = tokens; constructorSyntax = false; Token equals = AngleBracketParser.NotInsideAngleBrackets(tokens) .FirstOrDefault(t => t.Value == "=" && t.ParenDepth == tokens.First().ParenDepth); if (equals != null) { // type name = initializer; beforeInitializer = range(tokens.Begin, equals.Position); initializer = range(equals.Position + 1, tokens.End); } else { Token paren = AngleBracketParser.NotInsideAngleBrackets(tokens) .FirstOrDefault(t => t.Value == "("); if (paren != null) { // type name(initializer); constructorSyntax = true; beforeInitializer = range(tokens.Begin, paren.Position); initializer = range(paren.Position + 1, tokens.End) .TakeWhile(t => t.ParenDepth > paren.ParenDepth); } } name = beforeInitializer.Last(NonWhitespace); if (beforeInitializer.Begin == name.Position) { throw new Error(beforeInitializer.First().SourceLine, "Declaration has no type."); } type = range(beforeInitializer.Begin, name.Position); } VarDeclaration ParseVarDeclaration(TokenRange tokens) { Token name; TokenRange type, initializer; bool constructorSyntax; ParseDeclaration(tokens, out name, out type, out initializer, out constructorSyntax); return(new VarDeclaration { name = name.Value, type = str(NormalizeWhitespace(type)), initializer = initializer == null ? "" : str(NormalizeWhitespace(initializer)), initializerConstructorSyntax = constructorSyntax }); }
void ParseActorHeading(Actor actor, TokenRange toks) { var template = toks.First(NonWhitespace); if (template.Value == "template") { var templateParams = range(template.Position + 1, toks.End) .First(NonWhitespace) .Assert("Invalid template declaration", t => t.Value == "<") .GetMatchingRangeIn(toks); actor.templateFormals = SplitParameterList(templateParams, ",") .Select(p => ParseVarDeclaration(p)) //< SOMEDAY: ? .ToArray(); toks = range(templateParams.End + 1, toks.End); } var attribute = toks.First(NonWhitespace); while (attribute.Value == "[") { var attributeContents = attribute.GetMatchingRangeIn(toks); var asArray = attributeContents.ToArray(); if (asArray.Length < 2 || asArray[0].Value != "[" || asArray[asArray.Length - 1].Value != "]") { throw new Error(actor.SourceLine, "Invalid attribute: Expected [[...]]"); } actor.attributes.Add("[" + str(NormalizeWhitespace(attributeContents)) + "]"); toks = range(attributeContents.End + 1, toks.End); attribute = toks.First(NonWhitespace); } var staticKeyword = toks.First(NonWhitespace); if (staticKeyword.Value == "static") { actor.isStatic = true; toks = range(staticKeyword.Position + 1, toks.End); } var uncancellableKeyword = toks.First(NonWhitespace); if (uncancellableKeyword.Value == "UNCANCELLABLE") { actor.SetUncancellable(); toks = range(uncancellableKeyword.Position + 1, toks.End); } // Find the parameter list TokenRange paramRange = toks.Last(NonWhitespace) .Assert("Unexpected tokens after actor parameter list.", t => t.Value == ")" && t.ParenDepth == toks.First().ParenDepth) .GetMatchingRangeIn(toks); actor.parameters = SplitParameterList(paramRange, ",") .Select(p => ParseVarDeclaration(p)) .ToArray(); var name = range(toks.Begin, paramRange.Begin - 1).Last(NonWhitespace); actor.name = name.Value; // SOMEDAY: refactor? var returnType = range(toks.First().Position + 1, name.Position).SkipWhile(Whitespace); var retToken = returnType.First(); if (retToken.Value == "Future") { var ofType = returnType.Skip(1).First(NonWhitespace).Assert("Expected <", tok => tok.Value == "<").GetMatchingRangeIn(returnType); actor.returnType = str(NormalizeWhitespace(ofType)); toks = range(ofType.End + 1, returnType.End); } else if (retToken.Value == "void" /* && !returnType.Skip(1).Any(NonWhitespace)*/) { actor.returnType = null; toks = returnType.Skip(1); } else { throw new Error(actor.SourceLine, "Actor apparently does not return Future<T>"); } toks = toks.SkipWhile(Whitespace); if (!toks.IsEmpty) { if (toks.Last().Value == "::") { actor.nameSpace = str(range(toks.Begin, toks.End - 1)); } else { Console.WriteLine("Tokens: '{0}' {1} '{2}'", str(toks), toks.Count(), toks.Last().Value); throw new Error(actor.SourceLine, "Unrecognized tokens preceding parameter list in actor declaration"); } } if (errorMessagePolicy.ActorsNoDiscardByDefault() && !actor.attributes.Contains("[[flow_allow_discard]]")) { if (actor.IsCancellable()) { actor.attributes.Add("[[nodiscard]]"); } } HashSet <string> knownFlowAttributes = new HashSet <string>(); knownFlowAttributes.Add("[[flow_allow_discard]]"); foreach (var flowAttribute in actor.attributes.Where(a => a.StartsWith("[[flow_"))) { if (!knownFlowAttributes.Contains(flowAttribute)) { throw new Error(actor.SourceLine, "Unknown flow attribute {0}", flowAttribute); } } actor.attributes = actor.attributes.Where(a => !a.StartsWith("[[flow_")).ToList(); }