Exemple #1
0
        public static string Compiled(ObjectMacro asset)
        {
            var output          = string.Empty;
            var isNamespaceNull = string.IsNullOrEmpty(asset.@namespace);
            var usingStatements = new List <string>();
            var inherits        = asset.baseType;
            var implements      = asset.interfaces;
            var typeName        = Patcher.TypeName(asset);
            var variables       = asset.variables;
            var scope           = asset.scope;
            var modifier        = asset.classModifier;
            var @namespace      = asset.@namespace;
            var name            = asset.name;
            var methods         = asset.methods;

            foreach (Method method in methods)
            {
                var units = method.graph.units;

                foreach (IUnit unit in units)
                {
                    var statements = unit.CodeGenerator().usingStatements;
                    foreach (string statement in statements)
                    {
                        AssemblyBuilder.UsingStatement(statement, usingStatements);
                    }
                }
            }

            AssemblyBuilder.UsingStatements(variables, usingStatements);
            AssemblyBuilder.UsingStatement(inherits.type, usingStatements);

            string typeDeclaration = ClassBuilder.Declaration(
                isNamespaceNull ? 0 : 1,
                scope,
                modifier,
                typeName,
                inherits.type.CSharpName(false) == "object" ? string.Empty : inherits.type.CSharpName(false),
                implements,
                string.Empty,
                string.Empty,
                variables,
                string.Empty,
                string.Empty,
                methods,
                false
                );

            output += AssemblyBuilder.GenerateUsingStatements(usingStatements);

            if (!isNamespaceNull)
            {
                output += AssemblyBuilder.Namespace(typeDeclaration, @namespace);
                return(output);
            }

            output += typeDeclaration;

            return(output);
        }
Exemple #2
0
        public static string CompiledEnum(ObjectMacro asset)
        {
            var output          = string.Empty;
            var @namespace      = asset.@namespace;
            var name            = asset.name;
            var scope           = asset.scope;
            var items           = asset.enumValues;
            var isNamespaceNull = string.IsNullOrEmpty(@namespace);
            var typeName        = Patcher.TypeName(asset);

            var typeDeclaration = EnumDeclaration(
                isNamespaceNull ? 0 : 1,
                scope,
                typeName,
                string.Empty,
                items,
                false
                );

            if (!isNamespaceNull)
            {
                output += AssemblyBuilder.Namespace(typeDeclaration, @namespace);
                return(output);
            }

            output += typeDeclaration;
            return(output);
        }
Exemple #3
0
 public static void SetCompiledData(ObjectMacro macro)
 {
     macro.last_BaseType         = macro.baseType;
     macro.last_ClassModifier    = macro.classModifier;
     macro.last_ConstructorCount = macro.constructors.Count;
     macro.last_InterfaceCount   = macro.interfaces.Count;
     macro.last_Kind             = macro.kind;
     macro.last_MethodCount      = macro.methods.Count;
 }
Exemple #4
0
 public static string Define(int indent, ObjectMacro liveObject, bool isLive)
 {
     return(Declaration(indent,
                        liveObject.scope,
                        liveObject.name,
                        liveObject.baseType.type.CSharpName(),
                        liveObject.interfaces,
                        string.Empty,
                        string.Empty,
                        liveObject.variables,
                        string.Empty,
                        string.Empty,
                        liveObject.methods,
                        isLive
                        ));
 }
Exemple #5
0
 public static string Proxy(ObjectMacro asset)
 {
     return(string.Empty);
 }
Exemple #6
0
        public static string Proxy(ObjectMacro asset)
        {
            var output          = string.Empty;
            var @namespace      = asset.@namespace;
            var isNamespaceNull = string.IsNullOrEmpty(@namespace);
            var usingStatements = new List <string>();
            var inherits        = asset.baseType;
            var implements      = asset.interfaces.ToListPooled();
            var typeName        = Patcher.TypeName(asset);
            var variables       = asset.variables;
            var scope           = asset.scope;
            var modifier        = asset.classModifier;
            var name            = asset.name;
            var methods         = asset.methods;

            AssemblyBuilder.UsingStatement("System", usingStatements);
            AssemblyBuilder.UsingStatement("System.Linq", usingStatements);
            AssemblyBuilder.UsingStatement("System.Collections.Generic", usingStatements);
            AssemblyBuilder.UsingStatement("UnityEngine", usingStatements);
            AssemblyBuilder.UsingStatement("Lasm.UAlive", usingStatements);
            AssemblyBuilder.UsingStatement("Ludiq", usingStatements);
            AssemblyBuilder.UsingStatements(variables, usingStatements);
            AssemblyBuilder.UsingStatement(inherits.type, usingStatements);


            implements.Add(new Interface()
            {
                type = typeof(ILiveObject)
            });

            //var dynamicVariables = CodeBuilder.Indent(isNamespaceNull ? 1 : 2) + "[Serialize]" + "\n";
            //dynamicVariables += CodeBuilder.Indent(isNamespaceNull ? 1 : 2) + "protected Dictionary<string, object> variables = new Dictionary<string, object>();";

            var objectMacro = CodeBuilder.Indent(isNamespaceNull ? 1 : 2) + "protected ObjectMacro macro;" + "\n";

            var methodMacros = string.Empty;

            foreach (Method method in methods)
            {
                methodMacros += CodeBuilder.Indent(isNamespaceNull ? 1 : 2) + "protected Method " + method.name + "_Method;" + "\n";
            }



            string typeDeclaration = ClassBuilder.Declaration(
                isNamespaceNull ? 0 : 1,
                scope,
                modifier,
                typeName,
                inherits.type.CSharpName(false) == "object" ? string.Empty : inherits.type.CSharpName(false),
                implements,
                string.Empty,
                string.Empty,
                variables,
                objectMacro + methodMacros,
                string.Empty,
                string.Empty,
                methods,
                true
                );

            output += AssemblyBuilder.GenerateUsingStatements(usingStatements);

            output += "\n";
            output += "#if UNITY_EDITOR";
            output += "\n";
            output += "using UnityEditor;";
            output += "\n";
            output += "#endif";
            output += "\n \n";

            if (!isNamespaceNull)
            {
                output += AssemblyBuilder.Namespace(typeDeclaration, @namespace);
                return(output);
            }

            output += typeDeclaration;

            return(output);
        }
Exemple #7
0
 public static string TypeName(ObjectMacro asset)
 {
     return(Patcher.LegalVariableName((string.IsNullOrEmpty(asset.name) ? CodeBuilder.GetExtensionlessFileName(CodeBuilder.GetFileName(asset)).Replace(" ", string.Empty) : asset.name).Replace(" ", string.Empty), false));
 }
        public Root parse(string filename, string[] code)
        {
            logger.Debug($"Parsing {filename}");
            if (logger.IsTraceEnable)
            {
                foreach (var line in code)
                {
                    logger.Trace(line);
                }
            }


            var startTime = DateTime.Now.Ticks;
            var ast       = new Root();


            // Track some state variables for this parsing round.
            string topic                      = "random"; // Default topic = random
            int    lineno                     = 0;
            bool   inComment                  = false;    // In a multi-line comment
            bool   inObject                   = false;    // In an object
            string objectName                 = null;     // Name of the current object
            string objectLanguage             = null;     // Programming language of the object
            ICollection <string> objectBuffer = null;     // Buffer for the current object
            string onTrigger                  = null;     // Trigger we're on
            //Trigger currentTriggerObject = null;        // Trigger we're on
            string previous = null;                       // The a %Previous trigger

            // File scoped parser options.
            IDictionary <string, string> local_options = new Dictionary <string, string>();

            local_options.AddOrUpdate("concat", "none");
            //local_options.Add("concat", "space");
            //local_options.Add("concat", "newline");

            // The given "code" is an array of lines, so jump right in.
            for (int i = 0; i < code.Length; i++)
            {
                lineno++; // Increment the line counter.
                string line = code[i] ?? "";
                logger.Debug("Original Line: " + line);

                // Trim the line of whitespaces.
                line = Util.Strip(line);


                if (line.Length == 0)
                {
                    continue; //Skip blank line
                }
                // Are we inside an object?
                if (inObject)
                {
                    if (line.StartsWith("<object") || line.StartsWith("< object"))
                    {
                        // End of the object. Did we have a handler?
                        if (!string.IsNullOrWhiteSpace(objectName))
                        {
                            var macro = new ObjectMacro
                            {
                                Code     = objectBuffer,
                                Language = objectLanguage,
                                Name     = objectName,
                            };

                            ast.addObject(macro);
                        }
                        objectName     = null;
                        objectLanguage = null;
                        objectBuffer   = null;
                        inObject       = false;
                    }
                    else
                    {
                        // Collect the code.
                        objectBuffer.Add(line);
                    }

                    continue;
                }


                // Look for comments.
                if (line.StartsWith("/*"))
                {
                    // Beginning a multi-line comment.
                    if (line.IndexOf("*/") > -1)
                    {
                        // It ends on the same line.
                        continue;
                    }
                    inComment = true;
                }
                else if (line.StartsWith("//"))
                {
                    // A single line comment.
                    continue;
                }
                else if (line.IndexOf("*/") > -1)
                {
                    // End a multi-line comment.
                    inComment = false;
                    continue;
                }
                if (inComment) //else if?
                {
                    continue;
                }

                // Skip any blank lines and weird lines.
                if (line.Length < 2)
                {
                    logger.Warn($"Weird single-character line '#" + line + "' found (in topic #" + topic + ")");
                    continue;
                }

                // Separate the command from the rest of the line.
                string cmd = line.Substring(0, 1);
                line = Util.Strip(line.Substring(1));


                logger.Debug("\tCmd: " + cmd);

                // Ignore in-line comments if there's a space before and after the "//".
                if (line.IndexOf(" // ") > -1)
                {
                    string[] split = line.Split(new[] { " // " }, StringSplitOptions.None);
                    line = split[0];
                    //remove space between comment and code
                    line = line.TrimEnd(' ');
                }

                // In the event of a +Trigger, if we are force-lowercasing it, then do so
                // In the event of a +Trigger, if we are force-lowercasing it, then do so
                // now before the syntax check.
                if (forceCase && cmd == CMD_TRIGGER)
                {
                    line = line.ToLower();
                }


                //Run a syntax check on this line
                try
                {
                    checkSyntax(cmd, line);
                }
                catch (ParserException pex)
                {
                    if (strict)
                    {
                        throw pex;
                    }
                    else
                    {
                        logger.Warn($"Syntax logger.error(: {pex.Message} at {filename} line {lineno} near {cmd} {line}");
                    }
                }


                // Reset the %Previous if this is a new +Trigger.
                if (cmd.Equals(CMD_TRIGGER))
                {
                    previous = "";
                }

                // Do a look-ahead to see ^Continue and %Previous.
                if (cmd != CMD_CONTINUE)
                {
                    for (int j = (i + 1); j < code.Length; j++)
                    {
                        // Peek ahead.
                        string peek = Util.Strip(code[j]);

                        // Skip blank.
                        if (peek.Length == 0) //peek.Length < 2?
                        {
                            continue;
                        }

                        // Get the command.
                        string peekCmd = peek.Substring(0, 1);
                        peek = Util.Strip(peek.Substring(1));

                        // Only continue if the lookahead line has any data.
                        if (peek.Length > 0)
                        {
                            // The lookahead command has to be a % or a ^
                            if (!peekCmd.Equals(CMD_CONTINUE) && !peekCmd.Equals(CMD_PREVIOUS))
                            {
                                break;
                            }

                            // If the current command is a +, see if the following is a %.
                            if (cmd.Equals(CMD_TRIGGER))
                            {
                                if (peekCmd.Equals(CMD_PREVIOUS))
                                {
                                    // It has a %Previous!
                                    previous = peek;
                                    break;
                                }
                                else
                                {
                                    previous = "";
                                }
                            }

                            // If the current command is a ! and the next command(s) are
                            // ^, we'll tack each extension on as a "line break".
                            if (cmd.Equals(CMD_DEFINE))
                            {
                                if (peekCmd.Equals(CMD_CONTINUE))
                                {
                                    line += "<crlf>" + peek;
                                }
                            }

                            // If the current command is not a ^ and the line after is
                            // not a %, but the line after IS a ^, then tack it onto the
                            // end of the current line.
                            if (!cmd.Equals(CMD_CONTINUE) && !cmd.Equals(CMD_PREVIOUS) && !cmd.Equals(CMD_DEFINE))
                            {
                                if (peekCmd.Equals(CMD_CONTINUE))
                                {
                                    // Concatenation character?
                                    ConcatMode concatMode = null;
                                    if (local_options.ContainsKey("concat"))
                                    {
                                        concatMode = ConcatMode.FromName(local_options["concat"]);
                                    }

                                    if (concatMode == null)
                                    {
                                        concatMode = concat ?? Config.DEFAULT_CONCAT;
                                    }

                                    line += concatMode.ConcatChar + peek;
                                }
                                else
                                {
                                    break; //?warn
                                }
                            }
                        }
                    }
                }

                // Start handling command types.
                //TODO: change to switch-case
                if (cmd.Equals(CMD_DEFINE))
                {
                    logger.Debug("\t! DEFINE");
                    //string[] halves = line.split("\\s*=\\s*", 2);
                    string[] halves = new Regex("\\s*=\\s*").Split(line, 2);
                    //string[] left = whatis[0].split("\\s+", 2);
                    string[] left   = new Regex("\\s+").Split(halves[0], 2);
                    string   value  = "";
                    string   kind   = ""; //global, var, sub, ...
                    string   name   = "";
                    bool     delete = false;

                    if (halves.Length == 2)
                    {
                        value = halves[1].Trim();
                    }

                    if (left.Length >= 1)
                    {
                        kind = left[0];
                        if (left.Length >= 2)
                        {
                            left = Util.CopyOfRange(left, 1, left.Length);
                            //name = left[1].Trim().ToLower();
                            name = Util.Join(left, " ").Trim();
                        }
                    }

                    // Remove line breaks unless this is an array.
                    if (!kind.Equals("array"))
                    {
                        value = value.Replace("<crlf>", "");
                    }

                    // Version is the only type that doesn't have a var.
                    if (kind.Equals("version"))
                    {
                        logger.Debug("\tUsing RiveScript version " + value);

                        // Convert the value into a double, catch exceptions.
                        double version = 0;
                        try
                        {
                            version = double.Parse(value ?? "", new NumberFormatInfo {
                                CurrencyDecimalSeparator = "."
                            });
                        }
                        catch (FormatException)
                        {
                            logger.Warn("RiveScript version \"" + value + "\" not a valid floating number", filename, lineno);
                            continue;
                        }

                        if (version > RS_VERSION)
                        {
                            throw new ParserException($"We can't parse RiveScript v {value} documents at {filename} line {lineno}. Only support {RS_VERSION}.");
                        }

                        continue;
                    }
                    else
                    {
                        // All the other types require a variable and value.
                        if (name.Equals(""))
                        {
                            logger.Warn("Missing a " + kind + " variable name", filename, lineno);
                            continue;
                        }
                        if (value.Equals(""))
                        {
                            logger.Warn("Missing a " + kind + " value", filename, lineno);
                            continue;
                        }
                        if (value.Equals(Constants.UNDEF_TAG))
                        {
                            // Deleting its value.
                            delete = true;
                        }
                    }

                    // Handle the variable set types.
                    //TODO: change to switch-case
                    if (kind.Equals("local"))
                    {
                        // Local file scoped parser options
                        logger.Debug("\tSet local parser option " + name + " = " + value);
                        local_options.AddOrUpdate(name, value);
                    }
                    else if (kind.Equals("global"))
                    {
                        // Is it a special global? (debug or depth or etc).
                        logger.Debug("\tSet global " + name + " = " + value);
                        ast.begin.addGlobals(name, value);
                    }
                    else if (kind.Equals("var"))
                    {
                        // Set a bot variable.
                        logger.Debug("\tSet bot variable " + name + " = " + value);
                        ast.begin.addVar(name, value);
                    }
                    else if (kind.Equals("array"))
                    {
                        // Set an array.
                        logger.Debug("\tSet array " + name);

                        // Deleting it?
                        if (delete)
                        {
                            ast.begin.removeArray(name);
                            continue;
                        }

                        // Did the array have multiple lines?
                        //string[] parts = value.split("<crlf>");
                        //WARN:
                        string[]             parts = value.Split("<crlf>");
                        ICollection <string> items = new List <string>();
                        for (int a = 0; a < parts.Length; a++)
                        {
                            // Split at pipes or spaces?
                            string[] pieces;
                            if (parts[a].IndexOf("|") > -1)
                            {
                                //pieces = parts[a].split("\\|");
                                pieces = new Regex("\\|").Split(parts[a]);
                            }
                            else
                            {
                                pieces = new Regex("\\s+").Split(parts[a]);
                            }

                            // Add the pieces to the final array.
                            for (int b = 0; b < pieces.Length; b++)
                            {
                                items.Add(pieces[b]);
                            }
                        }

                        // Store this array.
                        ast.begin.addArray(name, items);
                    }
                    else if (kind.Equals("sub"))
                    {
                        // Set a substitution.
                        logger.Debug("\tSubstitution " + name + " => " + value);
                        ast.begin.addSub(name, value);
                    }
                    else if (kind.Equals("person"))
                    {
                        // Set a person substitution.
                        logger.Debug("\tPerson substitution " + name + " => " + value);
                        ast.begin.addPerson(name, value);
                    }
                    else
                    {
                        logger.Warn("Unknown definition type \"" + kind + "\"", filename, lineno);
                        continue;
                    }
                }
                else if (cmd.Equals(CMD_LABEL))
                {
                    // > LABEL
                    logger.Debug("\t> LABEL");
                    //string[] label =  line.split("\\s+");
                    string[] label = line.SplitRegex("\\s+");
                    string   type  = "";
                    string   name  = "";
                    if (label.Length >= 1)
                    {
                        type = label[0].Trim().ToLower();
                    }
                    if (label.Length >= 2)
                    {
                        name = label[1].Trim();
                    }

                    // Handle the label types.
                    if (type.Equals("begin"))
                    {
                        // The BEGIN statement.
                        logger.Debug("\tFound the BEGIN Statement.");

                        // A BEGIN is just a special topic.
                        type = "topic";
                        name = "__begin__";
                    }

                    if (type.Equals("topic"))
                    {
                        if (forceCase)
                        {
                            name = name.ToLower();
                        }


                        // Starting a new topic.
                        logger.Debug("\tSet topic to " + name);
                        onTrigger = "";
                        //currentTriggerObject = null;
                        topic = name;

                        // Does this topic include or inherit another one?
                        if (label.Length >= 3)
                        {
                            int mode_includes = 1;
                            int mode_inherits = 2;
                            int mode          = 0;
                            for (int a = 2; a < label.Length; a++)
                            {
                                if (label[a].ToLowerInvariant().Equals("includes"))
                                {
                                    mode = mode_includes;
                                }
                                else if (label[a].ToLowerInvariant().Equals("inherits"))
                                {
                                    mode = mode_inherits;
                                }
                                else if (mode > 0)
                                {
                                    // This topic is either inherited or included.
                                    if (mode == mode_includes)
                                    {
                                        topicManager.topic(topic).includes(label[a]);
                                    }
                                    else if (mode == mode_inherits)
                                    {
                                        topicManager.topic(topic).inherits(label[a]);
                                    }
                                }
                            }
                        }
                    }
                    if (type.Equals("object"))
                    {
                        // If a field was provided, it should be the programming language.
                        string language = "";

                        if (label.Length >= 3)
                        {
                            language = label[2].ToLower();
                        }

                        // Only try to parse a language we support.
                        onTrigger = "";
                        if (language.Length == 0)
                        {
                            logger.Warn("Trying to parse unknown programming language (assuming it's CSharp)", filename, lineno);
                            language = Constants.CSharpHandlerName; // Assume it's JavaScript
                        }

                        //INFO: to remove?
                        //if (!handlers.ContainsKey(language))
                        //{
                        //    // We don't have a handler for this language.
                        //    logger.debug("We can't handle " + language + " object code!");
                        //    continue;
                        //}

                        // Start collecting its code!
                        objectName     = name;
                        objectLanguage = language;
                        objectBuffer   = new List <string>();
                        inObject       = true;
                    }
                }
                else if (cmd.Equals(CMD_ENDLABEL))
                {
                    // < ENDLABEL
                    logger.Debug("\t< ENDLABEL");
                    string type = line.Trim().ToLower();

                    if (type.Equals("begin") || type.Equals("topic"))
                    {
                        logger.Debug("\t\tEnd topic label.");
                        topic = "random";
                    }
                    else if (type.Equals("object"))
                    {
                        logger.Debug("\t\tEnd object label.");
                        inObject = false;
                    }
                    else
                    {
                        logger.Warn("Unknown end topic type \"" + type + "\"", filename, lineno);
                    }
                }
                else if (cmd.Equals(CMD_TRIGGER))
                {
                    // + TRIGGER
                    logger.Debug("\t+ TRIGGER pattern: " + line);

                    //currentTriggerObject = new Trigger(line);

                    //if (previous.Length > 0)
                    //{
                    //    onTrigger = line + "{previous}" + previous;
                    //    currentTriggerObject.setPrevious(true);
                    //    topicManager.topic(topic).addPrevious(line, previous);
                    //}
                    //else
                    //{
                    //    onTrigger = line;
                    //}

                    //topicManager.topic(topic).addTrigger(currentTriggerObject);


                    //TODO onld stuff to see
                    if (previous.Length > 0)
                    {
                        // This trigger had a %Previous. To prevent conflict, tag the
                        // trigger with the "that" text.
                        onTrigger = line + "{previous}" + previous;

                        topicManager.topic(topic).trigger(line).setPrevious(true);
                        topicManager.topic(topic).addPrevious(line, previous);
                    }
                    else
                    {
                        // Set the current trigger to this.
                        onTrigger = line;
                    }
                }
                else if (cmd.Equals(CMD_REPLY))
                {
                    // - REPLY
                    logger.Debug("\t- REPLY: " + line);

                    // This can't come before a trigger!
                    if (onTrigger.Length == 0)
                    {
                        logger.Warn("Reply found before trigger", filename, lineno);
                        continue;
                    }

                    // Warn if we also saw a hard redirect.
                    if (topicManager.topic(topic).trigger(onTrigger).hasRedirect())
                    {
                        logger.Warn("You can't mix @Redirects with -Replies", filename, lineno);
                    }

                    // Add the reply to the trigger
                    topicManager.topic(topic).trigger(onTrigger).addReply(line);
                }
                else if (cmd.Equals(CMD_PREVIOUS))
                {
                    // % PREVIOUS
                    // This was handled above.
                    continue;
                }
                else if (cmd.Equals(CMD_CONTINUE))
                {
                    // ^ CONTINUE
                    // This was handled above.
                    continue;
                }
                else if (cmd.Equals(CMD_REDIRECT))
                {
                    // @ REDIRECT
                    logger.Debug("\t@ REDIRECT: " + line);

                    // This can't come before a trigger!
                    if (onTrigger.Length == 0)
                    {
                        logger.Warn("Redirect found before trigger", filename, lineno);
                        continue;
                    }

                    // Add the redirect to the trigger.
                    // TODO: this extends RiveScript, not compat w/ Perl yet
                    topicManager.topic(topic).trigger(onTrigger).addRedirect(line);
                }
                else if (cmd.Equals(CMD_CONDITION))
                {
                    // * CONDITION
                    logger.Debug("\t* CONDITION: " + line);

                    // This can't come before a trigger!
                    if (onTrigger.Length == 0)
                    {
                        logger.Warn("Redirect found before trigger", filename, lineno);
                        continue;
                    }

                    // Add the condition to the trigger.
                    topicManager.topic(topic).trigger(onTrigger).addCondition(line);
                }
                else
                {
                    logger.Warn("Unrecognized command \"" + cmd + "\"", filename, lineno);
                }
            }

            //becouse we use topicmanager to manage topis, we have to fill ast topics
            foreach (var item in topicManager.listTopics())
            {
                ast.addTopic(item.Value);
            }


            if (logger.IsDebugEnable)
            {
                logger.Debug($"Parsing {filename} completed in {DateTime.Now.Ticks - startTime} ms");
            }

            return(ast);
        }