예제 #1
0
        private static string ParseExpression(string code, string id, ParseMode mode, bool whenCondition, DekiScriptEnv env, DekiScriptRuntime runtime, Dictionary<string, string> channels, ref int i) {
            StringBuilder result = new StringBuilder();
            int nesting = 0;
            for(; i < code.Length; ++i) {
                int start;
                switch(code[i]) {
                case '"':
                case '\'':

                    // process strings
                    start = i;
                    ScanString(code, code[i], ref i);
                    result.Append(code, start, i - start);
                    --i;
                    break;
                case '/':

                    // check if / denotes the beginning of a comment, if so process it
                    start = i;
                    if(TryScanComment(code, ref i)) {

                        // NOTE: remove comments in when-condition

                        if(!whenCondition) {
                            result.Append(code, start, i - start);
                            result.Append("\n");
                        }
                        --i;
                    } else {
                        result.Append(code[i]);
                    }
                    break;
                case '\\':

                    // backslash (\) always appends the next character
                    result.Append(code[i++]);
                    if(i < code.Length) {
                        result.Append(code[i]);
                    }
                    break;
                case '(':

                    // increase nesting level
                    result.Append(code[i]);
                    ++nesting;
                    break;
                case '{':

                    // check if this is the beginning of a dekiscript block {{ }}
                    if(((i + 1) < code.Length) && (code[i + 1] == '{')) {
                        ++i;
                        string value;
                        start = i;
                        if(TryParseDekiScriptExpression(code, env, runtime, ref i, out value)) {
                            result.Append(value);
                        } else {
                            ++nesting;
                            result.Append('{');
                            result.Append(code, start, i - start);
                            --i;
                        }
                    } else {
                        ++nesting;
                        result.Append(code[i]);
                    }
                    break;
                case ')':
                case '}':

                    // decrease nesting level and check if this is the end of the sougth expression
                    result.Append(code[i]);
                    --nesting;

                    // NOTE: only exit if
                    // 1) we don't have to read all of the code
                    // 2) there are no open parentheses or cruly braces
                    // 3) we don't on a complete statement or the current characteris a closing curly brace

                    if((mode != ParseMode.ALL) && (nesting <= 0) && ((mode != ParseMode.STATEMENT) || (code[i] == '}'))) {

                        // found the end of the expression
                        ++i;
                        return result.ToString();
                    }
                    break;
                case ';':

                    // check if the statement is the end of the sougth expression
                    result.Append(code[i]);

                    // NOTE: only exit if
                    // 1) we don't have to read all of the code
                    // 2) there are no open parentheses or cruly braces
                    // 3) we stop on a complete statement

                    if((nesting <= 0) && (mode == ParseMode.STATEMENT)) {

                        // found the end of the expression
                        ++i;
                        return result.ToString();
                    }
                    break;
                case '@':

                    // channel name
                    if(channels != null) {
                        ++i;
                        start = i;
                        string channel;
                        string name;
                        if((i < code.Length) && ((code[i] == '"') || (code[i] == '\''))) {

                            // process: @"channel_name" or @'channel_name'
                            ScanString(code, code[i], ref i);
                            channel = code.Substring(start, i - start);
                            name = channel.Substring(1, channel.Length - 2).UnescapeString();
                        } else {

                            // process: @channel_magic_id
                            ScanId(code, ref i);
                            name = code.Substring(start, i - start);
                            if(!channels.TryGetValue(name, out channel)) {
                                channel = env.GetMagicId(name).ToString();
                            }
                        }
                        start = i;
                        ScanWhitespace(code, ref i);
                        if((i < code.Length) && (code[i] == '(')) {

                            // process: @channel ( ... )
                            string message = ParseExpression(code, id, ParseMode.EXPRESSION, false, env, runtime, channels, ref i);
                            message = message.Substring(1, message.Length - 2).Trim();
                            if(message.Length == 0) {
                                result.AppendFormat("Deki.publish({0})", channel);
                            } else {
                                result.AppendFormat("Deki.publish({0}, {1})", channel, message);
                            }
                        } else {

                            // channel is used for reading; add it to the channel set to read on activation
                            channels[name] = channel;

                            // convert channel name and add whitespace
                            result.AppendFormat("$channels[{0}]", name.QuoteString());
                            result.Append(code, start, i - start);
                        }
                        --i;
                    } else {
                        result.Append(code[i]);
                    }
                    break;
                case '#':

                    // NOTE: don't process #id in the when-condition

                    // element name
                    if(!whenCondition && (channels != null)) {
                        ++i;
                        start = i;

                        // process: #id
                        ScanId(code, ref i);
                        string name = code.Substring(start, i - start);
                        result.Append("$(\"#" + name + "\")");
                        --i;
                    } else {
                        result.Append(code[i]);
                    }
                    break;
                default:

                    // NOTE: don't process when() in the when-condition

                    // check if this is the beginning of an identifier
                    if(!whenCondition && IsAlpha(code[i])) {
                        start = i;
                        ScanId(code, ref i);
                        int j = i;
                        ScanWhitespace(code, ref j);

                        // check if scanned identifier is the keyword 'when'
                        if(((i - start) == WHEN.Length) && (string.Compare(code, start, WHEN, 0, WHEN.Length, StringComparison.Ordinal) == 0) && (j < code.Length) && (code[j] == '(')) {
                            i = j;
                            Dictionary<string, string> subChannels = new Dictionary<string, string>();

                            // parse the condition of the 'when()' statement
                            string condition = ParseExpression(code, id, ParseMode.EXPRESSION, true, env, runtime, subChannels, ref i);

                            // parse the body of the 'when()' expression
                            string body = ParseExpression(code, id, ParseMode.STATEMENT, false, env, runtime, subChannels, ref i);
                            BuildWhenStatement(condition.Trim(), id, body.Trim(), result, env, subChannels);
                        } else {
                            result.Append(code, start, i - start);
                        }
                        --i;
                    } else {
                        result.Append(code[i]);
                    }
                    break;
                }
            }
            return result.ToString();
        }