1 using Mercury.Exceptions;
2 using Mercury.Nucleus.Trees;
5 using System.Collections.Generic;
6 using System.Globalization;
10 namespace Mercury.Interpreting
39 public static class BasicActions<T>
44 private static CultureInfo cinf = CultureInfo.InvariantCulture;
55 =
new ConvertAction<T, string, int>(
"ParseInteger",
56 x => {
int i;
return int.TryParse(x, NumberStyles.Integer, cinf, out i) ? i :
default(
int); });
63 =
new ConvertAction<T, string, double>(
"ParseReal",
64 x => {
double d;
return double.TryParse(x, NumberStyles.Float, cinf, out d) ? d :
default(
double); });
71 =
new ConvertAction<T, string, bool>(
"ParseBoolean",
72 x => {
bool b;
return bool.TryParse(x, out b) ? b :
default(
bool); });
78 =
new ConvertAction<T, double, int>(
"Round", x => Convert.ToInt32(Math.Round(x)));
81 =
new ConvertAction<T, double, int>(
"Ceiling", x => Convert.ToInt32(Math.Ceiling(x)));
84 =
new ConvertAction<T, double, int>(
"Floor", x => Convert.ToInt32(Math.Floor(x)));
87 =
new ConvertAction<T, int, double>(
"ToReal", x => Convert.ToDouble(x));
90 =
new ConvertAction<T, object, string>(
"String", x => x.ToString());
111 =
new OperationAction<T, double, double>(
"FDiv", (x, y) => x / y);
114 =
new OperationAction<T, int, int>(
"Mod", (x, y) => x % y);
120 =
new ConvertAction<T, object, bool>(
"IsNull", x => x == null, ArgumentType.Null);
123 =
new FoldingAction<T, bool, bool>(
"And", 2, (x, y) => x && y,
true);
126 =
new FoldingAction<T, bool, bool>(
"Or", 2, (x, y) => x && y,
false);
129 =
new ConvertAction<T, bool, bool>(
"Not", x => !x);
132 =
new OperationAction<T, bool, bool>(
"Xor", (x, y) => x ^ y);
138 =
new OperationAction<T, object, bool>(
"Eq", (x, y) => (x != null) && x.Equals(y),
ArgumentType.Null);
141 =
new OperationAction<T, object, bool>(
"Neq", (x, y) => (x == null) || !x.Equals(y),
ArgumentType.Null);
144 =
new OperationAction<T, double, bool>(
"Gr", (x, y) => x > y);
147 =
new OperationAction<T, double, bool>(
"Ls", (x, y) => x < y);
150 =
new OperationAction<T, double, bool>(
"Geq", (x, y) => x >= y);
153 =
new OperationAction<T, double, bool>(
"Leq", (x, y) => x <= y);
159 =
new ConstantAction<T, string>(
"Empty",
"");
165 =
new JoinAction<T>();
168 =
new ConcatAction<T>();
174 =
new FlattenAction<T>();
180 =
new ConvertAction<T, Symbol, string>(
"Name", x => x.Name);
183 =
new ConvertAction<T, Tree<Symbol>,
Symbol>(
"Symbol", x => x.Value);
186 =
new ConvertAction<T, Tree<Symbol>,
int>(
"Depth", x => x.Depth);
189 =
new ConvertAction<T, Tree<Symbol>,
int>(
"Leaves", x => x.LeavesCount);
196 =
new SubTreeAction<T>();
204 =
new ConvertAction<T, Tree<Symbol>,
string>(
"Preterminal", x =>
206 return ((x.Children.Count != 1)
207 || ((x[0].Value.Type & (SymbolType.Terminal | SymbolType.Epsilon)) == SymbolType.None))
208 ? null : x[0].Value.Name;
230 =
new SelectAction<T>();
238 =
new CaseAction<T>();
241 =
new EvaluateAction<T>();
248 =
new SimpleAction<T>();
251 =
new FailAction<T>();
260 =
new TryAction<T>();
273 =
new IdentityAction<T>();
282 =
new LetAction<T>();
290 =
new VarAction<T>();
296 =
new ArgsCountAction<T>();
299 =
new TraceAction<T>();
306 return new List<InterpreterAction<T>>()
308 ParseInteger, ParseReal, ParseBoolean,
309 Round, Ceiling, Floor, ToReal,
String,
310 Add, Sub, Mul, Div, Pow, FDiv, Mod,
311 IsNull, And, Or, Not, Xor, Eq, Neq, Gr, Ls, Geq, Leq,
312 Empty, Join, Concat, Flatten,
313 Name,
Symbol, Depth, Leaves, SubTree, Preterminal,
314 If, Select, Case, Eval, Simple, Fail, Try, Error,
315 Identity, Let, Var, ArgsCount, Trace
332 public static IReadOnlyDictionary<string,string>
GetAliases()
334 return new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
336 {
"ToString",
"String" },
338 {
"+",
"Add" }, {
"-",
"Sub" }, {
"*",
"Mul" }, {
"/",
"Div" },
339 {
"//",
"FDiv" }, {
"%",
"Mod" }, {
"**",
"Pow" },
340 {
"@",
"String" }, {
"++",
"Concat" }, {
"#",
"Var" },
341 {
"&",
"And" }, {
"|",
"Or" }, {
"^",
"Xor" }, {
"!",
"Not" },
342 {
"==",
"Eq" }, {
"/=",
"Neq" },
343 {
">",
"Gr" }, {
"<",
"Ls" }, {
">=",
"Geq"}, {
"<=",
"Leq" },
344 {
"$",
"Eval" }, {
"id",
"Identity" },
353 {
return new TraceAction<T>(writer){ Name = name }; }
369 public sealed
class OperationAction<T, U, V> : InterpreterAction<T, V>
372 private Func<U, U, V> f;
384 : base(name, Tuple.Create(2, 2),
385 new[] { Defaults.TypeToArgType<T,U>() | (flags &
ArgumentType.Flags) })
387 if (f == null)
throw new ArgumentNullException(
"f");
393 #region [ InterpreterAction ]
397 {
return f(arguments[0].Value, arguments[1].Value); }
415 public sealed
class FoldingAction<T, U, V> : InterpreterAction<T, V>
418 private Func<V, U, V> f;
434 : base(name, Tuple.Create(minargs, int.MaxValue),
435 new[] { Defaults.TypeToArgType<T, U>() | (flags &
ArgumentType.Flags) })
437 if (f == null)
throw new ArgumentNullException(
"f");
444 #region [ InterpreterAction ]
448 {
return arguments.Aggregate(s, (x, y) => f(x, y.Value)); }
461 public sealed
class ConvertAction<T, U, V> : InterpreterAction<T, V>
464 private Func<U, V> f;
476 : base(name, Tuple.Create(1, 1),
477 new[] { Defaults.TypeToArgType<T, U>() | (flags &
ArgumentType.Flags) })
479 if (f == null)
throw new ArgumentNullException(
"f");
485 #region [ InterpreterAction ]
489 {
return f((U) arguments[0].Data); }
500 public sealed
class ConstantAction<T, U> : InterpreterAction<T, U>
514 { this.value = value; }
518 #region [ InterpreterAction ]
539 public sealed
class ArithmeticAction<T> : GenericAction<T>
542 private Func<dynamic, dynamic, dynamic> f;
553 : base(name, Tuple.Create(2, int.MaxValue), new[] { ArgumentType.Integer | ArgumentType.Real })
555 if (f == null)
throw new ArgumentNullException(
"f");
561 #region [ GenericAction ]
565 return actual.All(x => x.HasFlag(ArgumentType.Integer))
566 ? ArgumentType.Integer | ArgumentType.Real
575 dynamic val = arguments[0].Value;
576 for (
int ix = 1; ix < arguments.Length; ++ix)
577 val = f(val, arguments[ix].Value);
579 }
catch (ArithmeticException ex)
593 internal class JoinAction<T> : InterpreterAction<T, string>
599 : base(
"Join", Tuple.Create(1, int.MaxValue), new[] { ArgumentType.String, ArgumentType.Any })
604 #region [ InterpreterAction ]
606 public override string Evaluate(Argument[] arguments,
RecursiveEval<T> eval,
607 InterpreterContext<T> context)
608 {
return string.Join(arguments[0].Data as string, arguments.Skip(1).Select(x => x.Data.ToString())); }
616 internal class ConcatAction<T> : InterpreterAction<T, string>
621 public ConcatAction()
622 : base(
"Concat", Tuple.Create(0, int.MaxValue), new[] { ArgumentType.Any })
627 #region [ InterpreterAction ]
629 public override string Evaluate(Argument[] arguments,
RecursiveEval<T> eval,
630 InterpreterContext<T> context)
631 {
return string.Concat(arguments.Select(x => x.Data.ToString())); }
639 internal class FlattenAction<T> : InterpreterAction<T, string>
644 public FlattenAction()
645 : base(
"Flatten", Tuple.Create(1, 2), new[] { ArgumentType.Tree, ArgumentType.Integer })
650 #region [ InterpreterAction ]
652 public override string Evaluate(Argument[] arguments,
RecursiveEval<T> eval,
653 InterpreterContext<T> context)
655 int maxdepth = arguments.Length == 1 ? -1 : arguments[1].Value;
656 return (arguments[0].Data as Tree<Symbol>).ToString(maxdepth);
665 internal class SubTreeAction<T> : InterpreterAction<T, Tree<Symbol>>
670 public SubTreeAction()
671 : base(
"SubTree", Tuple.Create(2, 2),
672 new[] { ArgumentType.Integer, ArgumentType.Tree })
677 #region [ InterpreterAction ]
679 public override Tree<Symbol> Evaluate(Argument[] arguments,
RecursiveEval<T> eval,
680 InterpreterContext<T> context)
682 int ix = arguments[0].Value;
683 var tr = arguments[1].Data as Tree<Symbol>;
685 return (0 > ix || ix >= tr.Children.Count) ? null : tr[ix];
694 internal class IdentityAction<T> : GenericAction<T>
699 public IdentityAction()
700 : base(
"Identity", Tuple.Create(1, 1), new[] { ArgumentType.Any })
705 #region [ GenericAction ]
708 {
return actual[0] & expected; }
711 InterpreterContext<T> context)
712 {
return arguments[0].Data; }
720 internal class LetAction<T> : GenericAction<T>
726 : base(
"Let", Tuple.Create(3, int.MaxValue),
727 new[] { ArgumentType.Any | ArgumentType.Lazy },
false)
732 #region [ GenericAction ]
736 if (actual.Length % 2 != 1)
return ArgumentType.None;
738 for (
int ix = 0; ix < actual.Length - 2; ix += 2)
739 if (!actual[ix].HasFlag(
ArgumentType.String))
return ArgumentType.None;
741 return actual[actual.Length - 1];
745 InterpreterContext<T> context)
747 for (
int ix = 0; ix < arguments.Length - 2; ix += 2)
749 var name = arguments[ix].Data as string;
751 if (context.bindings.ContainsKey(name))
754 context.bindings.Add(name, arguments[ix + 1]);
757 context.LogEntry(
"{0} values binded", arguments.Length / 2);
758 return arguments[arguments.Length - 1].Data;
767 internal class VarAction<T> : InterpreterAction<T, object>
773 : base(
"Var", Tuple.Create(1, 1), new[] { ArgumentType.String })
778 #region [ InterpreterAction ]
780 public override object Evaluate(Argument[] arguments,
RecursiveEval<T> eval,
781 InterpreterContext<T> context)
783 var name = arguments[0].Data as string;
786 if (!context.bindings.TryGetValue(name, out bval))
789 if ((bval.Type & context.reqtp) == ArgumentType.None)
792 context.LogEntry(
"value of {0} fetched", name);
802 internal class TryAction<T> : GenericAction<T>
808 : base(
"Try", Tuple.Create(1, 2), new[] { ArgumentType.Any | ArgumentType.Lazy })
813 #region [ GenericAction ]
816 {
return (actual.Length == 1 ? actual[0] : actual[0] & actual[1]) & expected; }
819 InterpreterContext<T> context)
822 {
return arguments[0].Data; }
825 context.LogEntryEx(
"EXCEPTION",
"'{0}' caught in '{1}'",
826 ex.Message, context.action);
827 return arguments.Length == 2 ? arguments[1].Data : null;
837 internal class IfAction<T> : GenericAction<T>
843 : base(
"If", Tuple.Create(3, int.MaxValue),
844 new[] { ArgumentType.Any | ArgumentType.Lazy },
false)
849 #region [ GenericAction ]
853 if (actual.Length % 2 != 1)
return ArgumentType.None;
856 for(
int ix = 0; ix < actual.Length - 1; ix += 2)
860 argtp &= actual[ix + 1];
863 return (argtp & actual[actual.Length - 1]) & expected;
867 InterpreterContext<T> context)
869 for (
int ix = 0; ix < arguments.Length - 1; ix += 2)
870 if ((arguments[ix].Data != null) && arguments[ix].Value)
871 return arguments[ix + 1].Data;
873 return arguments[arguments.Length - 1].Data;
882 internal class SelectAction<T> : GenericAction<T>
887 public SelectAction()
888 : base(
"Select", Tuple.Create(2, int.MaxValue),
889 new[] { ArgumentType.Integer, ArgumentType.Any | ArgumentType.Lazy })
894 #region [ GenericAction ]
897 {
return actual.Skip(2).Aggregate(actual[1], (x, y) => x & y) & expected; }
900 InterpreterContext<T> context)
902 int ix = arguments[0].Value;
903 context.LogEntry(
"selector value is '{0}'", ix);
904 return ((0 > ix) || (ix >= arguments.Length - 2)) ? arguments[1].Value : arguments[ix + 2].Data;
913 internal class CaseAction<T> : GenericAction<T>
919 : base(
"Case", Tuple.Create(2, int.MaxValue),
920 new[] { ArgumentType.Any, ArgumentType.Any | ArgumentType.Lazy },
926 #region [ GenericAction ]
930 if ((actual.Length % 2) == 1)
931 return ArgumentType.None;
936 for (
int ix = 0; ix < actual.Length; ix += 2)
939 restp &= actual[ix + 1];
942 return (valtp ==
ArgumentType.None) ? ArgumentType.None : restp & expected;
946 InterpreterContext<T> context)
948 var val = arguments[0].Data;
949 context.LogEntry(
"selector value is '{0}'", val ??
"null");
953 for (
int ix = 2; ix < arguments.Length; ix += 2)
954 if (val.Equals(arguments[ix].Data))
return arguments[ix + 1].Data;
957 return arguments[1].Data;
966 internal class ArgsCountAction<T> : InterpreterAction<T, int>
972 public ArgsCountAction()
973 : base(
"ArgsCount", Tuple.Create(0, int.MaxValue), new[] { ArgumentType.Any | ArgumentType.Lazy })
978 #region [ InterpreterAction ]
981 InterpreterContext<T> context)
982 {
return arguments.Length; }
990 internal class EvaluateAction<T> : InterpreterAction<T, T>
995 public EvaluateAction()
996 : base(
"Eval", Tuple.Create(1, 1), new[] { ArgumentType.Tree })
1001 #region [ InterpreterAction ]
1004 InterpreterContext<T> context)
1005 {
return eval(arguments[0].Data as Tree<Symbol>, context); }
1013 internal class FailAction<T> : GenericAction<T>
1019 : base(
"Fail", Tuple.Create(0, 0), new
ArgumentType[0])
1024 #region [ GenericAction ]
1027 {
return expected; }
1029 public override object Invoke(Argument[] arguments,
RecursiveEval<T> eval, InterpreterContext<T> context)
1038 internal class SimpleAction<T> : InterpreterAction<T, T>
1046 public SimpleAction()
1047 : base(
"Simple", Tuple.Create(1, 1), new[] { ArgumentType.Tree })
1052 #region [ InterpreterAction ]
1055 InterpreterContext<T> context)
1057 var val = arguments[0].Data as Tree<Symbol>;
1058 if ((val.Children.Count != 1) || (val.Children[0].Value.Type !=
SymbolType.Nonterminal))
1061 return eval(val.Children[0], context);
1070 internal class TraceAction<T> : GenericAction<T>
1075 private TextWriter writer;
1079 public TraceAction()
1083 public TraceAction(TextWriter writer)
1084 : base(
"Trace", Tuple.Create(2, int.MaxValue),
1085 new[] { ArgumentType.Any | ArgumentType.Lazy, ArgumentType.String, ArgumentType.Any })
1086 { this.writer = writer; }
1090 #region [ GenericAction ]
1093 {
return actual[0] & expected; }
1096 InterpreterContext<T> context)
1098 var value = arguments[0].Value;
1099 var msgc = string.Format(arguments[1].Value.ToString(), arguments.Skip(2).Select(x => x.Value.ToString()).ToArray());
1100 var msg = string.Format(
"{0} <ret {1}>", msgc, value == null ?
"null" :
"value");
1102 context.LogEntryEx(
"TRACE", msg);
1103 if (writer != null) writer.Write(msg);
ArithmeticAction(string name, Func< dynamic, dynamic, dynamic > f)
Initializes a new instance of the ArithmeticAction{T} class.
override V Evaluate(Argument[] arguments, RecursiveEval< T > eval, InterpreterContext< T > context)
Evaluates the action.
delegate T RecursiveEval< T >(Tree< Symbol > tree, InterpreterContext< T > context)
Delegate type for recursive evaluation (interpretation)
Exception thrown by basic actions when a problem was encountered.
Represents the arithmetic action. It is similar to the Mercury.Interpreting.FoldingAction{T,U,V} but does not require initial value. The minimal number of arguments is therefore 2. For instance, "1 2 3" would be evaluated as f(f(1, 2), 3)
ArgumentType
Defines argument types using in the Mercury library
static IReadOnlyDictionary< string, string > GetAliases()
Returns aliases for basic actions. It contains the following aliases:
override object Invoke(Argument[] arguments, RecursiveEval< T > eval, InterpreterContext< T > context)
Evaluates the arguments. It is guaranteed to have a valid number of arguments (specified by Arity) a...
Function that wraps constant values in the RHS
SymbolType
Represents a type of symbol. Implemented as Flags since Symbol type inference is ambiguous.
OperationAction(string name, Func< U, U, V > f, ArgumentType flags=ArgumentType.None)
Initializes a new instance of the OperationAction{T, U, V} class.
override V Evaluate(Argument[] arguments, RecursiveEval< T > eval, InterpreterContext< T > context)
Evaluates the action.
Represents an argument passed to the Mercury.Interpreting.InterpreterAction{T}, the actual parameter ...
override U Evaluate(Argument[] arguments, RecursiveEval< T > eval, InterpreterContext< T > context)
Evaluates the action.
static IReadOnlyList< InterpreterAction< T > > GetAllActions()
Provides basic Mercury actions
ConstantAction(string name, U value)
Initializes a new instance of the ConstantAction{T, U} class.
override V Evaluate(Argument[] arguments, RecursiveEval< T > eval, InterpreterContext< T > context)
Evaluates the action.
Interpreter Context class. Some languages may use it to override it and remember data when parse tree...
Represents a single symbol of the grammar. This is an immutable class. For a symbol name to be val...
static InterpreterAction< T > CreateTracer(string name, TextWriter writer)
Creates custom trace action with stream, useful for logging.
FoldingAction(string name, int minargs, Func< V, U, V > f, V seed, ArgumentType flags=ArgumentType.None)
Initializes a new instance of the FoldingAction{T, U, V} class.
ConvertAction(string name, Func< U, V > f, ArgumentType flags=ArgumentType.None)
Initializes a new instance of the ConvertAction{T, U, V} class.
override ArgumentType InferReturnType(ArgumentType expected, ArgumentType[] actual)
Infers the actual return type from provided parameter types