[vala] Genie: Added string templating
- From: Jamie McCracken <jamiemcc src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [vala] Genie: Added string templating
- Date: Mon, 24 May 2010 19:26:34 +0000 (UTC)
commit e8142d02d0b0a16d3792cdffc31257e621690325
Author: Jamie McCracken <jamie mccrack gmail com>
Date: Mon May 24 13:52:55 2010 -0400
Genie: Added string templating
vala/valagenieparser.vala | 28 ++++++-
vala/valageniescanner.vala | 184 +++++++++++++++++++++++++++++++++++++++--
vala/valagenietokentype.vala | 3 +
3 files changed, 204 insertions(+), 11 deletions(-)
---
diff --git a/vala/valagenieparser.vala b/vala/valagenieparser.vala
index 02c759f..6397596 100644
--- a/vala/valagenieparser.vala
+++ b/vala/valagenieparser.vala
@@ -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);
}
diff --git a/vala/valageniescanner.vala b/vala/valageniescanner.vala
index 50a02a5..aacc3ed 100644
--- a/vala/valageniescanner.vala
+++ b/vala/valageniescanner.vala
@@ -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 '.':
diff --git a/vala/valagenietokentype.vala b/vala/valagenietokentype.vala
index a17807a..30ed7ba 100644
--- a/vala/valagenietokentype.vala
+++ b/vala/valagenietokentype.vala
@@ -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,
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]