issue #2 - fix template string scanning
`l.Prev.Rune` is actually current rune and `c` is next rune.
This commit is contained in:
		
							parent
							
								
									685b7b25bd
								
							
						
					
					
						commit
						83bb761062
					
				| @ -36,6 +36,30 @@ func TestSimpleVar(t *testing.T) { | ||||
| 	assertEqual(t, expected, actual) | ||||
| } | ||||
| 
 | ||||
| func TestSimpleVarEndsEcapsed(t *testing.T) { | ||||
| 	src := `<? "test $var\"";` | ||||
| 
 | ||||
| 	expected := &stmt.StmtList{ | ||||
| 		Stmts: []node.Node{ | ||||
| 			&stmt.Expression{ | ||||
| 				Expr: &scalar.Encapsed{ | ||||
| 					Parts: []node.Node{ | ||||
| 						&scalar.EncapsedStringPart{Value: "test "}, | ||||
| 						&expr.Variable{VarName: &node.Identifier{Value: "var"}}, | ||||
| 						&scalar.EncapsedStringPart{Value: "\\\""}, | ||||
| 					}, | ||||
| 				}, | ||||
| 			}, | ||||
| 		}, | ||||
| 	} | ||||
| 
 | ||||
| 	actual, _, _ := php7.Parse(bytes.NewBufferString(src), "test.php") | ||||
| 	assertEqual(t, expected, actual) | ||||
| 
 | ||||
| 	actual, _, _ = php5.Parse(bytes.NewBufferString(src), "test.php") | ||||
| 	assertEqual(t, expected, actual) | ||||
| } | ||||
| 
 | ||||
| func TestSimpleVarPropertyFetch(t *testing.T) { | ||||
| 	src := `<? "test $foo->bar()";` | ||||
| 
 | ||||
|  | ||||
| @ -8624,40 +8624,40 @@ yyrule149: // .|[ \t\n\r] | ||||
| 
 | ||||
| 	F1: | ||||
| 		for { | ||||
| 			if c == -1 { | ||||
| 				break | ||||
| 			} | ||||
| 			switch c { | ||||
| 			case '"': | ||||
| 				lval.Token(l.newToken(l.Token())) | ||||
| 				return T_ENCAPSED_AND_WHITESPACE | ||||
| 				break F1 | ||||
| 
 | ||||
| 			switch l.Prev.Rune { | ||||
| 			case '$': | ||||
| 				c = l.Next() | ||||
| 				if rune(c) == '{' || c >= 'A' && c <= 'Z' || c == '_' || c >= 'a' && c <= 'z' || c >= '\u007f' && c <= 'ÿ' { | ||||
| 					l.ungetChars(1) | ||||
| 				if l.Prev.Rune == '{' || c >= 'A' && c <= 'Z' || c == '_' || c >= 'a' && c <= 'z' || c >= '\u007f' && c <= 'ÿ' { | ||||
| 					l.ungetChars(2) | ||||
| 					tb := l.Token() | ||||
| 					lval.Token(l.newToken(tb[:len(tb)-1])) | ||||
| 					lval.Token(l.newToken(tb[:len(tb)-2])) | ||||
| 					return T_ENCAPSED_AND_WHITESPACE | ||||
| 					break F1 | ||||
| 				} | ||||
| 				l.ungetChars(0) | ||||
| 				l.ungetChars(1) | ||||
| 
 | ||||
| 			case '{': | ||||
| 				c = l.Next() | ||||
| 				if rune(c) == '$' { | ||||
| 					l.ungetChars(1) | ||||
| 				if l.Prev.Rune == '$' { | ||||
| 					l.ungetChars(2) | ||||
| 					tb := l.Token() | ||||
| 					lval.Token(l.newToken(tb[:len(tb)-1])) | ||||
| 					lval.Token(l.newToken(tb[:len(tb)-2])) | ||||
| 					return T_ENCAPSED_AND_WHITESPACE | ||||
| 					break F1 | ||||
| 				} | ||||
| 				l.ungetChars(0) | ||||
| 				l.ungetChars(1) | ||||
| 			case '\\': | ||||
| 				c = l.Next() | ||||
| 			} | ||||
| 			if rune(c) == '"' { | ||||
| 				lval.Token(l.newToken(l.Token())) | ||||
| 				return T_ENCAPSED_AND_WHITESPACE | ||||
| 				break F1 | ||||
| 			} | ||||
| 			c = l.Next() | ||||
| 			if c == -1 { | ||||
| 				break | ||||
| 			} | ||||
| 		} | ||||
| 		goto yystate0 | ||||
| 	} | ||||
|  | ||||
| @ -448,43 +448,44 @@ NEW_LINE        (\r|\n|\r\n) | ||||
| <STRING,HEREDOC,BACKQUOTE>\$                l.ungetChars(1);l.pushState(STRING_VAR) | ||||
| <STRING>.|[ \t\n\r] | ||||
|     F1:for { | ||||
|         if c == -1 { | ||||
|             break; | ||||
|         } | ||||
| 
 | ||||
|         switch c { | ||||
|             case '"' :  | ||||
|                 lval.Token(l.newToken(l.Token())); | ||||
|                 return T_ENCAPSED_AND_WHITESPACE | ||||
|                 break F1; | ||||
|              | ||||
|         switch l.Prev.Rune { | ||||
|             case '$': | ||||
|                 c = l.Next(); | ||||
|                 if rune(c) == '{' || c >= 'A' && c <= 'Z' || c == '_' || c >= 'a' && c <= 'z' || c >= '\u007f' && c <= 'ÿ' { | ||||
|                     l.ungetChars(1) | ||||
|                 if l.Prev.Rune == '{' || c >= 'A' && c <= 'Z' || c == '_' || c >= 'a' && c <= 'z' || c >= '\u007f' && c <= 'ÿ' { | ||||
|                     l.ungetChars(2) | ||||
|                     tb := l.Token() | ||||
|                     lval.Token(l.newToken(tb[:len(tb)-1])); | ||||
|                     lval.Token(l.newToken(tb[:len(tb)-2])); | ||||
|                     return T_ENCAPSED_AND_WHITESPACE | ||||
|                     break F1; | ||||
|                 }  | ||||
|                 l.ungetChars(0) | ||||
|                 l.ungetChars(1) | ||||
|              | ||||
|             case '{': | ||||
|                 c = l.Next(); | ||||
|                 if rune(c) == '$' { | ||||
|                     l.ungetChars(1) | ||||
|                 if l.Prev.Rune == '$' { | ||||
|                     l.ungetChars(2) | ||||
|                     tb := l.Token() | ||||
|                     lval.Token(l.newToken(tb[:len(tb)-1]));  | ||||
|                     lval.Token(l.newToken(tb[:len(tb)-2]));  | ||||
|                     return T_ENCAPSED_AND_WHITESPACE | ||||
|                     break F1; | ||||
|                 }  | ||||
|                 l.ungetChars(0) | ||||
|                 l.ungetChars(1) | ||||
| 
 | ||||
|             case '\\': | ||||
|                 c = l.Next(); | ||||
|         } | ||||
| 
 | ||||
|         if rune(c) == '"' { | ||||
|             lval.Token(l.newToken(l.Token())); | ||||
|             return T_ENCAPSED_AND_WHITESPACE | ||||
|             break F1; | ||||
|         } | ||||
| 
 | ||||
|         c = l.Next() | ||||
| 
 | ||||
|         if c == -1 { | ||||
|             break; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| <BACKQUOTE>.|[ \t\n\r] | ||||
|  | ||||
| @ -25,11 +25,11 @@ func assertEqual(t *testing.T, expected interface{}, actual interface{}) { | ||||
| } | ||||
| 
 | ||||
| type lval struct { | ||||
| 	token token.Token | ||||
| 	Tkn token.Token | ||||
| } | ||||
| 
 | ||||
| func (lv *lval) Token(t token.Token) { | ||||
| 	lv.token = t | ||||
| 	lv.Tkn = t | ||||
| } | ||||
| 
 | ||||
| func TestIdentifier(t *testing.T) { | ||||
| @ -538,3 +538,41 @@ CAT; | ||||
| 
 | ||||
| 	assertEqual(t, expected, actual) | ||||
| } | ||||
| 
 | ||||
| func TestStringTokensAfterVariable(t *testing.T) { | ||||
| 	src := `<?php "test \"$var\""` | ||||
| 
 | ||||
| 	expected := []int{ | ||||
| 		scanner.Rune2Class('"'), | ||||
| 		scanner.T_ENCAPSED_AND_WHITESPACE, | ||||
| 		scanner.T_VARIABLE, | ||||
| 		scanner.T_ENCAPSED_AND_WHITESPACE, | ||||
| 		scanner.Rune2Class('"'), | ||||
| 	} | ||||
| 
 | ||||
| 	expectedTokens := []string{ | ||||
| 		"\"", | ||||
| 		"test \\\"", | ||||
| 		"$var", | ||||
| 		"\\\"", | ||||
| 		"\"", | ||||
| 	} | ||||
| 
 | ||||
| 	lexer := scanner.NewLexer(bytes.NewBufferString(src), "test.php") | ||||
| 	lv := &lval{} | ||||
| 	actual := []int{} | ||||
| 	actualTokens := []string{} | ||||
| 
 | ||||
| 	for { | ||||
| 		token := lexer.Lex(lv) | ||||
| 		if token < 0 { | ||||
| 			break | ||||
| 		} | ||||
| 
 | ||||
| 		actualTokens = append(actualTokens, lv.Tkn.Value) | ||||
| 		actual = append(actual, token) | ||||
| 	} | ||||
| 
 | ||||
| 	assertEqual(t, expected, actual) | ||||
| 	assertEqual(t, expectedTokens, actualTokens) | ||||
| } | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user