]> git.ipfire.org Git - thirdparty/vala.git/commitdiff
Genie: Added string templating
authorJamie McCracken <jamie.mccrack@gmail.com>
Mon, 24 May 2010 17:52:55 +0000 (13:52 -0400)
committerJamie McCracken <jamie.mccrack gmail com>
Mon, 24 May 2010 19:26:07 +0000 (15:26 -0400)
vala/valagenieparser.vala
vala/valageniescanner.vala
vala/valagenietokentype.vala

index 02c759f7d5d58320640250a2273c6003af531a5e..6397596418caae54e022e3b3d259bc75a8747f14 100644 (file)
@@ -342,6 +342,9 @@ public class Vala.Genie.Parser : CodeVisitor {
                case TokenType.STRING_LITERAL:
                        next ();
                        return new StringLiteral (get_last_string (), get_src (begin));
+               case TokenType.TEMPLATE_STRING_LITERAL:
+                       next ();
+                       return new StringLiteral ("\"%s\"".printf (get_last_string ()), get_src (begin));
                case TokenType.VERBATIM_STRING_LITERAL:
                        next ();
                        string raw_string = get_last_string ();
@@ -623,6 +626,7 @@ public class Vala.Genie.Parser : CodeVisitor {
                case TokenType.REAL_LITERAL:
                case TokenType.CHARACTER_LITERAL:
                case TokenType.STRING_LITERAL:
+               case TokenType.TEMPLATE_STRING_LITERAL:
                case TokenType.VERBATIM_STRING_LITERAL:
                case TokenType.NULL:
                        expr = parse_literal ();
@@ -635,6 +639,9 @@ public class Vala.Genie.Parser : CodeVisitor {
                case TokenType.OPEN_PARENS:
                        expr = parse_tuple ();
                        break;
+               case TokenType.OPEN_TEMPLATE:
+                       expr = parse_template ();
+                       break;
                case TokenType.THIS:
                        expr = parse_this_access ();
                        break;
@@ -705,6 +712,21 @@ public class Vala.Genie.Parser : CodeVisitor {
                return expr;
        }
 
+       Expression parse_template () throws ParseError {
+               var begin = get_location ();
+               var template = new Template ();
+
+               expect (TokenType.OPEN_TEMPLATE);
+               while (current () != TokenType.CLOSE_TEMPLATE) {
+                       template.add_expression (parse_expression ());
+                       expect (TokenType.COMMA);
+               }
+               expect (TokenType.CLOSE_TEMPLATE);
+
+               template.source_reference = get_src (begin);
+               return template;
+       }
+
        Expression parse_tuple () throws ParseError {
                expect (TokenType.OPEN_PARENS);
                var expr_list = new ArrayList<Expression> ();
@@ -1170,6 +1192,7 @@ public class Vala.Genie.Parser : CodeVisitor {
                                        case TokenType.REAL_LITERAL:
                                        case TokenType.CHARACTER_LITERAL:
                                        case TokenType.STRING_LITERAL:
+                                       case TokenType.TEMPLATE_STRING_LITERAL:
                                        case TokenType.VERBATIM_STRING_LITERAL:
                                        case TokenType.NULL:
                                        case TokenType.THIS:
@@ -3063,14 +3086,15 @@ public class Vala.Genie.Parser : CodeVisitor {
                if (ModifierFlags.NEW in flags) {
                        sig.hides = true;
                }
-               set_attributes (sig, attrs);
                
                if (ModifierFlags.STATIC in flags) {
                        throw new ParseError.SYNTAX (get_error ("`static' modifier not allowed on signals"));
                } else if (ModifierFlags.CLASS in flags) {
                        throw new ParseError.SYNTAX (get_error ("`class' modifier not allowed on signals"));
                }
-               
+
+               set_attributes (sig, attrs);
+
                foreach (FormalParameter formal_param in params) {
                        sig.add_parameter (formal_param);
                }
index 50a02a5f34850ed8e0e6ccff5e14935d85ab526f..aacc3edfab989b5197b2c5a23da1a992a027546b 100644 (file)
@@ -58,6 +58,16 @@ public class Vala.Genie.Scanner {
                public bool else_found;
                public bool skip_section;
        }
+
+       State[] state_stack;
+
+       enum State {
+               PARENS,
+               BRACE,
+               BRACKET,
+               TEMPLATE,
+               TEMPLATE_PART
+       }
        
        public Scanner (SourceFile source_file) {
                this.source_file = source_file;
@@ -82,6 +92,14 @@ public class Vala.Genie.Scanner {
                
        }
 
+       bool in_template () {
+               return (state_stack.length > 0 && state_stack[state_stack.length - 1] == State.TEMPLATE);
+       }
+
+       bool in_template_part () {
+               return (state_stack.length > 0 && state_stack[state_stack.length - 1] == State.TEMPLATE_PART);
+       }
+
        bool is_ident_char (char c) {
                return (c.isalnum () || c == '_');
        }
@@ -459,7 +477,128 @@ public class Vala.Genie.Scanner {
                return TokenType.IDENTIFIER;
        }
 
+       
+       public TokenType read_template_token (out SourceLocation token_begin, out SourceLocation token_end) {
+               TokenType type;
+               char* begin = current;
+               token_begin.pos = begin;
+               token_begin.line = line;
+               token_begin.column = column;
+
+               int token_length_in_chars = -1;
+
+               if (current >= end) {
+                       type = TokenType.EOF;
+               } else {
+                       switch (current[0]) {
+                       case '"':
+                               type = TokenType.CLOSE_TEMPLATE;
+                               current++;
+                               state_stack.length--;
+                               break;
+                       case '$':
+                               token_begin.pos++; // $ is not part of following token
+                               current++;
+                               if (current[0].isalpha () || current[0] == '_') {
+                                       int len = 0;
+                                       while (current < end && is_ident_char (current[0])) {
+                                               current++;
+                                               len++;
+                                       }
+                                       type = TokenType.IDENTIFIER;
+                                       state_stack += State.TEMPLATE_PART;
+                               } else if (current[0] == '(') {
+                                       current++;
+                                       column += 2;
+                                       state_stack += State.PARENS;
+                                       return read_token (out token_begin, out token_end);
+                               } else if (current[0] == '$') {
+                                       type = TokenType.TEMPLATE_STRING_LITERAL;
+                                       current++;
+                                       state_stack += State.TEMPLATE_PART;
+                               } else {
+                                       Report.error (new SourceReference (source_file, line, column + 1, line, column + 1), "unexpected character");
+                                       return read_template_token (out token_begin, out token_end);
+                               }
+                               break;
+                       default:
+                               type = TokenType.TEMPLATE_STRING_LITERAL;
+                               token_length_in_chars = 0;
+                               while (current < end && current[0] != '"' && current[0] != '$') {
+                                       if (current[0] == '\\') {
+                                               current++;
+                                               token_length_in_chars++;
+                                               if (current >= end) {
+                                                       break;
+                                               }
+
+                                               switch (current[0]) {
+                                               case '\'':
+                                               case '"':
+                                               case '\\':
+                                               case '0':
+                                               case 'b':
+                                               case 'f':
+                                               case 'n':
+                                               case 'r':
+                                               case 't':
+                                                       current++;
+                                                       token_length_in_chars++;
+                                                       break;
+                                               case 'x':
+                                                       // hexadecimal escape character
+                                                       current++;
+                                                       token_length_in_chars++;
+                                                       while (current < end && current[0].isxdigit ()) {
+                                                               current++;
+                                                               token_length_in_chars++;
+                                                       }
+                                                       break;
+                                               default:
+                                                       Report.error (new SourceReference (source_file, line, column + token_length_in_chars, line, column + token_length_in_chars), "invalid escape sequence");
+                                                       break;
+                                               }
+                                       } else if (current[0] == '\n') {
+                                               break;
+                                       } else {
+                                               unichar u = ((string) current).get_char_validated ((long) (end - current));
+                                               if (u != (unichar) (-1)) {
+                                                       current += u.to_utf8 (null);
+                                                       token_length_in_chars++;
+                                               } else {
+                                                       current++;
+                                                       Report.error (new SourceReference (source_file, line, column + token_length_in_chars, line, column + token_length_in_chars), "invalid UTF-8 character");
+                                               }
+                                       }
+                               }
+                               if (current >= end || current[0] == '\n') {
+                                       Report.error (new SourceReference (source_file, line, column + token_length_in_chars, line, column + token_length_in_chars), "syntax error, expected \"");
+                                       state_stack.length--;
+                                       return read_token (out token_begin, out token_end);
+                               }
+                               state_stack += State.TEMPLATE_PART;
+                               break;
+                       }
+               }
+
+               if (token_length_in_chars < 0) {
+                       column += (int) (current - begin);
+               } else {
+                       column += token_length_in_chars;
+               }
+
+               token_end.pos = current;
+               token_end.line = line;
+               token_end.column = column - 1;
+
+               return type;
+       }
+
+
        public TokenType read_token (out SourceLocation token_begin, out SourceLocation token_end) {
+               
+
+
                /* emit dedents if outstanding before checking any other chars */
 
                if (pending_dedents > 0) {
@@ -481,6 +620,23 @@ public class Vala.Genie.Scanner {
                }
 
 
+               if (in_template ()) {
+                       return read_template_token (out token_begin, out token_end);
+               } else if (in_template_part ()) {
+                       state_stack.length--;
+
+                       token_begin.pos = current;
+                       token_begin.line = line;
+                       token_begin.column = column;
+
+                       token_end.pos = current;
+                       token_end.line = line;
+                       token_end.column = column - 1;
+
+                       return TokenType.COMMA;
+               }
+
+
                if ((_indent_spaces == 0 ) || (last_token != TokenType.EOL)) {
                        /* scrub whitespace (excluding newlines) and comments */                
                        space ();
@@ -583,19 +739,20 @@ public class Vala.Genie.Scanner {
                        }
                        type = get_identifier_or_keyword (begin, len);
                } else if (current[0] == '@') {
-                       int len = 0;
-                       if (current[1] == '@') {
-                               token_begin.pos += 2; // @@ is not part of the identifier
+                       if (current < end - 1 && current[1] == '"') {
+                               type = TokenType.OPEN_TEMPLATE;
                                current += 2;
+                               state_stack += State.TEMPLATE;
                        } else {
+                               token_begin.pos++; // @ is not part of the identifier
                                current++;
-                               len = 1;
-                       }
-                       while (current < end && is_ident_char (current[0])) {
-                               current++;
-                               len++;
+                               int len = 0;
+                               while (current < end && is_ident_char (current[0])) {
+                                       current++;
+                                       len++;
+                               }
+                               type = TokenType.IDENTIFIER;
                        }
-                       type = TokenType.IDENTIFIER;
                } else if (current[0].isdigit ()) {
                        while (current < end && current[0].isdigit ()) {
                                current++;
@@ -652,29 +809,38 @@ public class Vala.Genie.Scanner {
                        case '{':
                                type = TokenType.OPEN_BRACE;
                                open_brace_count++;
+                               state_stack += State.BRACE;
                                current++;
                                break;
                        case '}':
                                type = TokenType.CLOSE_BRACE;
                                open_brace_count--;
+                               state_stack.length--;
                                current++;
                                break;
                        case '(':
                                type = TokenType.OPEN_PARENS;
                                open_parens_count++;
+                               state_stack += State.PARENS;
                                current++;
                                break;
                        case ')':
                                type = TokenType.CLOSE_PARENS;
                                open_parens_count--;
                                current++;
+                               state_stack.length--;
+                               if (in_template ()) {
+                                       type = TokenType.COMMA;
+                               }
                                break;
                        case '[':
                                type = TokenType.OPEN_BRACKET;
+                               state_stack += State.BRACKET;
                                current++;
                                break;
                        case ']':
                                type = TokenType.CLOSE_BRACKET;
+                               state_stack.length--;
                                current++;
                                break;
                        case '.':
index a17807a23726a306ff3aba0d1f784c9f2a7508aa..30ed7bac6e9ecc58d03d031a122967cd21d9439e 100644 (file)
@@ -50,6 +50,7 @@ public enum Vala.Genie.TokenType {
        CLOSE_BRACE,
        CLOSE_BRACKET,
        CLOSE_PARENS,
+       CLOSE_TEMPLATE,
        COLON,
        COMMA,
        CONST,
@@ -120,6 +121,7 @@ public enum Vala.Genie.TokenType {
        OPEN_BRACE,
        OPEN_BRACKET,
        OPEN_PARENS,
+       OPEN_TEMPLATE,
        OVERRIDE,
        OWNED,
        PARAMS,
@@ -146,6 +148,7 @@ public enum Vala.Genie.TokenType {
        STRING_LITERAL,
        STRUCT,
        SUPER,
+       TEMPLATE_STRING_LITERAL,
        THIS,
        TILDE,
        TO,