Example #1
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="original"></param>
        /// <completionlist cref=""/>
        /// <example></example>
        /// <include file='' path='[@name=""]'/>
        /// <permission cref=""></permission>
        /// <remarks></remarks>
        /// <see cref=""/>
        /// <seealso cref=""/>
        /// <typeparam></typeparam>
        public Doc()
        {
            def = GenLanguageDef.Empty.With(
                CommentStart: null,
                CommentEnd: null,
                CommentLine: null,
                NestedComments: false,
                IdentStart: letter,
                IdentLetter: alphaNum,
                OpStart: oneOf(@"!%&*+.<=>?@/\^|-~"),
                OpLetter: oneOf(@"!%&*+.<=>?@/\^|-~"),
                ReservedOpNames: List <string>(),
                ReservedNames: List <string>(
                    "summary", "remarks", "param", "example", "permission",
                    "include", "completionlist", "see", "seealso"),
                CaseSensitive: true
                );

            lexer = makeTokenParser(def);
        }
        public ProcessSystemConfigParser(string nodeName, Types typeDefs, IEnumerable <FuncSpec> strategyFuncs)
        {
            strategyFuncs     = strategyFuncs ?? new FuncSpec[0];
            this.nodeName     = nodeName;
            this.types        = typeDefs;
            this.clusterType  = types.Register(BuildClusterType());
            this.processType  = types.Register(BuildProcessType());
            this.routerType   = types.Register(BuildRouterType());
            this.strategyType = types.Register(BuildStrategySpec(types, strategyFuncs));

            var opChars = ":!%&*+.<=>\\^|-~";

            // Process config definition
            Definition = GenLanguageDef.Empty.With(
                CommentStart: "/*",
                CommentEnd: "*/",
                CommentLine: "//",
                NestedComments: true,
                OpStart: oneOf(opChars),
                OpLetter: oneOf(opChars),
                IdentStart: letter,
                IdentLetter: either(alphaNum, oneOf("-_")),
                ReservedNames: List("if", "then", "else").AddRange(types.AllInOrder.Map(t => t.Name)),
                ReservedOpNames: List("-", "+", "/", "*", "==", "!=", ">", "<", "<=", ">=", "||", "&&", "|", "&", "%", "!", "~", "^")
                );

            // Token parser
            // This builds the standard token parser from the definition above
            TokenParser   = makeTokenParser(Definition);
            identifier    = TokenParser.Identifier;
            stringLiteral = TokenParser.StringLiteral;
            integer       = TokenParser.Integer;
            floating      = TokenParser.Float;
            natural       = TokenParser.Natural;
            whiteSpace    = TokenParser.WhiteSpace;
            symbol        = TokenParser.Symbol;
            reserved      = TokenParser.Reserved;
            reservedOp    = TokenParser.ReservedOp;

            // Binary operator parser
            Func <string, Assoc, Operator <ValueToken> > binary =
                (name, assoc) =>
                Operator.Infix(assoc,
                               from x in reservedOp(name)
                               select ValueToken.BinaryOp(name));

            // Prefix operator parser
            Func <string, Operator <ValueToken> > prefix =
                (name) =>
                Operator.Prefix(
                    from x in reservedOp(name)
                    select ValueToken.PrefixOp(name));

            // Postfix operator parser
            Func <string, Operator <ValueToken> > postfix =
                (name) =>
                Operator.Postfix(
                    from x in reservedOp(name)
                    select ValueToken.PostfixOp(name));

            // Operator table
            Operator <ValueToken>[][] table =
            {
                new [] { prefix("-"), prefix("+"), prefix("!") },
                new [] { binary("*",  Assoc.Left), binary("/", Assoc.Left), binary("%", Assoc.Left)},
                new [] { binary("+",  Assoc.Left), binary("-", Assoc.Left)},
                new [] { binary("<",  Assoc.Left), binary(">", Assoc.Left), binary(">=", Assoc.Left), binary("<=", Assoc.Left)},
                new [] { binary("==", Assoc.Left), binary("!=", Assoc.Left)},
                new [] { binary("&",  Assoc.Left) },
                new [] { binary("^",  Assoc.Left) },
                new [] { binary("|",  Assoc.Left) },
                new [] { binary("&&", Assoc.Left) },
                new [] { binary("||", Assoc.Left) },
            };


            Func <Option <string>, TypeDef, Parser <ValueToken> > valueInst = null;
            Parser <TypeDef> typeName = null;

            // ProcessId parser
            processId =
                token(
                    from xs in many1(choice(lower, digit, oneOf("@/[,-_]{}: ")))
                    let r                     = (new string(xs.ToArray())).Trim()
                                      let pid = ProcessId.TryParse(r)
                                                from res in pid.Match(
                        Right: x => result(x),
                        Left: ex => failure <ProcessId>($"{ex.Message} '({r})'"))
                                                select res);

            // ProcessName parser
            processName =
                token(
                    from o in symbol("\"")
                    from xs in many1(choice(lower, digit, oneOf("@/[,-_]{.}: ")))
                    from c in symbol("\"")
                    let r                 = (new string(xs.ToArray())).Trim()
                                    let n = ProcessName.TryParse(r)
                                            from res in n.Match(
                        Right: x => result(x),
                        Left: ex => failure <ProcessName>(ex.Message))
                                            select res);

            // Attribute parser
            Func <string, Parser <ValueToken>, Parser <NamedValueToken> > attr =
                (name, p) =>
                from x in reserved(name)
                from _ in symbol("=")
                from v in p
                select new NamedValueToken(name, v, None);

            // Type name parser
            Parser <Type> type =
                from x in letter
                from xs in many1(choice(letter, ch('.'), ch('_')))
                select Type.GetType(new string(x.Cons(xs).ToArray()));

            var directive    = types.Directive.ValueParser(this).Map(x => (Directive)x);
            var msgDirective = types.MessageDirective.ValueParser(this).Map(x => (MessageDirective)x);

            Parser <State <Exception, Option <Directive> > > exceptionDirective =
                from b in symbol("|")
                from t in token(type)
                from a in symbol("->")
                from d in directive
                select Strategy.With(d, t);

            Parser <State <Exception, Option <Directive> > > otherwiseDirective =
                from b in symbol("|")
                from t in symbol("_")
                from a in symbol("->")
                from d in directive
                select Strategy.Otherwise(d);

            Parser <State <Directive, Option <MessageDirective> > > matchMessageDirective =
                from b in symbol("|")
                from d in token(directive)
                from a in symbol("->")
                from m in token(msgDirective)
                select Strategy.When(m, d);

            Parser <State <Directive, Option <MessageDirective> > > otherwiseMsgDirective =
                from b in symbol("|")
                from t in symbol("_")
                from a in symbol("->")
                from d in token(msgDirective)
                select Strategy.Otherwise(d);

            // Strategy exception -> directive parser
            match =
                from _ in attempt(reserved("match"))
                from direx in many(attempt(exceptionDirective))
                from other in optional(otherwiseDirective)
                let dirs = direx.Append(other.AsEnumerable()).ToArray()
                           from ok in dirs.Length > 0
                    ? result(dirs)
                    : failure <State <Exception, Option <Directive> >[]>("'match' must be followed by at least one clause")
                           select new ValueToken(types.Get("strategy"), Strategy.Match(dirs));

            Parser <State <StrategyContext, Unit> > redirectMatch =
                from direx in many(attempt(matchMessageDirective))
                from other in optional(otherwiseMsgDirective)
                let dirs = direx.Append(other.AsEnumerable()).ToArray()
                           from ok in dirs.Length > 0
                    ? result(dirs)
                    : failure <State <Directive, Option <MessageDirective> >[]>("'redirect when' must be followed by at least one clause")
                           select Strategy.Redirect(dirs);

            // Strategy directive -> message-directive matching parser
            redirect =
                from n in attempt(reserved("redirect"))
                from t in either(attempt(symbol(":")), reserved("when"))
                from r in t == ":"
                   ? from d in token(msgDirective)
                select Strategy.Redirect(d)
                   : redirectMatch
                select new ValueToken(types.Get("strategy"), r);

            // Type name parser
            typeName = choice(types.AllInOrder.Map(t => reserved(t.Name).Map(_ => t)).ToArray());

            // cluster.<alias>.<property> parser -- TODO: generalise
            Parser <ValueToken> clusterVar =
                attempt(
                    from _ in reserved("cluster")
                    from tup in either(
                        attempt(
                            from d1 in symbol(".")
                            from alias in identifier
                            from d2 in symbol(".")
                            from id in identifier
                            select Tuple(alias, id)),
                        attempt(
                            from d in symbol(".")
                            from id in identifier
                            select Tuple("", id)))
                    from sub in optional(from d2 in symbol(".")
                                         from id2 in identifier
                                         select id2).Map(x => x.IfNone("value"))
                    from state in getState <ParserState>()                              // TODO: This can be generalised into an object walking system
                    from v in state.Clusters.Find(tup.Item1).Match(                     //       where an object (in this case the cluster), is in 'scope'
                        Some: cluster =>                                                //       and recursive walking of the dot operator will find the
                        cluster.Settings.Find(tup.Item2).Match(                         //       value.
                            Some: local => result(local),
                            None: () => failure <ValueToken>($"unknown identifier 'cluster.{tup.Item2}'")),
                        None: () => failure <ValueToken>($"cluster.{tup.Item2} used when a cluster with a node-name attribute set to '{nodeName}' hasn't been defined.  Or the cluster called '{nodeName}' exists and is aliased, and you're not providing the variable in the form: cluster.<alias>.<property-name>"))
                    select v
                    );

            // Variable of unknown type parser
            Parser <ValueToken> variable =
                either(
                    clusterVar,
                    attempt(
                        from id in identifier
                        from state in getState <ParserState>()
                        from v in state.Local(id).Match(
                            Some: v => result(v),
                            None: () => failure <ValueToken>($"unknown identifier '{id}' "))
                        select v
                        )
                    );

            // Variable of known type parser
            Func <TypeDef, Parser <ValueToken> > variableOfType =
                expect =>
                from v in variable
                from r in v.Type == expect
                        ? result(v)
                        : expect.Convert(v).Match(
                    Some: x => result(x),
                    None: () => failure <ValueToken>($"type mismatch {v.Type} found, expected {expect}")
                    )
                select r;

            Parser <ValueToken> ternary =
                token(
                    from __ in attempt(reserved("if"))
                    from eb in exprUnknownType
                    from ex in eb.Type == types.Bool
                        ? result(eb)
                        : failure <ValueToken>("ternary expressions must evaluate to a boolean value")
                    from th in reserved("then")
                    from te in exprUnknownType
                    from el in reserved("else")
                    from ee in exprUnknownType
                    select((bool)ex.Value) ? te : ee
                    );

            valueUntyped = choice(
                variable,
                choice(types.AllInOrder.Map(typ => attempt(typ.ValueParser(this).Map(val => new ValueToken(typ, typ.Ctor(None, val))))).ToArray())
                );

            // Expression term parser
            Parser <ValueToken> termUnknownType =
                choice(
                    parens(lazyp(() => exprUnknownType)),
                    ternary,
                    valueUntyped);

            // Expression parser
            exprUnknownType =
                buildExpressionParser(table, termUnknownType);

            // Variable declaration parser
            valueDef =
                from typ in either(
                    attempt(reserved("let")).Map(x => Option <TypeDef> .None),
                    typeName.Map(Option <TypeDef> .Some)
                    )
                from arr in optional(symbol("[]"))
                from _ in arr.IsSome && typ.IsNone
                    ? failure <Unit>("when declaring an array you must specify the type, you can't use 'let'")
                    : result <Unit>(unit)
                from id in identifier.label("identifier")
                from alias in optional(
                    from a_ in reserved("as")
                    from nm in identifier
                    select nm)
                from __ in symbol(":")
                from v in arr.IsSome
                    ? either(
                    attempt(valueInst(alias, TypeDef.Map(() => typ.IfNone(TypeDef.Unknown)))),
                    valueInst(alias, TypeDef.Array(() => typ.IfNone(TypeDef.Unknown))))
                    : typ.Map(t => expr(alias, t))
                .IfNone(() => exprUnknownType)
                from nv in result(new NamedValueToken(id, v, alias))
                from state in getState <ParserState>()
                from res in state.LocalExists(id)
                    ? failure <ParserState>($"A value with the name '{id}' already declared")
                    : result(state.AddLocal(id, v))
                from ___ in setState(res)
                select nv;

            // Value or variable parser
            valueInst = (alias, typ) => either(variableOfType(typ), typ.ValueParser(this).Map(value => new ValueToken(typ, typ.Ctor(alias, value))));

            // Expression term parser
            term =
                (alias, expected) =>
                choice(
                    parens(lazyp(() => expr(alias, expected))),
                    valueInst(alias, expected),
                    from val in exprUnknownType
                    from res in val.Type == expected
                            ? result(val)
                            : failure <ValueToken>($"expression must evaluate to {expected}, it actually evaluates to {val.Type}")
                    select res
                    );

            // Expression parser
            expr =
                (alias, expected) =>
                buildExpressionParser(table, term(alias, expected));

            // Parses a named argument: name = value
            namedArgument =
                (settingName, spec) =>
                attempt(token(attr(spec.Name, expr(None, spec.Type()))));

            // Parses a single non-named argument
            argument =
                (settingName, spec) =>
                attempt(token(expr(None, spec.Type()).Map(x => new NamedValueToken(spec.Name, x, None))));

            // Parses many arguments, wrapped in ( )
            argumentMany =
                (settingName, spec) =>
                from a in commaSep1(choice(spec.Map(arg => namedArgument(settingName, arg))))
                from r in a.Count == spec.Length
                        ? result(a)
                        : failure <Seq <NamedValueToken> >("Invalid arguments for " + settingName)
                select r;

            // Parses the arguments for a setting
            arguments =
                (settingName, spec) =>
                spec.Length == 0
                        ? failure <Seq <NamedValueToken> >("Invalid arguments spec, has zero arguments")
                        : spec.Length == 1
                            ? from a in argument(settingName, spec.Head())
                select SeqOne(a)
                            : argumentMany(settingName, spec);

            // Declare the global type
            var globalType = new TypeDef("global", (_, x) => x, typeof(Lst <NamedValueToken>), nodeName, 0);

            // Global namespace
            parser = from ws in whiteSpace
                     from __ in setState(ParserState.Empty)
                     from ss in globalType.ValueParser(this)
                     select(Lst <NamedValueToken>) ss;
        }
Example #3
0
        static ScriptParser()
        {
            // All characters that can be operators
            var opChars = ":!%&*+.<=>\\^|-~()[].";

            // Defines the components of the scripting language
            var definition = GenLanguageDef.Empty.With(
                CommentStart: "/*",
                CommentEnd: "*/",
                CommentLine: "//",
                NestedComments: true,
                OpStart: oneOf(opChars),
                OpLetter: oneOf(opChars),
                IdentStart: letter,
                IdentLetter: either(alphaNum, oneOf("-_")),
                ReservedNames: List("log", "fail", "Sum", "true", "false", "unit"),
                ReservedOpNames: List(";", "&&", "&", "-", "+", "/", "*", "==", "!=",
                                      "=", "<-", "<<", ">>", ">", "<", "<=", ">=",
                                      "=>", "||", "|", ",")
                );

            // Takes the definition and builds a set of core parsers that
            // can be used to build more complex parsers.
            lexer = makeTokenParser(definition);

            // Take some local copies of the lexer parsers for ease of use later
            charlit = lexer.CharLiteral;
            ident   = either(
                lexer.Identifier,
                from t in token(letter)
                from _ in notFollowedBy(letter)
                select t.ToString());
            reserved   = lexer.Reserved;
            reservedOp = lexer.ReservedOp;
            symbol     = lexer.Symbol;
            whiteSpace = lexer.WhiteSpace; // This incidentally will also strip comments
            integer    = lexer.Integer;
            floating   = lexer.Float;
            stringlit  = lexer.StringLiteral;

            // Helper method that takes an operator string and returns a Func
            // that makes it easy to build ScriptExprs that represent binary
            // operators
            Func <ScriptExpr, ScriptExpr, ScriptExpr> BinaryOp(string op) =>
            (ScriptExpr lhs, ScriptExpr rhs) =>
            op == "-" ? Binary(lhs, rhs, "-")
                    : op == "+" ? Binary(lhs, rhs, "+")
                    : op == "/" ? Binary(lhs, rhs, "/")
                    : op == "*" ? Binary(lhs, rhs, "*")
                    : op == "==" ? BooleanBinary(lhs, rhs, "==")
                    : op == "!=" ? BooleanBinary(lhs, rhs, "!=")
                    : op == "=" ? Binary(lhs, rhs, "=")
                    : op == "<-" ? Binary(lhs, rhs, "<-")
                    : op == ">" ? BooleanBinary(lhs, rhs, ">")
                    : op == "<" ? BooleanBinary(lhs, rhs, "<")
                    : op == ">=" ? BooleanBinary(lhs, rhs, ">=")
                    : op == "<=" ? BooleanBinary(lhs, rhs, "<=")
                    : op == "&&" ? BooleanBinary(lhs, rhs, "&&")
                    : op == "||" ? BooleanBinary(lhs, rhs, "||")
                    : op == "%" ? Binary(lhs, rhs, "%")
                    : op == "??" ? Binary(lhs, rhs, "??")
                    : op == ";" ? Binary(lhs, rhs, ";")
                    : op == "," ? Args(lhs, rhs)
                    : throw new NotSupportedException();

            // Helper method that takes an operator string and returns a Func
            // that makes it easy to build ScriptExprs that represent unary
            // prefix operators
            Func <ScriptExpr, ScriptExpr> PrefixOp(string op) =>
            (ScriptExpr rhs) =>
            op == "!" ? BooleanPrefix(rhs, "!")
                    : op == "-" ? Prefix(rhs, "-")
                    : op == "+" ? rhs
                    : throw new NotSupportedException();

            // Binary operator parser definition - this is used in the operators table
            // to define precendence and associativity.
            Operator <ScriptExpr> binary(string name, Assoc assoc) =>
            Operator.Infix(assoc,
                           from x in reservedOp(name)
                           select BinaryOp(name));

            // Unary prefix operator parser definition - this is used in the operators
            // table to define precendence and associativity.
            Operator <ScriptExpr> prefix(string name) =>
            Operator.Prefix(
                from x in reservedOp(name)
                select PrefixOp(name));

            // Operator precedence and associativity table
            Operator <ScriptExpr>[][] operators =
            {
                new [] { prefix("-"),  prefix("+"),  prefix("!")  },
                new [] { binary("*",   Assoc.Left),  binary("/", Assoc.Left), binary("%", Assoc.Left)},
                new [] { binary("+",   Assoc.Left),  binary("-", Assoc.Left)},
                new [] { binary("<<",  Assoc.Left),  binary(">>", Assoc.Left)},
                new [] { binary("<",   Assoc.Left),  binary(">", Assoc.Left), binary(">=", Assoc.Left), binary("<=", Assoc.Left)},
                new [] { binary("==",  Assoc.Left),  binary("!=", Assoc.Left)},
                new [] { binary("&",   Assoc.Left) },
                new [] { binary("|",   Assoc.Left) },
                new [] { binary("&&",  Assoc.Left) },
                new [] { binary("||",  Assoc.Left) },
                new [] { binary("??",  Assoc.Left) },
                new [] { binary(">>=", Assoc.Right) },
                new [] { binary("?",   Assoc.Left) },
                new [] { binary(":",   Assoc.Right) },
                new [] { binary("=",   Assoc.Right), binary("<-", Assoc.Right)},
                new [] { binary(".",   Assoc.Right) },
                new [] { binary(",",   Assoc.Right) },
                new [] { binary("=>",  Assoc.Right) },
                new [] { binary(";",   Assoc.Right) },
            };

            Parser <ScriptExpr> expr     = null;
            Parser <ScriptExpr> lazyExpr = lazyp(() => expr);

            // Constant or interpolated string parser
            var interpStr = from str in attempt(stringlit).label("string literal")
                            from res2 in (str.Contains('{') && str.Contains('}'))
                                ? from istr in result(Interpolate.Parser(str.ToPString()))
                            from res in istr.IsFaulted
                                      ? failure <ScriptExpr>(istr.Reply.Error.Msg)
                                      : result(istr.Reply.Result)
                            select res
                                : result(ConstString(str))
                            select res2;

            // Constant parser
            var constant = choice(
                attempt(integer.Map(Const).label("integer")),
                attempt(charlit.Map(ConstChar).label("char literal")),
                attempt(interpStr),
                attempt(floating.Map(Const).label("float")),
                attempt(symbol("true").Map(_ => Const(true)).label("true")),
                symbol("false").Map(_ => Const(false)).label("false"));

            // Function invocation parser
            var invoke = from id in ident
                         from ar in either(
                attempt(symbol("()")).Map(_ => Seq <ScriptExpr>()),
                from op in symbol("(")
                from args in lazyExpr
                from cl in symbol(")")
                select FlattenTuple(args))
                         select Invoke(id, ar);

            // log function parser
            var log = from _ in symbol("log")
                      from o in symbol("(")
                      from m in lazyExpr
                      from c in symbol(")")
                      select Log(m);

            // fail function parser
            var fail = from _ in symbol("fail")
                       from o in symbol("(")
                       from m in lazyExpr
                       from c in symbol(")")
                       select Fail(m);

            // Term parser - this is the main building block for the expression parser
            //               all language terms must be definied here.
            var term =
                choice(
                    attempt(log),
                    attempt(fail),
                    attempt(invoke),
                    attempt(constant),
                    attempt(ident).Map(Ident),
                    token(lexer.Parens(lazyExpr)).Map(Parens));

            // This takes the operator precedence and associativity table and the term
            // parser and builds a full expression parser that deals with all of the
            // complex rules over precedence and associativity.  This is a wonderful
            // function that saves lives.
            expr = buildExpressionParser(operators.Reverse().ToArray(), term);

            // This is the final parser.  Because the tokens and the symbols all strip
            // the space *after* their content has been parsed, the final parser must
            // strip the space *before* the first token.  So, that's what this does,
            // removes the space, parses the expression, then it expects an end-of-file
            parser = from ws in whiteSpace
                     from ex in expr
                     from __ in eof
                     select ex;
        }
Example #4
0
        public Reader(Query <Q> alg)
        {
            this.alg = alg;
            lexer    = makeTokenParser(GenLanguageDef.Empty);

            Parser <Seq <char> > toend(Parser <char> a) => manyUntil(a, ch(';'));

            var floating =
                from x in asString(many1(digit))
                from y in either(attempt(from _ in either(attempt(ch('.')), ch(','))
                                         from y in asString(many1(digit))
                                         select(y)),
                                 result("0"))
                let opt = parseDouble($"{x},{y}")
                          from res in opt.Match(
                    x => result(x),
                    () => failure <double>("not a valid number"))
                          select(res);

            searchName =
                from _    in str("find")
                from __   in spaces
                from ___  in str("name")
                from ____ in spaces
                from name in asString(toend(anyChar))
                select(alg.Name(name));

            searchAll =
                from _ in str("find")
                from __ in spaces
                from ___ in str("all")
                from ____ in ch(';')
                select(alg.All());


            searchFuzzyName =
                from _      in str("find")
                from __     in spaces
                from ___    in str("fuzzy")
                from ____   in spaces
                from _____  in str("name")
                from ______ in spaces
                from name   in asString(toend(anyChar))
                select(alg.FuzzyName(name));

            Func <string, Parser <string> > findEarningX = p =>
                                                           from _       in str("find")
                                                           from __      in spaces
                                                           from ___     in str("earning")
                                                           from ____    in spaces
                                                           from _____   in str(p)
                                                           from ______  in spaces
                                                           from _______ in str("than")
                                                           select("");

            searchEarningMore =
                from _      in findEarningX("more")
                from __     in spaces
                from salary in floating
                from ___    in ch(';')
                select(alg.EarningMore(salary));

            searchEarningLess =
                from _      in findEarningX("less")
                from __     in spaces
                from salary in floating
                from ___    in ch(';')
                select(alg.EarningLess(salary));

            searchEarning =
                from _      in str("find")
                from __     in spaces
                from ___    in str("earning")
                from ____   in spaces
                from salary in floating
                select(alg.Earning(salary));

            newEntryWithId =
                from _        in str("add")
                from __       in spaces
                from ___      in str("earning")
                from ____     in spaces
                from salary   in floating
                from _____    in spaces
                from ______   in str("id")
                from _______  in spaces
                from ido      in  asInteger(many1(digit))
                from id       in ido.Match(
                    x => result(x),
                    () => failure <int>(""))
                from ________   in spaces
                from _________  in str("name")
                from __________ in spaces
                from name     in asString(toend(anyChar))
                select(alg.NewEntryWithId(name, id, salary));

            newEntry =
                from _       in str("add")
                from __      in spaces
                from ___     in str("earning")
                from ____    in spaces
                from salary  in floating
                from _____   in spaces
                from ______  in str("name")
                from _______ in spaces
                from name    in asString(toend(anyChar))
                select(alg.NewEntry(name, salary));

            removeEntry =
                from _       in str("remove")
                from __      in spaces
                from ___     in str("id")
                from ____    in spaces
                from id      in lexer.Integer
                from _____   in spaces
                from ______  in str("name")
                from _______ in spaces
                from name    in asString(toend(anyChar))
                select(alg.RemoveEntry(name, id));

            save =
                from _        in str("save")
                from __       in spaces
                from filename in asString(many1(alphaNum))
                from ext      in str(".txt")
                from ___      in ch(';')
                select(alg.Save(filename + ext));

            load =
                from _        in str("load")
                from __       in spaces
                from filename in asString(many1(alphaNum))
                from ext      in str(".txt")
                from ___      in ch(';')
                select(alg.Load(filename + ext));

            clear =
                from _ in str("clear")
                from __ in ch(';')
                select(alg.Clear());
        }