public EnvFile ProcessFile(String name, String contents) { if (this.PathFiles.ContainsKey(name)) { return(this.PathFiles[name]); } var file = new EnvFile(name, contents); var tokenizer = new GLuaLexer(contents); var parser = new GLuaParser(tokenizer, this); this.PathFiles[name] = file; this.LexerFiles[tokenizer] = file; this.ParserFiles[parser] = file; file.Successful = true; try { file.AST = parser.Parse( ); } catch (Exception) { file.Successful = false; throw; } if (file.Successful) { foreach (IPriorityContainer module in this.Modules.Values.OrderBy(con => con.Priority)) { if (module is AnalyserEntry entryA) { entryA.Analyser.File = file; entryA.Analyser.Analyse(file.AST); } else if (module is FolderEntry entryB) { entryB.Folder.File = file; file.AST = ( StatementList )entryB.Folder.Fold(file.AST); } } foreach (Error err in file.Errors) { if (err.Type == ErrorType.Error || err.Type == ErrorType.Fatal) { file.Successful = false; break; } } } return(file); }
protected override ASTNode FoldFunctionCallExpression(FunctionCallExpression node, params Object[] args) { // Fold args and base node = ( FunctionCallExpression )base.FoldFunctionCallExpression(node, args); // Fold some functions if (node.Base is VariableExpression varExpr) { if (varExpr.Variable.Name == "RunString" // Assert we have enough arguments for RunString && node.Arguments.Count > 0) { if (!(node.Arguments[0] is StringExpression) || (node.Arguments.Count > 1 && !(node.Arguments[1] is StringExpression)) || (node.Arguments.Count > 2 && !(node.Arguments[2] is BooleanExpression))) { return(node); } var code = (node.Arguments[0] as StringExpression).Value; var name = node.Arguments.Count > 1 ? (node.Arguments[1] as StringExpression).Value : "runstring_" + R.Next( ); // Dispose of useless RunString calls if (code.Trim( ) == "") { return(null); } EnvFile file = this.Environment.ProcessFile(name, code); if (file.Successful && file.AST != null) { file.AST.Scope.InternalData.RemoveValue("isRoot"); file.AST.Scope.InternalData.RemoveValue("isFunction"); // Enclose it in a do...end statement so that it doesn't // breaks other analysers/folders too bad return(GetDoStatement(node, file.AST)); } } // CompileString is almost the same as RunString // except it's an anonymous function definition else if (varExpr.Variable.Name == "CompileString" && node.Arguments.Count > 0) { if (!(node.Arguments[0] is StringExpression) || (node.Arguments.Count > 1 && !(node.Arguments[1] is StringExpression))) { return(node); } var code = (node.Arguments[0] as StringExpression).Value.Trim( ); var id = node.Arguments.Count > 1 ? (node.Arguments[1] as StringExpression).Value : "compilestring_" + R.Next( ); // It'll be an empty function anyways if (code == "") { var scope = new Scope(node.Scope.Parser, node.Scope); return(GetAnonymousFunctionExpression(node, scope, new StatementList(null, scope, new List <LToken> ( )) )); } EnvFile file = this.Environment.ProcessFile(id, code); if (file.Successful && file.AST != null) { file.AST.InternalData.RemoveValue("isRoot"); var scope = new Scope(node.Scope.Parser, node.Scope); AnonymousFunctionExpression func = GetAnonymousFunctionExpression(node, scope, file.AST); // Add ... as argument because idk what // people might pass to it and there're // no ways to specify argument names so // ¯\_(ツ)_/¯ func.AddArgument(new VarArgExpression( func, scope, GetTokenList("...", "...", "...", TokenType.Punctuation, AdjustRange(node.Range, "...")) )); return(func); } } } return(node); }