Skip to content

Commit

Permalink
Try parsing for all lines of muli-line character literal. Fixes #675 (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
kamphaus authored and elliotchance committed Apr 26, 2018
1 parent d9c08ad commit a95ff5d
Show file tree
Hide file tree
Showing 3 changed files with 101 additions and 28 deletions.
66 changes: 39 additions & 27 deletions ast/character_literal.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,45 +81,57 @@ func RepairCharacterLiteralsFromSource(rootNode Node, preprocessedFile string) [

for _, node := range characterLiteralNodes {
cNode := node.(*CharacterLiteral)

// Use the node position to retrieve the original line from the
// preprocessed source.
pos := node.Position()
line, err :=
cc.GetLineFromPreprocessedFile(preprocessedFile, pos.File, pos.Line)

// If there was a problem reading the line we should raise a warning and
// use the value we have. Hopefully that will be an accurate enough
// representation.
var (
err error
lastLine = pos.LineEnd
i int
)
if lastLine == 0 {
lastLine = pos.Line
}
for line := pos.Line; line <= lastLine; line++ {
i, err = parseCharacterLiteralFromPosition(preprocessedFile, pos, line)
if err == nil {
cNode.Value = i
break
}
}
if err != nil {
errs = append(errs, CharacterLiteralError{
Node: cNode,
Err: err,
})
}

// Extract the exact value from the line.
if pos.Column-1 >= len(line) {
errs = append(errs, CharacterLiteralError{
Node: cNode,
Err: errors.New("cannot get exact value"),
})
} else {
literal := line[pos.Column-1:]
if i, err := parseCharacterLiteralFromSource(literal); err == nil {
cNode.Value = i
} else {
errs = append(errs, CharacterLiteralError{
Node: cNode,
Err: fmt.Errorf("cannot parse character literal: %v from %s", err, literal),
})
}
}
}

return errs
}

func parseCharacterLiteralFromPosition(preprocessedFile string, pos Position, lineNbr int) (ret int, err error) {
// Use the node position to retrieve the original line from the
// preprocessed source.
line, err :=
cc.GetLineFromPreprocessedFile(preprocessedFile, pos.File, lineNbr)

// If there was a problem reading the line we should raise a warning and
// use the value we have. Hopefully that will be an accurate enough
// representation.
if err != nil {
return 0, err
}

// Extract the exact value from the line.
if pos.Column-1 >= len(line) {
return 0, errors.New("cannot get exact value")
}
literal := line[pos.Column-1:]
if ret, err = parseCharacterLiteralFromSource(literal); err == nil {
return ret, nil
}
return 0, fmt.Errorf("cannot parse character literal: %v from %s", err, literal)
}

func parseCharacterLiteralFromSource(literal string) (ret int, err error) {
runes := []rune(literal)
if len(runes) < 1 {
Expand Down
39 changes: 39 additions & 0 deletions ast/character_literal_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -361,3 +361,42 @@ func prepareRepairFromSourceTest(t *testing.T, fileContent string, test func(fil

test(ppFilePath)
}

func TestCharacterLiteralRepairFromSourceMultiline(t *testing.T) {
cl := &CharacterLiteral{
Addr: 0x7f980b858308,
Pos: NewPositionFromString("col:12"),
Type: "int",
Value: 10,
ChildNodes: []Node{},
}
cl.Pos.LineEnd = 6
root := &CompoundStmt{
Pos: Position{File: "dummy.c", Line: 5},
ChildNodes: []Node{cl},
}
FixPositions([]Node{root})
type test struct {
file string
expected int
err error
}
tests := []test{
{"# 2 \"x.c\"\n\n# 4 \"dummy.c\"ff\nxxxxx\nvar xyst = '\nxxxxxxxxx, };\nyyyy", 10, fmt.Errorf("cannot parse character literal: illegal character '}' at index 0 from };")},
{"# 2 \"x.c\"\n\n# 4 \"dummy.c\"ff\nxxxxx\nvar xyst = 'A'zzz\nyyyy", int('A'), nil},
{"# 2 \"x.c\"\n\n# 4 \"dummy.c\"ff\nxxxxx\nvar xyst = {\nxxxxxxxxx, 'B'};\nyyyy", int('B'), nil},
}
for _, test := range tests {
prepareRepairFromSourceTest(t, test.file, func(ppFilePath string) {
errors := RepairCharacterLiteralsFromSource(root, ppFilePath)
if cl.Value != test.expected {
t.Errorf("RepairCharacterLiteralsFromSource - expected: %x, got: %x", test.expected, cl.Value)
}
if test.err != nil && len(errors) == 0 || test.err == nil && len(errors) != 0 {
t.Errorf("RepairCharacterLiteralsFromSource - error should match: expected: %v, got: %v", test.err, errors)
} else if test.err != nil && errors[0].Err.Error() != test.err.Error() {
t.Errorf("RepairCharacterLiteralsFromSource - error should match: expected: %s, got: %s", test.err.Error(), errors[0].Err.Error())
}
})
}
}
24 changes: 23 additions & 1 deletion tests/cast.c
Original file line number Diff line number Diff line change
Expand Up @@ -93,14 +93,33 @@ void test_preprocessor()
}

typedef unsigned char pcre_uchar;

void caststr() {
pcre_uchar str[] = "abcd";
is_streq((char *) str, "abcd");
}

static const pcre_uchar TEST[] = {
'x', (pcre_uchar) CHAR_NBSP, '\n', '\0' };

#define CHAR_E ((unsigned char) 'e')
static const pcre_uchar TEST2[] = {
'x', (pcre_uchar) CHAR_NBSP, '\n',
(pcre_uchar) CHAR_E, '\0' };


void test_static_array()
{
is_eq('x', TEST[0]);
is_eq((pcre_uchar) '\xa0', TEST[1]);
is_eq('\n', TEST[2]);
is_eq('x', TEST2[0]);
is_eq('e', TEST2[3]); // can distinguish character at same column in different lines
}

int main()
{
plan(31);
plan(36);

START_TEST(cast);
START_TEST(castbool);
Expand Down Expand Up @@ -194,5 +213,8 @@ int main()
diag("Typedef slice convertion")
caststr();

diag("Compare with static array")
test_static_array();

done_testing();
}

0 comments on commit a95ff5d

Please sign in to comment.