/// <summary> /// Sets a value on a member of a basic type. /// </summary> /// <param name="ctx">The context of the runtime</param> /// <param name="node">The assignment ast node</param> /// <param name="isDeclaration">Whether or not this is a declaration</param> /// <param name="varExp">The expression representing the index of the instance to set</param> /// <param name="valExp">The expression representing the value to set</param> public static void SetVariableValue(Context ctx, IAstVisitor visitor, AstNode node, bool isDeclaration, Expr varExp, Expr valExp) { string varname = ((VariableExpr)varExp).Name; // Case 1: var result; if (valExp == null) { ctx.Memory.SetValue(varname, LObjects.Null, isDeclaration); } // Case 2: var result = <expression>; else { var result = valExp.Evaluate(visitor); // Check for type: e.g. LFunction ? when using Lambda? if (result != null && result != LObjects.Null) { var lobj = result as LObject; if (lobj != null && lobj.Type.TypeVal == TypeConstants.Function) { // 1. Define the function in global symbol scope SymbolHelper.ResetSymbolAsFunction(varExp.SymScope, varname, lobj); } } // CHECK_LIMIT: ctx.Limits.CheckStringLength(node, result); ctx.Memory.SetValue(varname, result, isDeclaration); } // LIMIT CHECK ctx.Limits.CheckScopeCount(varExp); ctx.Limits.CheckScopeStringLength(varExp); }
/// <summary> /// Sets up the reference to token iterator and context /// </summary> /// <param name="tk"></param> /// <param name="ctx"></param> public static void Setup(TokenIterator tk, Context ctx, string scriptName) { _tokenIt = tk; _ctx = ctx; _scriptName = scriptName; _withStack = new Stack<string>(); }
/// <summary> /// Executes further Registration actions /// </summary> /// <param name="ctx">The context of the interperter</param> public override void Setup(Context ctx) { ctx.Types.Register(typeof(File), null); ctx.Types.Register(typeof(Files), null); ctx.Types.Register(typeof(Dir), null); ctx.Types.Register(typeof(Dirs), null); }
/// <summary> /// Call a fluent script function from c#. /// </summary> /// <param name="context">The context of the call.</param> /// <param name="functionName">The name of the function to call</param> /// <param name="convertApplicableTypes">Whether or not to convert applicable c# types to fluentscript types, eg. ints and longs to double, List(object) to LArrayType and Dictionary(string, object) to LMapType</param> /// <param name="args"></param> public static object CallFunctionViaCSharp(Context context, string functionName, bool convertApplicableTypes, params object[] args) { var exists = context.Symbols.IsFunc(functionName); if (!exists) return null; var sym = context.Symbols.GetSymbol(functionName) as SymbolFunction; var expr = sym.FuncExpr as FunctionExpr; return FunctionHelper.CallFunctionViaCSharpUsingLambda(context, expr, convertApplicableTypes, args); }
/// <summary> /// Gets a member access object representing the a member access. /// </summary> /// <param name="node"></param> /// <param name="ctx"></param> /// <param name="varExp"></param> /// <param name="memberName"></param> /// <returns></returns> public static MemberAccess GetMemberAccess(AstNode node, Context ctx, Expr varExp, string memberName, IAstVisitor visitor) { var isVariableExp = varExp.IsNodeType(NodeTypes.SysVariable); var variableName = isVariableExp ? ((VariableExpr) varExp).Name : string.Empty; // CASE 1: External function call "user.create" if (isVariableExp && FunctionHelper.IsExternalFunction(ctx.ExternalFunctions, variableName, memberName)) return new MemberAccess(MemberMode.FunctionExternal) {Name = variableName, MemberName = memberName}; // CASE 2. Static method call: "Person.Create" if (isVariableExp) { var result = MemberHelper.IsExternalTypeName(ctx.Memory, ctx.Types, variableName); if (result.Success) return MemberHelper.GetExternalTypeMember(node, (Type) result.Item, variableName, null, memberName, true); } // CASE 3: Module if (varExp.IsNodeType(NodeTypes.SysVariable)) { var name = varExp.ToQualifiedName(); if (!ctx.Memory.Contains(name)) { var modresult = ResolveSymbol(varExp.SymScope, name); if (modresult != null) return modresult; } } // CASE 4: Nested member. var res = varExp.Visit(visitor); if (res is MemberAccess ) { return res as MemberAccess; } var obj = res as LObject; // Check for empty objects. ExceptionHelper.NotNull(node, obj, "member access"); var type = obj.Type; // Case 3: Method / Property on FluentScript type bool isCoreType = obj.Type.IsBuiltInType(); if (isCoreType) { var result = MemberHelper.GetLangBasicTypeMember(node, ctx.Methods, obj, memberName); return result; } // CASE 4: Method / Property on External/Host language type (C#) var lclass = obj as LClass; var lclassType = lclass.Type as LClassType; var member = MemberHelper.GetExternalTypeMember(node, lclassType.DataType, variableName, lclass.Value, memberName, false); return member; }
/// <summary> /// Call a fluent script function from c#. /// </summary> /// <param name="context">The context of the call.</param> /// <param name="expr">The lambda function</param> /// <param name="convertApplicableTypes">Whether or not to convert applicable c# types to fluentscript types, eg. ints and longs to double, List(object) to LArrayType and Dictionary(string, object) to LMapType</param> /// <param name="args"></param> public static object CallFunctionViaCSharpUsingLambda(Context context, FunctionExpr expr, bool convertApplicableTypes, params object[] args) { var argsList = args.ToList<object>(); if (convertApplicableTypes) LangTypeHelper.ConvertToLangTypeValues(argsList); var execution = new Execution(); execution.Ctx = context; if (EvalHelper.Ctx == null) EvalHelper.Ctx = context; var result = FunctionHelper.CallFunctionInScript(context, execution, expr.Meta.Name, expr, null, argsList, false); return result; }
/// <summary> /// Initialize /// </summary> public Interpreter() { _settings = new LangSettings(); // Initialzie the context. _context = new Context(); _context.Settings = _settings; _context.Limits.Init(); _memory = _context.Memory; _parser = new Parser(_context); _parser.Settings = _settings; InitSystemFunctions(); }
/// <summary> /// Executes each phase supplied. /// </summary> /// <param name="script">The script to execute</param> /// <param name="phaseCtx">Contextual information passed to all phases.</param> /// <param name="ctx">The context of the runtime</param> /// <param name="phases">The list of phases.</param> /// <returns></returns> public PhaseResult Execute(string script, PhaseContext phaseCtx, Context ctx, List<IPhase> phases) { if (phases == null || phases.Count == 0) throw new ArgumentException("No phases supplied to execute"); // 2. Keep track of last phase result PhaseResult lastPhaseResult = null; foreach (var phase in phases) { // 3. Execute the phase and get it's result. phase.Ctx = ctx; lastPhaseResult = phase.Execute(phaseCtx); phase.Result = lastPhaseResult; // 4. Stop the phase execution. if (!phase.Result.Success) { break; } } return lastPhaseResult; }
/// <summary> /// Calls an internal function or external function. /// </summary> /// <param name="ctx">The context of the runtime.</param> /// <param name="fexpr">The function call expression</param> /// <param name="functionName">The name of the function. if not supplied, gets from the fexpr</param> /// <param name="pushCallStack"></param> /// <returns></returns> public static object CallFunction(Context ctx, FunctionCallExpr fexpr, string functionName, bool pushCallStack, IAstVisitor visitor) { if(string.IsNullOrEmpty(functionName)) functionName = fexpr.NameExp.ToQualifiedName(); // 1. Check if script func or extern func. var isScriptFunc = fexpr.SymScope.IsFunction(functionName); var isExternFunc = ctx.ExternalFunctions.Contains(functionName); // 2. If neither, this is an error scenario. if (!isScriptFunc && !isExternFunc) throw ExceptionHelper.BuildRunTimeException(fexpr, "Function does not exist : '" + functionName + "'"); // 3. Push the name of the function on teh call stack if(pushCallStack) ctx.State.Stack.Push(functionName, fexpr); // 4. Call the function. object result = null; // Case 1: Custom C# function blog.create blog.* if (isExternFunc) result = FunctionHelper.CallFunctionExternal(ctx, visitor, functionName, fexpr); // Case 2: Script functions "createUser('john');" else { var sym = fexpr.SymScope.GetSymbol(functionName) as SymbolFunction; var func = sym.FuncExpr as FunctionExpr; var resolveParams = !fexpr.RetainEvaluatedParams; result = FunctionHelper.CallFunctionInScript(ctx, visitor, functionName, func, fexpr.ParamListExpressions, fexpr.ParamList, resolveParams); } // 3. Finnaly pop the call stact. if(pushCallStack) ctx.State.Stack.Pop(); result = CheckConvert(result); return result; }
/// <summary> /// Validate the statements for errors. /// </summary> /// <param name="stmts">Statements to validate</param> /// <returns></returns> public RunResult Validate(List<Expr> stmts) { var start = DateTime.Now; if (stmts == null || stmts.Count == 0) return new RunResult(start, start, true, "No nodes to validate"); _ctx = stmts[0].Ctx; // Reset the errors. _errors = new List<ScriptError>(); _parseStk = new ParseStackManager(); // Use the visitor to walk the AST tree of statements/expressions var visitor = new AstVisitor((astnode1) => Validate(astnode1), (astnode2) =>OnNodeEnd(astnode2)); visitor.Visit(stmts); var end = DateTime.Now; // Now check for success. bool success = _errors.Count == 0; _results = new RunResult(start, end, success, _errors); _results.Errors = _errors; return _results; }
/// <summary> /// Sets a value on a member of a basic type. /// </summary> /// <param name="ctx">The context of the runtime</param> /// <param name="varExp">The expression representing the index of the instance to set</param> /// <param name="valExp">The expression representing the value to set</param> /// <param name="node">The assignment ast node</param> public static void SetMemberValue(Context ctx, IAstVisitor visitor, AstNode node, Expr varExp, Expr valExp) { // 1. Get the value that is being assigned. var val = valExp.Evaluate(visitor) as LObject; // 2. Check the limit if string. ctx.Limits.CheckStringLength(node, val); // 3. Evaluate expression to get index info. var memAccess = varExp.Evaluate(visitor) as MemberAccess; if (memAccess == null) throw ExceptionHelper.BuildRunTimeException(node, "Value to assign is null"); // Case 1: Set member on basic type if (memAccess.Type != null) { // Get methods associated with type. var methods = ctx.Methods.Get(memAccess.Type); // Case 1: users['total'] = 20 if (memAccess.Type == LTypes.Map) { var target = memAccess.Instance as LObject; methods.SetByStringMember(target, memAccess.MemberName, val); } } // Case 2: Set member on custom c# class else if(memAccess.DataType != null) { if(memAccess.Property != null) { var prop = memAccess.Property; prop.SetValue(memAccess.Instance, val.GetValue(prop.PropertyType), null); } } }
/// <summary> /// The context of the program. /// </summary> public void SetContext(Context ctx) { _ctx = ctx; }
/// <summary> /// Executes a setup on the interpreter /// </summary> /// <param name="ctx"></param> public virtual void Setup(Context ctx) { }
/// <summary> /// Finds a matching script function name from the list of strings representing identifiers. /// </summary> /// <param name="ctx">The context of the script</param> /// <param name="ids">List of strings representing identifier tokens</param> /// <returns></returns> public static FunctionLookupResult MatchFunctionName(Context ctx, List<Tuple<string,int>> ids) { var names = ids; var foundFuncName = string.Empty; var found = false; var tokenCount = 0; var memberMode = MemberMode.FunctionScript; for( int ndx = ids.Count - 1; ndx >=0; ndx-- ) { // "refill inventory" var possible = ids[ndx]; string funcName = possible.Item1; string funcNameWithUnderScores = funcName.Replace(' ', '_'); // Case 1: "refill inventory" - exists with spaces if (ctx.Symbols.IsFunc(funcName)) { foundFuncName = funcName; } // Case 2: "refill_inventory" - replace space with underscore. else if (ctx.Symbols.IsFunc(funcNameWithUnderScores)) { foundFuncName = funcNameWithUnderScores; } // Case 3: Check external functions else if (ctx.ExternalFunctions.Contains(funcName)) { memberMode = MemberMode.FunctionExternal; foundFuncName = funcName; } if (!string.IsNullOrEmpty(foundFuncName)) { found = true; tokenCount = possible.Item2; break; } } // CASE 1: Not found if (!found ) return FunctionLookupResult.False; // CASE 2: Single word function if ((found && tokenCount == 1) && memberMode == MemberMode.FunctionScript) { var sym = ctx.Symbols.GetSymbol(foundFuncName) as SymbolFunction; var func = sym.FuncExpr as FunctionExpr; //var func = ctx.Functions.GetByName(foundFuncName); // If wildcard return true; if (func.Meta.HasWildCard) return new FunctionLookupResult(true, foundFuncName, memberMode) { TokenCount = tokenCount }; else return FunctionLookupResult.False; } var result = new FunctionLookupResult() { Exists = found, Name = foundFuncName, FunctionMode = memberMode, TokenCount = tokenCount }; return result; }
/// <summary> /// Initialize /// </summary> /// <param name="ctx"></param> public FluentPluginHelper(Context ctx) { _ctx = ctx; }
/// <summary> /// Execute a member call. /// </summary> /// <param name="ctx">The context of the script</param> /// <param name="memberAccess">Object to hold all the relevant information required for the member call.</param> /// <param name="paramListExpressions">The expressions to resolve as parameters</param> /// <param name="paramList">The list of parameters.</param> /// <returns></returns> public static object CallMemberOnClass(Context ctx, AstNode node, MemberAccess memberAccess, List<Expr> paramListExpressions, List<object> paramList, IAstVisitor visitor) { object result = LObjects.Null; var obj = memberAccess.Instance; var type = memberAccess.DataType; // Case 1: Property access if (memberAccess.Property != null) { var prop = type.GetProperty(memberAccess.MemberName); if (prop != null) result = prop.GetValue(obj, null); } // Case 2: Method call. else if( memberAccess.Method != null) { result = FunctionHelper.MethodCall(ctx, obj, type, memberAccess.Method, paramListExpressions, paramList, true, visitor); } // Case 1: Property access if (memberAccess.Field != null) { result = memberAccess.Field.GetValue(obj); } result = CheckConvert(result); return result; }
/// <summary> /// Call a function by passing in all the values. /// </summary> /// <param name="ctx">The context of the runtime</param> /// <param name="functionName">The name of the function to call.</param> /// <param name="paramListExpressions">List of parameters as expressions to evaluate first to actual values</param> /// <param name="paramVals">List to store the resolved paramter expressions. ( these will be resolved if paramListExpressions is supplied and resolveParams is true. If /// resolveParams is false, the list is assumed to have the values for the paramters to the function.</param> /// <param name="resolveParams">Whether or not to resolve the list of parameter expression objects</param> /// <returns></returns> public static object CallFunctionInScript(Context ctx, IAstVisitor visitor, string functionName, FunctionExpr function, List<Expr> paramListExpressions, List<object> paramVals, bool resolveParams) { // 1. Determine if any parameters provided. var hasParams = paramListExpressions != null && paramListExpressions.Count > 0; // 2. Resolve parameters if necessary var hasArguments = function.Meta.HasArguments(); if (resolveParams && function != null && (hasArguments || hasParams)) ParamHelper.ResolveParametersForScriptFunction(function.Meta, paramListExpressions, paramVals, visitor); // 3. Assign the argument values to the function and evaluate. function.ArgumentValues = paramVals; visitor.VisitFunction(function); object result = null; if (function.HasReturnValue) result = function.ReturnValue; else result = LObjects.Null; return result; }
public Limits(Context ctx) { _ctx = ctx; }
/// <summary> /// Initialize the context. /// </summary> /// <param name="context"></param> public Parser(Context context) : base(context) { _tokenIt = new TokenIterator(); }
/// <summary> /// Calls a property get /// </summary> /// <param name="ctx">The context of the runtime</param> /// <param name="memberAccess">Object to hold all the relevant information required for the member call.</param> /// <param name="paramListExpressions">The collection of parameters as expressions</param> /// <param name="paramList">The collection of parameter values after they have been evaluated</param> /// <returns></returns> public static object CallMemberOnBasicType(Context ctx, AstNode node, MemberAccess memberAccess, List<Expr> paramListExpressions, List<object> paramList, IAstVisitor visitor) { object result = null; // 1. Get methods var methods = ctx.Methods.Get(memberAccess.Type); // 2. Get object on which method/property is being called on. var lobj = (LObject)memberAccess.Instance; // 3. Property ? if (memberAccess.Mode == MemberMode.PropertyMember) { result = methods.GetProperty(lobj, memberAccess.MemberName); } // 4. Method else if (memberAccess.Mode == MemberMode.MethodMember) { object[] args = null; if(paramListExpressions != null && paramListExpressions.Count > 0) { ParamHelper.ResolveNonNamedParameters(paramListExpressions, paramList, visitor); args = paramList.ToArray(); } result = methods.ExecuteMethod(lobj, memberAccess.MemberName, args); } result = CheckConvert(result); return result; }
/// <summary> /// Sets a value on a member of a basic type. /// </summary> /// <param name="ctx">The context of the runtime</param> /// <param name="varExp">The expression representing the index of the instance to set</param> /// <param name="valExp">The expression representing the value to set</param> /// <param name="node">The assignment ast node</param> public static void SetIndexValue(Context ctx, IAstVisitor visitor, AstNode node, Expr varExp, Expr valExp) { // 1. Get the value that is being assigned. var val = valExp.Evaluate(visitor) as LObject; // 2. Check the limit if string. ctx.Limits.CheckStringLength(node, val); // 3. Evaluate expression to get index info. var indexExp = varExp.Evaluate(visitor) as IndexAccess; if (indexExp == null) throw ExceptionHelper.BuildRunTimeException(node, "Value to assign is null"); // 4. Get the target of the index access and the name / number to set. var target = indexExp.Instance; var memberNameOrIndex = indexExp.MemberName; // Get methods associated with type. var methods = ctx.Methods.Get(target.Type); // Case 1: users[0] = 'kishore' if(target.Type == LTypes.Array || target.Type.TypeVal == TypeConstants.Table) { var index = Convert.ToInt32(((LNumber) memberNameOrIndex).Value); methods.SetByNumericIndex(target, index, val); } // Case 2: users['total'] = 20 else if (target.Type == LTypes.Map) { var name = ((LString) memberNameOrIndex).Value; methods.SetByStringMember(target, name, val); } }
/// <summary> /// Calls the custom function. /// </summary> /// <param name="name">Name of the function</param> /// <param name="exp"></param> /// <returns></returns> public static object CallFunctionExternal(Context ctx, IAstVisitor visitor, string name, FunctionCallExpr exp ) { var externalFuncs = ctx.ExternalFunctions; var objectName = name; var method = string.Empty; Func<string, string, FunctionCallExpr, object> callback = null; // Contains callback for full function name ? e.g. CreateUser if (externalFuncs.Contains(name)) callback = externalFuncs.GetByName(name); // Contains callback that handles multiple methods on a "object". // e.g. Blog.Create, Blog.Delete etc. if (name.Contains(".")) { var ndxDot = name.IndexOf("."); objectName = name.Substring(0, ndxDot); method = name.Substring(ndxDot + 1); if (externalFuncs.Contains(objectName + ".*")) callback = externalFuncs.GetByName(objectName + ".*"); } if (callback == null) return LObjects.Null; // 1. Resolve parameter froms expressions into Lang values. ParamHelper.ResolveParametersToHostLangValues(exp.ParamListExpressions, exp.ParamList, visitor); object result = callback(objectName, method, exp); return result; }
/// <summary> /// Initialize /// </summary> /// <param name="text">The text to parse</param> public Lexer(string text) { this._ctx = new Context(); this.Init(text); }
/// <summary> /// Initialize /// </summary> public ParserBase(Context context) { _context = context; _parseErrors = new List<LangException>(); _lexer = new Lexer(""); _lexer.SetContext(_context); }
/// <summary> /// Dynamically invokes a method call. /// </summary> /// <param name="ctx">Context of the script</param> /// <param name="obj">Instance of the object for which the method call is being applied.</param> /// <param name="datatype">The datatype of the object.</param> /// <param name="methodInfo">The method to call.</param> /// <param name="paramListExpressions">List of expressions representing parameters for the method call</param> /// <param name="paramList">The list of values(evaluated from expressions) to call.</param> /// <param name="resolveParams">Whether or not to resolve the parameters from expressions to values.</param> /// <returns></returns> private static object MethodCall(Context ctx, object obj, Type datatype, MethodInfo methodInfo, List<Expr> paramListExpressions, List<object> paramList, bool resolveParams, IAstVisitor visitor) { // 1. Convert language expressions to values. if (resolveParams) ParamHelper.ResolveParametersForMethodCall(methodInfo, paramListExpressions, paramList, visitor); // 2. Convert internal language types to c# code method types. object[] args = LangTypeHelper.ConvertArgs(paramList, methodInfo); // 3. Handle params object[]; if (methodInfo.GetParameters().Length == 1) { if (methodInfo.GetParameters()[0].ParameterType == typeof(object[])) args = new object[] { args }; } object result = methodInfo.Invoke(obj, args); return result; }