public static IArgument Function(CharSource source, ref char chr, Dictionary <string, IFunction> funcs) { // Arrive here having seen '(' if (!source.AdvanceWhiteSpace(out chr)) { throw new FinalCharacterException("Expected a function name"); } var name = Arguments.Single(source, ref chr, funcs); if (!(name is NameArgument nameArg)) { throw new InvalidArgumentException($"Function name type error: Type = {name.GetType().Name}, Value = {name.ToString()}"); } if (!funcs.TryGetValue(nameArg.Value, out var func)) { throw new InvalidArgumentException($"Function does not exist: \"{nameArg.Value}\""); } // Get next character: if (!source.SkipWhiteSpace(ref chr)) { throw new FinalCharacterException("Expected closing ')'"); } var funcArg = new FunctionArgument() { Call = new FunctionCall(0) // Line number doesn't really matter, as this isn't a whole statement { Function = func } }; if (chr == ':') { // Arguments to go with it if (!source.AdvanceWhiteSpace(out chr)) { throw new FinalCharacterException("Expected argument list"); } funcArg.Call.Arguments = Arguments.Multiple(source, ref chr, funcs); // Get closing bracket if (!source.SkipWhiteSpace(ref chr)) { throw new FinalCharacterException("Expected closing ')'"); } else if (chr != ')') { throw new InvalidCharacterException($"Expected closing ')': found '{chr}'"); } } else if (chr != ')') { throw new InvalidCharacterException($"Expected closing ')' or arguments (':'): found '{chr}'"); } source.Advance(out chr); return(funcArg); }
public static ArgumentList Multiple(CharSource source, ref char chr, Dictionary <string, IFunction> funcs) { var args = new ArgumentList(); // Typically get here having seen nothing or the first character already // Running out of text here is not an error, unless specified as more to come while (source.SkipWhiteSpace(ref chr)) { var arg = Single(source, ref chr, funcs); args.Add(arg); if (!source.SkipWhiteSpace(ref chr)) { return(args); } else if (chr != ',') { return(args); } source.Advance(out chr); } // No need to throw here, as if more expected single argument parsing will catch return(args); }
public static Executable Parse(CharSource source, Dictionary <string, IFunction> funcs) { // Get to first character var exec = new Executable(); if (!source.Advance(out var chr)) { return(exec); } // Always ends on first character of next statement, if possible while (source.SkipWhiteSpace(ref chr)) { var statement = Statement(source, ref chr, funcs); exec.Add(statement); } return(exec); }