- using System.Collections.Generic;
- using Ink.Parsed;
- using System.Linq;
- namespace Ink
- {
- public partial class InkParser
- {
- protected class NameWithMetadata {
- public string name;
- public Runtime.DebugMetadata metadata;
- }
- protected class FlowDecl
- {
- public Identifier name;
- public List<FlowBase.Argument> arguments;
- public bool isFunction;
- }
- protected Knot KnotDefinition()
- {
- var knotDecl = Parse(KnotDeclaration);
- if (knotDecl == null)
- return null;
- Expect(EndOfLine, "end of line after knot name definition", recoveryRule: SkipToNextLine);
- ParseRule innerKnotStatements = () => StatementsAtLevel (StatementLevel.Knot);
- var content = Expect (innerKnotStatements, "at least one line within the knot", recoveryRule: KnotStitchNoContentRecoveryRule) as List<Parsed.Object>;
- return new Knot (knotDecl.name, content, knotDecl.arguments, knotDecl.isFunction);
- }
- protected FlowDecl KnotDeclaration()
- {
- Whitespace ();
- if (KnotTitleEquals () == null)
- return null;
- Whitespace ();
- Identifier identifier = Parse(IdentifierWithMetadata);
- Identifier knotName;
- bool isFunc = identifier?.name == "function";
- if (isFunc) {
- Expect (Whitespace, "whitespace after the 'function' keyword");
- knotName = Parse(IdentifierWithMetadata);
- } else {
- knotName = identifier;
- }
- if (knotName == null) {
- Error ("Expected the name of the " + (isFunc ? "function" : "knot"));
- knotName = new Identifier { name = "" };
- }
- Whitespace ();
- List<FlowBase.Argument> parameterNames = Parse (BracketedKnotDeclArguments);
- Whitespace ();
-
- Parse(KnotTitleEquals);
- return new FlowDecl () { name = knotName, arguments = parameterNames, isFunction = isFunc };
- }
- protected string KnotTitleEquals()
- {
-
- var multiEquals = ParseCharactersFromString ("=");
- if (multiEquals == null || multiEquals.Length <= 1) {
- return null;
- } else {
- return multiEquals;
- }
- }
- protected object StitchDefinition()
- {
- var decl = Parse(StitchDeclaration);
- if (decl == null)
- return null;
- Expect(EndOfLine, "end of line after stitch name", recoveryRule: SkipToNextLine);
- ParseRule innerStitchStatements = () => StatementsAtLevel (StatementLevel.Stitch);
- var content = Expect(innerStitchStatements, "at least one line within the stitch", recoveryRule: KnotStitchNoContentRecoveryRule) as List<Parsed.Object>;
- return new Stitch (decl.name, content, decl.arguments, decl.isFunction );
- }
- protected FlowDecl StitchDeclaration()
- {
- Whitespace ();
-
- if (ParseString ("=") == null)
- return null;
-
- if (ParseString ("=") != null)
- return null;
- Whitespace ();
-
- bool isFunc = ParseString ("function") != null;
- if ( isFunc ) {
- Whitespace ();
- }
- Identifier stitchName = Parse(IdentifierWithMetadata);
- if (stitchName == null)
- return null;
- Whitespace ();
- List<FlowBase.Argument> flowArgs = Parse(BracketedKnotDeclArguments);
- Whitespace ();
- return new FlowDecl () { name = stitchName, arguments = flowArgs, isFunction = isFunc };
- }
- protected object KnotStitchNoContentRecoveryRule()
- {
-
- ParseUntil (KnotDeclaration, new CharacterSet ("="), null);
- var recoveredFlowContent = new List<Parsed.Object>();
- recoveredFlowContent.Add( new Parsed.Text("<ERROR IN FLOW>" ) );
- return recoveredFlowContent;
- }
- protected List<FlowBase.Argument> BracketedKnotDeclArguments()
- {
- if (ParseString ("(") == null)
- return null;
- var flowArguments = Interleave<FlowBase.Argument>(Spaced(FlowDeclArgument), Exclude (String(",")));
- Expect (String (")"), "closing ')' for parameter list");
-
-
- if (flowArguments == null) {
- flowArguments = new List<FlowBase.Argument> ();
- }
- return flowArguments;
- }
- protected FlowBase.Argument FlowDeclArgument()
- {
-
-
-
-
-
- var firstIden = Parse(IdentifierWithMetadata);
- Whitespace ();
- var divertArrow = ParseDivertArrow ();
- Whitespace ();
- var secondIden = Parse(IdentifierWithMetadata);
- if (firstIden == null && secondIden == null)
- return null;
- var flowArg = new FlowBase.Argument ();
- if (divertArrow != null) {
- flowArg.isDivertTarget = true;
- }
-
- if (firstIden != null && firstIden.name == "ref") {
- if (secondIden == null) {
- Error ("Expected an parameter name after 'ref'");
- }
- flowArg.identifier = secondIden;
- flowArg.isByReference = true;
- }
-
- else {
- if (flowArg.isDivertTarget) {
- flowArg.identifier = secondIden;
- } else {
- flowArg.identifier = firstIden;
- }
- if (flowArg.identifier == null) {
- Error ("Expected an parameter name");
- }
- flowArg.isByReference = false;
- }
- return flowArg;
- }
- protected ExternalDeclaration ExternalDeclaration()
- {
- Whitespace ();
- Identifier external = Parse(IdentifierWithMetadata);
- if (external == null || external.name != "EXTERNAL")
- return null;
- Whitespace ();
- var funcIdentifier = Expect(IdentifierWithMetadata, "name of external function") as Identifier ?? new Identifier();
- Whitespace ();
- var parameterNames = Expect (BracketedKnotDeclArguments, "declaration of arguments for EXTERNAL, even if empty, i.e. 'EXTERNAL "+funcIdentifier+"()'") as List<FlowBase.Argument>;
- if (parameterNames == null)
- parameterNames = new List<FlowBase.Argument> ();
- var argNames = parameterNames.Select (arg => arg.identifier?.name).ToList();
- return new ExternalDeclaration (funcIdentifier, argNames);
- }
- }
- }