mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
gofmt the last outstanding files in src/pkg
- added a list of issues to printer/nodes.go R=rsc http://go/go-review/1024002
This commit is contained in:
parent
39fd52d3a0
commit
0ea9dd815a
7 changed files with 330 additions and 313 deletions
|
|
@ -623,7 +623,7 @@ const (
|
||||||
string */
|
string */
|
||||||
DF_SYMBOLIC DynFlag = 0x0002; /* Indicates "symbolic" linking. */
|
DF_SYMBOLIC DynFlag = 0x0002; /* Indicates "symbolic" linking. */
|
||||||
DF_TEXTREL DynFlag = 0x0004; /* Indicates there may be relocations in
|
DF_TEXTREL DynFlag = 0x0004; /* Indicates there may be relocations in
|
||||||
non-writable segments. */
|
non-writable segments. */
|
||||||
DF_BIND_NOW DynFlag = 0x0008; /* Indicates that the dynamic linker should
|
DF_BIND_NOW DynFlag = 0x0008; /* Indicates that the dynamic linker should
|
||||||
process all relocations for the object
|
process all relocations for the object
|
||||||
containing this entry before transferring
|
containing this entry before transferring
|
||||||
|
|
@ -1394,7 +1394,7 @@ type Header32 struct {
|
||||||
*/
|
*/
|
||||||
type Section32 struct {
|
type Section32 struct {
|
||||||
Name uint32; /* Section name (index into the
|
Name uint32; /* Section name (index into the
|
||||||
section header string table). */
|
section header string table). */
|
||||||
Type uint32; /* Section type. */
|
Type uint32; /* Section type. */
|
||||||
Flags uint32; /* Section flags. */
|
Flags uint32; /* Section flags. */
|
||||||
Addr uint32; /* Address in memory image. */
|
Addr uint32; /* Address in memory image. */
|
||||||
|
|
@ -1508,7 +1508,7 @@ type Header64 struct {
|
||||||
|
|
||||||
type Section64 struct {
|
type Section64 struct {
|
||||||
Name uint32; /* Section name (index into the
|
Name uint32; /* Section name (index into the
|
||||||
section header string table). */
|
section header string table). */
|
||||||
Type uint32; /* Section type. */
|
Type uint32; /* Section type. */
|
||||||
Flags uint64; /* Section flags. */
|
Flags uint64; /* Section flags. */
|
||||||
Addr uint64; /* Address in memory image. */
|
Addr uint64; /* Address in memory image. */
|
||||||
|
|
|
||||||
|
|
@ -232,40 +232,40 @@ type Formatter func(state *State, value interface{}, ruleName string) bool
|
||||||
// A FormatterMap is a set of custom formatters.
|
// A FormatterMap is a set of custom formatters.
|
||||||
// It maps a rule name to a formatter function.
|
// It maps a rule name to a formatter function.
|
||||||
//
|
//
|
||||||
type FormatterMap map [string] Formatter;
|
type FormatterMap map[string]Formatter
|
||||||
|
|
||||||
|
|
||||||
// A parsed format expression is built from the following nodes.
|
// A parsed format expression is built from the following nodes.
|
||||||
//
|
//
|
||||||
type (
|
type (
|
||||||
expr interface {};
|
expr interface{};
|
||||||
|
|
||||||
alternatives []expr; // x | y | z
|
alternatives []expr; // x | y | z
|
||||||
|
|
||||||
sequence []expr; // x y z
|
sequence []expr; // x y z
|
||||||
|
|
||||||
literal [][]byte; // a list of string segments, possibly starting with '%'
|
literal [][]byte; // a list of string segments, possibly starting with '%'
|
||||||
|
|
||||||
field struct {
|
field struct {
|
||||||
fieldName string; // including "@", "*"
|
fieldName string; // including "@", "*"
|
||||||
ruleName string; // "" if no rule name specified
|
ruleName string; // "" if no rule name specified
|
||||||
};
|
};
|
||||||
|
|
||||||
group struct {
|
group struct {
|
||||||
indent, body expr; // (indent >> body)
|
indent, body expr; // (indent >> body)
|
||||||
};
|
};
|
||||||
|
|
||||||
option struct {
|
option struct {
|
||||||
body expr; // [body]
|
body expr; // [body]
|
||||||
};
|
};
|
||||||
|
|
||||||
repetition struct {
|
repetition struct {
|
||||||
body, separator expr; // {body / separator}
|
body, separator expr; // {body / separator}
|
||||||
};
|
};
|
||||||
|
|
||||||
custom struct {
|
custom struct {
|
||||||
ruleName string;
|
ruleName string;
|
||||||
fun Formatter
|
fun Formatter;
|
||||||
};
|
};
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -273,7 +273,7 @@ type (
|
||||||
// A Format is the result of parsing a format specification.
|
// A Format is the result of parsing a format specification.
|
||||||
// The format may be applied repeatedly to format values.
|
// The format may be applied repeatedly to format values.
|
||||||
//
|
//
|
||||||
type Format map [string] expr;
|
type Format map[string]expr
|
||||||
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
|
@ -290,7 +290,7 @@ type Format map [string] expr;
|
||||||
// the receiver, and thus can be very light-weight.
|
// the receiver, and thus can be very light-weight.
|
||||||
//
|
//
|
||||||
type Environment interface {
|
type Environment interface {
|
||||||
Copy() Environment
|
Copy() Environment;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -298,15 +298,15 @@ type Environment interface {
|
||||||
// It is provided as argument to custom formatters.
|
// It is provided as argument to custom formatters.
|
||||||
//
|
//
|
||||||
type State struct {
|
type State struct {
|
||||||
fmt Format; // format in use
|
fmt Format; // format in use
|
||||||
env Environment; // user-supplied environment
|
env Environment; // user-supplied environment
|
||||||
errors chan os.Error; // not chan *Error (errors <- nil would be wrong!)
|
errors chan os.Error; // not chan *Error (errors <- nil would be wrong!)
|
||||||
hasOutput bool; // true after the first literal has been written
|
hasOutput bool; // true after the first literal has been written
|
||||||
indent bytes.Buffer; // current indentation
|
indent bytes.Buffer; // current indentation
|
||||||
output bytes.Buffer; // format output
|
output bytes.Buffer; // format output
|
||||||
linePos token.Position; // position of line beginning (Column == 0)
|
linePos token.Position; // position of line beginning (Column == 0)
|
||||||
default_ expr; // possibly nil
|
default_ expr; // possibly nil
|
||||||
separator expr; // possibly nil
|
separator expr; // possibly nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -365,22 +365,22 @@ func (s *State) Write(data []byte) (int, os.Error) {
|
||||||
// write text segment and indentation
|
// write text segment and indentation
|
||||||
n1, _ := s.output.Write(data[i0 : i+1]);
|
n1, _ := s.output.Write(data[i0 : i+1]);
|
||||||
n2, _ := s.output.Write(s.indent.Bytes());
|
n2, _ := s.output.Write(s.indent.Bytes());
|
||||||
n += n1 + n2;
|
n += n1+n2;
|
||||||
i0 = i + 1;
|
i0 = i+1;
|
||||||
s.linePos.Offset = s.output.Len();
|
s.linePos.Offset = s.output.Len();
|
||||||
s.linePos.Line++;
|
s.linePos.Line++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
n3, _ := s.output.Write(data[i0 : len(data)]);
|
n3, _ := s.output.Write(data[i0:len(data)]);
|
||||||
return n + n3, nil;
|
return n+n3, nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
type checkpoint struct {
|
type checkpoint struct {
|
||||||
env Environment;
|
env Environment;
|
||||||
hasOutput bool;
|
hasOutput bool;
|
||||||
outputLen int;
|
outputLen int;
|
||||||
linePos token.Position;
|
linePos token.Position;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -489,13 +489,13 @@ func (s *State) eval(fexpr expr, value reflect.Value, index int) bool {
|
||||||
if s.hasOutput {
|
if s.hasOutput {
|
||||||
// not the first literal
|
// not the first literal
|
||||||
if s.separator != nil {
|
if s.separator != nil {
|
||||||
sep := s.separator; // save current separator
|
sep := s.separator; // save current separator
|
||||||
s.separator = nil; // and disable it (avoid recursion)
|
s.separator = nil; // and disable it (avoid recursion)
|
||||||
mark := s.save();
|
mark := s.save();
|
||||||
if !s.eval(sep, value, index) {
|
if !s.eval(sep, value, index) {
|
||||||
s.restore(mark);
|
s.restore(mark);
|
||||||
}
|
}
|
||||||
s.separator = sep; // enable it again
|
s.separator = sep; // enable it again
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
s.hasOutput = true;
|
s.hasOutput = true;
|
||||||
|
|
@ -505,7 +505,7 @@ func (s *State) eval(fexpr expr, value reflect.Value, index int) bool {
|
||||||
// segment contains a %-format at the beginning
|
// segment contains a %-format at the beginning
|
||||||
if lit[1] == '%' {
|
if lit[1] == '%' {
|
||||||
// "%%" is printed as a single "%"
|
// "%%" is printed as a single "%"
|
||||||
s.Write(lit[1 : len(lit)]);
|
s.Write(lit[1:len(lit)]);
|
||||||
} else {
|
} else {
|
||||||
// use s instead of s.output to get indentation right
|
// use s instead of s.output to get indentation right
|
||||||
fmt.Fprintf(s, string(lit), value.Interface());
|
fmt.Fprintf(s, string(lit), value.Interface());
|
||||||
|
|
@ -515,7 +515,7 @@ func (s *State) eval(fexpr expr, value reflect.Value, index int) bool {
|
||||||
s.Write(lit);
|
s.Write(lit);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true; // a literal never evaluates to nil
|
return true; // a literal never evaluates to nil
|
||||||
|
|
||||||
case *field:
|
case *field:
|
||||||
// determine field value
|
// determine field value
|
||||||
|
|
@ -580,7 +580,7 @@ func (s *State) eval(fexpr expr, value reflect.Value, index int) bool {
|
||||||
ruleName := t.ruleName;
|
ruleName := t.ruleName;
|
||||||
if ruleName == "" {
|
if ruleName == "" {
|
||||||
// no alternate rule name, value type determines rule
|
// no alternate rule name, value type determines rule
|
||||||
ruleName = typename(value.Type())
|
ruleName = typename(value.Type());
|
||||||
}
|
}
|
||||||
fexpr = s.getFormat(ruleName);
|
fexpr = s.getFormat(ruleName);
|
||||||
|
|
||||||
|
|
@ -620,10 +620,10 @@ func (s *State) eval(fexpr expr, value reflect.Value, index int) bool {
|
||||||
// evaluate the body and append the result to the state's output
|
// evaluate the body and append the result to the state's output
|
||||||
// buffer unless the result is nil
|
// buffer unless the result is nil
|
||||||
mark := s.save();
|
mark := s.save();
|
||||||
if !s.eval(t.body, value, 0) { // TODO is 0 index correct?
|
if !s.eval(t.body, value, 0) { // TODO is 0 index correct?
|
||||||
s.restore(mark);
|
s.restore(mark);
|
||||||
}
|
}
|
||||||
return true; // an option never evaluates to nil
|
return true; // an option never evaluates to nil
|
||||||
|
|
||||||
case *repetition:
|
case *repetition:
|
||||||
// evaluate the body and append the result to the state's output
|
// evaluate the body and append the result to the state's output
|
||||||
|
|
@ -643,7 +643,7 @@ func (s *State) eval(fexpr expr, value reflect.Value, index int) bool {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true; // a repetition never evaluates to nil
|
return true; // a repetition never evaluates to nil
|
||||||
|
|
||||||
case *custom:
|
case *custom:
|
||||||
// invoke the custom formatter to obtain the result
|
// invoke the custom formatter to obtain the result
|
||||||
|
|
@ -680,14 +680,14 @@ func (f Format) Eval(env Environment, args ...) ([]byte, os.Error) {
|
||||||
for i := 0; i < value.NumField(); i++ {
|
for i := 0; i < value.NumField(); i++ {
|
||||||
fld := value.Field(i);
|
fld := value.Field(i);
|
||||||
mark := s.save();
|
mark := s.save();
|
||||||
if !s.eval(s.getFormat(typename(fld.Type())), fld, 0) { // TODO is 0 index correct?
|
if !s.eval(s.getFormat(typename(fld.Type())), fld, 0) { // TODO is 0 index correct?
|
||||||
s.restore(mark);
|
s.restore(mark);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
errors <- nil; // no errors
|
errors <- nil; // no errors
|
||||||
}();
|
}();
|
||||||
|
|
||||||
err := <- errors;
|
err := <-errors;
|
||||||
return s.output.Bytes(), err;
|
return s.output.Bytes(), err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -23,14 +23,13 @@ func parse(t *testing.T, form string, fmap FormatterMap) Format {
|
||||||
|
|
||||||
func verify(t *testing.T, f Format, expected string, args ...) {
|
func verify(t *testing.T, f Format, expected string, args ...) {
|
||||||
if f == nil {
|
if f == nil {
|
||||||
return; // allow other tests to run
|
return; // allow other tests to run
|
||||||
}
|
}
|
||||||
result := f.Sprint(args);
|
result := f.Sprint(args);
|
||||||
if result != expected {
|
if result != expected {
|
||||||
t.Errorf(
|
t.Errorf(
|
||||||
"result : `%s`\nexpected: `%s`\n\n",
|
"result : `%s`\nexpected: `%s`\n\n",
|
||||||
result, expected
|
result, expected);
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -62,9 +61,9 @@ func formatter(s *State, value interface{}, rule_name string) bool {
|
||||||
|
|
||||||
|
|
||||||
func TestCustomFormatters(t *testing.T) {
|
func TestCustomFormatters(t *testing.T) {
|
||||||
fmap0 := FormatterMap{ "/": formatter };
|
fmap0 := FormatterMap{"/": formatter};
|
||||||
fmap1 := FormatterMap{ "int": formatter, "blank": formatter, "nil": formatter };
|
fmap1 := FormatterMap{"int": formatter, "blank": formatter, "nil": formatter};
|
||||||
fmap2 := FormatterMap{ "testing.T": formatter };
|
fmap2 := FormatterMap{"testing.T": formatter};
|
||||||
|
|
||||||
f := parse(t, `int=`, fmap0);
|
f := parse(t, `int=`, fmap0);
|
||||||
verify(t, f, ``, 1, 2, 3);
|
verify(t, f, ``, 1, 2, 3);
|
||||||
|
|
@ -97,14 +96,13 @@ func TestCustomFormatters(t *testing.T) {
|
||||||
func check(t *testing.T, form, expected string, args ...) {
|
func check(t *testing.T, form, expected string, args ...) {
|
||||||
f := parse(t, form, nil);
|
f := parse(t, form, nil);
|
||||||
if f == nil {
|
if f == nil {
|
||||||
return; // allow other tests to run
|
return; // allow other tests to run
|
||||||
}
|
}
|
||||||
result := f.Sprint(args);
|
result := f.Sprint(args);
|
||||||
if result != expected {
|
if result != expected {
|
||||||
t.Errorf(
|
t.Errorf(
|
||||||
"format : %s\nresult : `%s`\nexpected: `%s`\n\n",
|
"format : %s\nresult : `%s`\nexpected: `%s`\n\n",
|
||||||
form, result, expected
|
form, result, expected);
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -164,7 +162,7 @@ func TestChanTypes(t *testing.T) {
|
||||||
check(t, `chan="chan"`, `chan`, c0);
|
check(t, `chan="chan"`, `chan`, c0);
|
||||||
|
|
||||||
c1 := make(chan int);
|
c1 := make(chan int);
|
||||||
go func(){ c1 <- 42 }();
|
go func() { c1 <- 42 }();
|
||||||
check(t, `chan="chan"`, `chan`, c1);
|
check(t, `chan="chan"`, `chan`, c1);
|
||||||
// check(t, `chan=*`, `42`, c1); // reflection support for chans incomplete
|
// check(t, `chan=*`, `42`, c1); // reflection support for chans incomplete
|
||||||
}
|
}
|
||||||
|
|
@ -174,14 +172,14 @@ func TestFuncTypes(t *testing.T) {
|
||||||
var f0 func() int;
|
var f0 func() int;
|
||||||
check(t, `func="func"`, `func`, f0);
|
check(t, `func="func"`, `func`, f0);
|
||||||
|
|
||||||
f1 := func() int { return 42; };
|
f1 := func() int { return 42 };
|
||||||
check(t, `func="func"`, `func`, f1);
|
check(t, `func="func"`, `func`, f1);
|
||||||
// check(t, `func=*`, `42`, f1); // reflection support for funcs incomplete
|
// check(t, `func=*`, `42`, f1); // reflection support for funcs incomplete
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func TestInterfaceTypes(t *testing.T) {
|
func TestInterfaceTypes(t *testing.T) {
|
||||||
var i0 interface{};
|
var i0 interface{}
|
||||||
check(t, `interface="interface"`, `interface`, i0);
|
check(t, `interface="interface"`, `interface`, i0);
|
||||||
|
|
||||||
i0 = "foo";
|
i0 = "foo";
|
||||||
|
|
@ -234,8 +232,7 @@ type T1 struct {
|
||||||
a int;
|
a int;
|
||||||
}
|
}
|
||||||
|
|
||||||
const F1 =
|
const F1 = `datafmt "datafmt";`
|
||||||
`datafmt "datafmt";`
|
|
||||||
`int = "%d";`
|
`int = "%d";`
|
||||||
`datafmt.T1 = "<" a ">";`
|
`datafmt.T1 = "<" a ">";`
|
||||||
|
|
||||||
|
|
@ -248,21 +245,19 @@ func TestStruct1(t *testing.T) {
|
||||||
// Formatting of a struct with an optional field (ptr)
|
// Formatting of a struct with an optional field (ptr)
|
||||||
|
|
||||||
type T2 struct {
|
type T2 struct {
|
||||||
s string;
|
s string;
|
||||||
p *T1;
|
p *T1;
|
||||||
}
|
}
|
||||||
|
|
||||||
const F2a =
|
const F2a = F1 +
|
||||||
F1 +
|
|
||||||
`string = "%s";`
|
`string = "%s";`
|
||||||
`ptr = *;`
|
`ptr = *;`
|
||||||
`datafmt.T2 = s ["-" p "-"];`
|
`datafmt.T2 = s ["-" p "-"];`
|
||||||
|
|
||||||
const F2b =
|
const F2b = F1 +
|
||||||
F1 +
|
|
||||||
`string = "%s";`
|
`string = "%s";`
|
||||||
`ptr = *;`
|
`ptr = *;`
|
||||||
`datafmt.T2 = s ("-" p "-" | "empty");`;
|
`datafmt.T2 = s ("-" p "-" | "empty");`
|
||||||
|
|
||||||
func TestStruct2(t *testing.T) {
|
func TestStruct2(t *testing.T) {
|
||||||
check(t, F2a, "foo", T2{"foo", nil});
|
check(t, F2a, "foo", T2{"foo", nil});
|
||||||
|
|
@ -275,18 +270,16 @@ func TestStruct2(t *testing.T) {
|
||||||
// Formatting of a struct with a repetitive field (slice)
|
// Formatting of a struct with a repetitive field (slice)
|
||||||
|
|
||||||
type T3 struct {
|
type T3 struct {
|
||||||
s string;
|
s string;
|
||||||
a []int;
|
a []int;
|
||||||
}
|
}
|
||||||
|
|
||||||
const F3a =
|
const F3a = `datafmt "datafmt";`
|
||||||
`datafmt "datafmt";`
|
|
||||||
`default = "%v";`
|
`default = "%v";`
|
||||||
`array = *;`
|
`array = *;`
|
||||||
`datafmt.T3 = s {" " a a / ","};`
|
`datafmt.T3 = s {" " a a / ","};`
|
||||||
|
|
||||||
const F3b =
|
const F3b = `datafmt "datafmt";`
|
||||||
`datafmt "datafmt";`
|
|
||||||
`int = "%d";`
|
`int = "%d";`
|
||||||
`string = "%s";`
|
`string = "%s";`
|
||||||
`array = *;`
|
`array = *;`
|
||||||
|
|
@ -306,12 +299,11 @@ func TestStruct3(t *testing.T) {
|
||||||
// Formatting of a struct with alternative field
|
// Formatting of a struct with alternative field
|
||||||
|
|
||||||
type T4 struct {
|
type T4 struct {
|
||||||
x *int;
|
x *int;
|
||||||
a []int;
|
a []int;
|
||||||
}
|
}
|
||||||
|
|
||||||
const F4a =
|
const F4a = `datafmt "datafmt";`
|
||||||
`datafmt "datafmt";`
|
|
||||||
`int = "%d";`
|
`int = "%d";`
|
||||||
`ptr = *;`
|
`ptr = *;`
|
||||||
`array = *;`
|
`array = *;`
|
||||||
|
|
@ -319,8 +311,7 @@ const F4a =
|
||||||
`empty = *:nil;`
|
`empty = *:nil;`
|
||||||
`datafmt.T4 = "<" (x:empty x | "-") ">" `
|
`datafmt.T4 = "<" (x:empty x | "-") ">" `
|
||||||
|
|
||||||
const F4b =
|
const F4b = `datafmt "datafmt";`
|
||||||
`datafmt "datafmt";`
|
|
||||||
`int = "%d";`
|
`int = "%d";`
|
||||||
`ptr = *;`
|
`ptr = *;`
|
||||||
`array = *;`
|
`array = *;`
|
||||||
|
|
@ -341,12 +332,11 @@ func TestStruct4(t *testing.T) {
|
||||||
// Formatting a struct (documentation example)
|
// Formatting a struct (documentation example)
|
||||||
|
|
||||||
type Point struct {
|
type Point struct {
|
||||||
name string;
|
name string;
|
||||||
x, y int;
|
x, y int;
|
||||||
}
|
}
|
||||||
|
|
||||||
const FPoint =
|
const FPoint = `datafmt "datafmt";`
|
||||||
`datafmt "datafmt";`
|
|
||||||
`int = "%d";`
|
`int = "%d";`
|
||||||
`hexInt = "0x%x";`
|
`hexInt = "0x%x";`
|
||||||
`string = "---%s---";`
|
`string = "---%s---";`
|
||||||
|
|
@ -361,8 +351,7 @@ func TestStructPoint(t *testing.T) {
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
// Formatting a slice (documentation example)
|
// Formatting a slice (documentation example)
|
||||||
|
|
||||||
const FSlice =
|
const FSlice = `int = "%b";`
|
||||||
`int = "%b";`
|
|
||||||
`array = { * / ", " }`
|
`array = { * / ", " }`
|
||||||
|
|
||||||
func TestSlice(t *testing.T) {
|
func TestSlice(t *testing.T) {
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ import (
|
||||||
|
|
||||||
|
|
||||||
// noPos is used when there is no corresponding source position for a token.
|
// noPos is used when there is no corresponding source position for a token.
|
||||||
var noPos token.Position;
|
var noPos token.Position
|
||||||
|
|
||||||
|
|
||||||
// The mode parameter to the Parse* functions is a set of flags (or 0).
|
// The mode parameter to the Parse* functions is a set of flags (or 0).
|
||||||
|
|
@ -27,43 +27,43 @@ var noPos token.Position;
|
||||||
// parser functionality.
|
// parser functionality.
|
||||||
//
|
//
|
||||||
const (
|
const (
|
||||||
PackageClauseOnly uint = 1 << iota; // parsing stops after package clause
|
PackageClauseOnly uint = 1<<iota; // parsing stops after package clause
|
||||||
ImportsOnly; // parsing stops after import declarations
|
ImportsOnly; // parsing stops after import declarations
|
||||||
ParseComments; // parse comments and add them to AST
|
ParseComments; // parse comments and add them to AST
|
||||||
Trace; // print a trace of parsed productions
|
Trace; // print a trace of parsed productions
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
// The parser structure holds the parser's internal state.
|
// The parser structure holds the parser's internal state.
|
||||||
type parser struct {
|
type parser struct {
|
||||||
scanner.ErrorVector;
|
scanner.ErrorVector;
|
||||||
scanner scanner.Scanner;
|
scanner scanner.Scanner;
|
||||||
|
|
||||||
// Tracing/debugging
|
// Tracing/debugging
|
||||||
mode uint; // parsing mode
|
mode uint; // parsing mode
|
||||||
trace bool; // == (mode & Trace != 0)
|
trace bool; // == (mode & Trace != 0)
|
||||||
indent uint; // indentation used for tracing output
|
indent uint; // indentation used for tracing output
|
||||||
|
|
||||||
// Comments
|
// Comments
|
||||||
comments *ast.CommentGroup; // list of collected comments
|
comments *ast.CommentGroup; // list of collected comments
|
||||||
lastComment *ast.CommentGroup; // last comment in the comments list
|
lastComment *ast.CommentGroup; // last comment in the comments list
|
||||||
leadComment *ast.CommentGroup; // the last lead comment
|
leadComment *ast.CommentGroup; // the last lead comment
|
||||||
lineComment *ast.CommentGroup; // the last line comment
|
lineComment *ast.CommentGroup; // the last line comment
|
||||||
|
|
||||||
// Next token
|
// Next token
|
||||||
pos token.Position; // token position
|
pos token.Position; // token position
|
||||||
tok token.Token; // one token look-ahead
|
tok token.Token; // one token look-ahead
|
||||||
lit []byte; // token literal
|
lit []byte; // token literal
|
||||||
|
|
||||||
// Non-syntactic parser control
|
// Non-syntactic parser control
|
||||||
optSemi bool; // true if semicolon separator is optional in statement list
|
optSemi bool; // true if semicolon separator is optional in statement list
|
||||||
exprLev int; // < 0: in control clause, >= 0: in expression
|
exprLev int; // < 0: in control clause, >= 0: in expression
|
||||||
|
|
||||||
// Scopes
|
// Scopes
|
||||||
pkgScope *ast.Scope;
|
pkgScope *ast.Scope;
|
||||||
fileScope *ast.Scope;
|
fileScope *ast.Scope;
|
||||||
topScope *ast.Scope;
|
topScope *ast.Scope;
|
||||||
};
|
}
|
||||||
|
|
||||||
|
|
||||||
// scannerMode returns the scanner mode bits given the parser's mode bits.
|
// scannerMode returns the scanner mode bits given the parser's mode bits.
|
||||||
|
|
@ -79,7 +79,7 @@ func (p *parser) init(filename string, src []byte, mode uint) {
|
||||||
p.ErrorVector.Init();
|
p.ErrorVector.Init();
|
||||||
p.scanner.Init(filename, src, p, scannerMode(mode));
|
p.scanner.Init(filename, src, p, scannerMode(mode));
|
||||||
p.mode = mode;
|
p.mode = mode;
|
||||||
p.trace = mode & Trace != 0; // for convenience (p.trace is used frequently)
|
p.trace = mode&Trace != 0; // for convenience (p.trace is used frequently)
|
||||||
p.next();
|
p.next();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -88,16 +88,15 @@ func (p *parser) init(filename string, src []byte, mode uint) {
|
||||||
// Parsing support
|
// Parsing support
|
||||||
|
|
||||||
func (p *parser) printTrace(a ...) {
|
func (p *parser) printTrace(a ...) {
|
||||||
const dots =
|
const dots = ". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . "
|
||||||
". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . "
|
|
||||||
". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ";
|
". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ";
|
||||||
const n = uint(len(dots));
|
const n = uint(len(dots));
|
||||||
fmt.Printf("%5d:%3d: ", p.pos.Line, p.pos.Column);
|
fmt.Printf("%5d:%3d: ", p.pos.Line, p.pos.Column);
|
||||||
i := 2*p.indent;
|
i := 2 * p.indent;
|
||||||
for ; i > n; i -= n {
|
for ; i > n; i -= n {
|
||||||
fmt.Print(dots);
|
fmt.Print(dots);
|
||||||
}
|
}
|
||||||
fmt.Print(dots[0 : i]);
|
fmt.Print(dots[0:i]);
|
||||||
fmt.Println(a);
|
fmt.Println(a);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -109,7 +108,8 @@ func trace(p *parser, msg string) *parser {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func un/*trace*/(p *parser) {
|
// Usage pattern: defer un(trace(p, "..."));
|
||||||
|
func un(p *parser) {
|
||||||
p.indent--;
|
p.indent--;
|
||||||
p.printTrace(")");
|
p.printTrace(")");
|
||||||
}
|
}
|
||||||
|
|
@ -127,7 +127,7 @@ func (p *parser) next0() {
|
||||||
case p.tok.IsLiteral():
|
case p.tok.IsLiteral():
|
||||||
p.printTrace(s, string(p.lit));
|
p.printTrace(s, string(p.lit));
|
||||||
case p.tok.IsOperator(), p.tok.IsKeyword():
|
case p.tok.IsOperator(), p.tok.IsKeyword():
|
||||||
p.printTrace("\"" + s + "\"");
|
p.printTrace("\""+s+"\"");
|
||||||
default:
|
default:
|
||||||
p.printTrace(s);
|
p.printTrace(s);
|
||||||
}
|
}
|
||||||
|
|
@ -209,7 +209,7 @@ func (p *parser) consumeCommentGroup() int {
|
||||||
func (p *parser) next() {
|
func (p *parser) next() {
|
||||||
p.leadComment = nil;
|
p.leadComment = nil;
|
||||||
p.lineComment = nil;
|
p.lineComment = nil;
|
||||||
line := p.pos.Line; // current line
|
line := p.pos.Line; // current line
|
||||||
p.next0();
|
p.next0();
|
||||||
|
|
||||||
if p.tok == token.COMMENT {
|
if p.tok == token.COMMENT {
|
||||||
|
|
@ -246,7 +246,7 @@ func (p *parser) errorExpected(pos token.Position, msg string) {
|
||||||
// make the error message more specific
|
// make the error message more specific
|
||||||
msg += ", found '" + p.tok.String() + "'";
|
msg += ", found '" + p.tok.String() + "'";
|
||||||
if p.tok.IsLiteral() {
|
if p.tok.IsLiteral() {
|
||||||
msg += " " + string(p.lit);
|
msg += " "+string(p.lit);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
p.Error(pos, msg);
|
p.Error(pos, msg);
|
||||||
|
|
@ -258,7 +258,7 @@ func (p *parser) expect(tok token.Token) token.Position {
|
||||||
if p.tok != tok {
|
if p.tok != tok {
|
||||||
p.errorExpected(pos, "'" + tok.String() + "'");
|
p.errorExpected(pos, "'" + tok.String() + "'");
|
||||||
}
|
}
|
||||||
p.next(); // make progress in any case
|
p.next(); // make progress in any case
|
||||||
return pos;
|
return pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -272,7 +272,8 @@ func openScope(p *parser) *parser {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func close/*Scope*/(p *parser) {
|
// Usage pattern: defer close(openScope(p));
|
||||||
|
func close(p *parser) {
|
||||||
p.topScope = p.topScope.Outer;
|
p.topScope = p.topScope.Outer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -300,7 +301,7 @@ func (p *parser) parseIdent() *ast.Ident {
|
||||||
p.next();
|
p.next();
|
||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
p.expect(token.IDENT); // use expect() error handling
|
p.expect(token.IDENT); // use expect() error handling
|
||||||
return &ast.Ident{p.pos, ""};
|
return &ast.Ident{p.pos, ""};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -361,7 +362,7 @@ func (p *parser) parseType() ast.Expr {
|
||||||
|
|
||||||
if typ == nil {
|
if typ == nil {
|
||||||
p.errorExpected(p.pos, "type");
|
p.errorExpected(p.pos, "type");
|
||||||
p.next(); // make progress
|
p.next(); // make progress
|
||||||
return &ast.BadExpr{p.pos};
|
return &ast.BadExpr{p.pos};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -536,7 +537,7 @@ func (p *parser) parseParameterType(ellipsisOk bool) ast.Expr {
|
||||||
typ := p.tryParameterType(ellipsisOk);
|
typ := p.tryParameterType(ellipsisOk);
|
||||||
if typ == nil {
|
if typ == nil {
|
||||||
p.errorExpected(p.pos, "type");
|
p.errorExpected(p.pos, "type");
|
||||||
p.next(); // make progress
|
p.next(); // make progress
|
||||||
typ = &ast.BadExpr{p.pos};
|
typ = &ast.BadExpr{p.pos};
|
||||||
}
|
}
|
||||||
return typ;
|
return typ;
|
||||||
|
|
@ -757,14 +758,22 @@ func (p *parser) parseChanType() *ast.ChanType {
|
||||||
|
|
||||||
func (p *parser) tryRawType(ellipsisOk bool) ast.Expr {
|
func (p *parser) tryRawType(ellipsisOk bool) ast.Expr {
|
||||||
switch p.tok {
|
switch p.tok {
|
||||||
case token.IDENT: return p.parseTypeName();
|
case token.IDENT:
|
||||||
case token.LBRACK: return p.parseArrayType(ellipsisOk);
|
return p.parseTypeName();
|
||||||
case token.STRUCT: return p.parseStructType();
|
case token.LBRACK:
|
||||||
case token.MUL: return p.parsePointerType();
|
return p.parseArrayType(ellipsisOk);
|
||||||
case token.FUNC: return p.parseFuncType();
|
case token.STRUCT:
|
||||||
case token.INTERFACE: return p.parseInterfaceType();
|
return p.parseStructType();
|
||||||
case token.MAP: return p.parseMapType();
|
case token.MUL:
|
||||||
case token.CHAN, token.ARROW: return p.parseChanType();
|
return p.parsePointerType();
|
||||||
|
case token.FUNC:
|
||||||
|
return p.parseFuncType();
|
||||||
|
case token.INTERFACE:
|
||||||
|
return p.parseInterfaceType();
|
||||||
|
case token.MAP:
|
||||||
|
return p.parseMapType();
|
||||||
|
case token.CHAN, token.ARROW:
|
||||||
|
return p.parseChanType();
|
||||||
case token.LPAREN:
|
case token.LPAREN:
|
||||||
lparen := p.pos;
|
lparen := p.pos;
|
||||||
p.next();
|
p.next();
|
||||||
|
|
@ -811,7 +820,7 @@ func (p *parser) parseStmtList() []ast.Stmt {
|
||||||
if p.tok == token.SEMICOLON {
|
if p.tok == token.SEMICOLON {
|
||||||
p.next();
|
p.next();
|
||||||
} else if p.optSemi {
|
} else if p.optSemi {
|
||||||
p.optSemi = false; // "consume" optional semicolon
|
p.optSemi = false; // "consume" optional semicolon
|
||||||
} else {
|
} else {
|
||||||
expectSemi = true;
|
expectSemi = true;
|
||||||
}
|
}
|
||||||
|
|
@ -878,7 +887,7 @@ func (p *parser) parseFuncTypeOrLit() ast.Expr {
|
||||||
|
|
||||||
p.exprLev++;
|
p.exprLev++;
|
||||||
body := p.parseBlockStmt(nil);
|
body := p.parseBlockStmt(nil);
|
||||||
p.optSemi = false; // function body requires separating ";"
|
p.optSemi = false; // function body requires separating ";"
|
||||||
p.exprLev--;
|
p.exprLev--;
|
||||||
|
|
||||||
return &ast.FuncLit{typ, body};
|
return &ast.FuncLit{typ, body};
|
||||||
|
|
@ -918,14 +927,14 @@ func (p *parser) parseOperand() ast.Expr {
|
||||||
return p.parseFuncTypeOrLit();
|
return p.parseFuncTypeOrLit();
|
||||||
|
|
||||||
default:
|
default:
|
||||||
t := p.tryRawType(true); // could be type for composite literal or conversion
|
t := p.tryRawType(true); // could be type for composite literal or conversion
|
||||||
if t != nil {
|
if t != nil {
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
p.errorExpected(p.pos, "operand");
|
p.errorExpected(p.pos, "operand");
|
||||||
p.next(); // make progress
|
p.next(); // make progress
|
||||||
return &ast.BadExpr{p.pos};
|
return &ast.BadExpr{p.pos};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1097,9 +1106,12 @@ func isTypeName(x ast.Expr) bool {
|
||||||
switch t := x.(type) {
|
switch t := x.(type) {
|
||||||
case *ast.BadExpr:
|
case *ast.BadExpr:
|
||||||
case *ast.Ident:
|
case *ast.Ident:
|
||||||
case *ast.ParenExpr: return isTypeName(t.X); // TODO(gri): should (TypeName) be illegal?
|
case *ast.ParenExpr:
|
||||||
case *ast.SelectorExpr: return isTypeName(t.X);
|
return isTypeName(t.X); // TODO(gri): should (TypeName) be illegal?
|
||||||
default: return false; // all other nodes are not type names
|
case *ast.SelectorExpr:
|
||||||
|
return isTypeName(t.X);
|
||||||
|
default:
|
||||||
|
return false; // all other nodes are not type names
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -1111,12 +1123,15 @@ func isCompositeLitType(x ast.Expr) bool {
|
||||||
switch t := x.(type) {
|
switch t := x.(type) {
|
||||||
case *ast.BadExpr:
|
case *ast.BadExpr:
|
||||||
case *ast.Ident:
|
case *ast.Ident:
|
||||||
case *ast.ParenExpr: return isCompositeLitType(t.X);
|
case *ast.ParenExpr:
|
||||||
case *ast.SelectorExpr: return isTypeName(t.X);
|
return isCompositeLitType(t.X);
|
||||||
|
case *ast.SelectorExpr:
|
||||||
|
return isTypeName(t.X);
|
||||||
case *ast.ArrayType:
|
case *ast.ArrayType:
|
||||||
case *ast.StructType:
|
case *ast.StructType:
|
||||||
case *ast.MapType:
|
case *ast.MapType:
|
||||||
default: return false; // all other nodes are not legal composite literal types
|
default:
|
||||||
|
return false; // all other nodes are not legal composite literal types
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -1154,9 +1169,12 @@ func (p *parser) parsePrimaryExpr() ast.Expr {
|
||||||
x := p.parseOperand();
|
x := p.parseOperand();
|
||||||
L: for {
|
L: for {
|
||||||
switch p.tok {
|
switch p.tok {
|
||||||
case token.PERIOD: x = p.parseSelectorOrTypeAssertion(p.checkExpr(x));
|
case token.PERIOD:
|
||||||
case token.LBRACK: x = p.parseIndex(p.checkExpr(x));
|
x = p.parseSelectorOrTypeAssertion(p.checkExpr(x));
|
||||||
case token.LPAREN: x = p.parseCallOrConversion(p.checkExprOrType(x));
|
case token.LBRACK:
|
||||||
|
x = p.parseIndex(p.checkExpr(x));
|
||||||
|
case token.LPAREN:
|
||||||
|
x = p.parseCallOrConversion(p.checkExprOrType(x));
|
||||||
case token.LBRACE:
|
case token.LBRACE:
|
||||||
if isCompositeLitType(x) && (p.exprLev >= 0 || !isTypeName(x)) {
|
if isCompositeLitType(x) && (p.exprLev >= 0 || !isTypeName(x)) {
|
||||||
x = p.parseCompositeLit(x);
|
x = p.parseCompositeLit(x);
|
||||||
|
|
@ -1206,7 +1224,7 @@ func (p *parser) parseBinaryExpr(prec1 int) ast.Expr {
|
||||||
for p.tok.Precedence() == prec {
|
for p.tok.Precedence() == prec {
|
||||||
pos, op := p.pos, p.tok;
|
pos, op := p.pos, p.tok;
|
||||||
p.next();
|
p.next();
|
||||||
y := p.parseBinaryExpr(prec + 1);
|
y := p.parseBinaryExpr(prec+1);
|
||||||
x = &ast.BinaryExpr{p.checkExpr(x), pos, op, p.checkExpr(y)};
|
x = &ast.BinaryExpr{p.checkExpr(x), pos, op, p.checkExpr(y)};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1272,7 +1290,7 @@ func (p *parser) parseSimpleStmt(labelOk bool) ast.Stmt {
|
||||||
if p.tok == token.INC || p.tok == token.DEC {
|
if p.tok == token.INC || p.tok == token.DEC {
|
||||||
// increment or decrement
|
// increment or decrement
|
||||||
s := &ast.IncDecStmt{x[0], p.tok};
|
s := &ast.IncDecStmt{x[0], p.tok};
|
||||||
p.next(); // consume "++" or "--"
|
p.next(); // consume "++" or "--"
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1492,7 +1510,7 @@ func isExprSwitch(s ast.Stmt) bool {
|
||||||
}
|
}
|
||||||
if e, ok := s.(*ast.ExprStmt); ok {
|
if e, ok := s.(*ast.ExprStmt); ok {
|
||||||
if a, ok := e.X.(*ast.TypeAssertExpr); ok {
|
if a, ok := e.X.(*ast.TypeAssertExpr); ok {
|
||||||
return a.Type != nil; // regular type assertion
|
return a.Type != nil; // regular type assertion
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -1565,7 +1583,7 @@ func (p *parser) parseCommClause() *ast.CommClause {
|
||||||
if p.tok == token.ARROW {
|
if p.tok == token.ARROW {
|
||||||
rhs = p.parseExpr();
|
rhs = p.parseExpr();
|
||||||
} else {
|
} else {
|
||||||
p.expect(token.ARROW); // use expect() error handling
|
p.expect(token.ARROW); // use expect() error handling
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// else SendExpr
|
// else SendExpr
|
||||||
|
|
@ -1637,7 +1655,7 @@ func (p *parser) parseForStmt() ast.Stmt {
|
||||||
}
|
}
|
||||||
if rhs, isUnary := as.Rhs[0].(*ast.UnaryExpr); isUnary && rhs.Op == token.RANGE {
|
if rhs, isUnary := as.Rhs[0].(*ast.UnaryExpr); isUnary && rhs.Op == token.RANGE {
|
||||||
// rhs is range expression; check lhs
|
// rhs is range expression; check lhs
|
||||||
return &ast.RangeStmt{pos, key, value, as.TokPos, as.Tok, rhs.X, body}
|
return &ast.RangeStmt{pos, key, value, as.TokPos, as.Tok, rhs.X, body};
|
||||||
} else {
|
} else {
|
||||||
p.errorExpected(s2.Pos(), "range clause");
|
p.errorExpected(s2.Pos(), "range clause");
|
||||||
return &ast.BadStmt{pos};
|
return &ast.BadStmt{pos};
|
||||||
|
|
@ -1647,7 +1665,7 @@ func (p *parser) parseForStmt() ast.Stmt {
|
||||||
return &ast.ForStmt{pos, s1, p.makeExpr(s2), s3, body};
|
return &ast.ForStmt{pos, s1, p.makeExpr(s2), s3, body};
|
||||||
}
|
}
|
||||||
|
|
||||||
panic(); // unreachable
|
panic(); // unreachable
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1659,13 +1677,13 @@ func (p *parser) parseStmt() ast.Stmt {
|
||||||
|
|
||||||
switch p.tok {
|
switch p.tok {
|
||||||
case token.CONST, token.TYPE, token.VAR:
|
case token.CONST, token.TYPE, token.VAR:
|
||||||
decl, _ := p.parseDecl(false); // do not consume trailing semicolon
|
decl, _ := p.parseDecl(false); // do not consume trailing semicolon
|
||||||
return &ast.DeclStmt{decl};
|
return &ast.DeclStmt{decl};
|
||||||
case
|
case
|
||||||
// tokens that may start a top-level expression
|
// tokens that may start a top-level expression
|
||||||
token.IDENT, token.INT, token.FLOAT, token.CHAR, token.STRING, token.FUNC, token.LPAREN, // operand
|
token.IDENT, token.INT, token.FLOAT, token.CHAR, token.STRING, token.FUNC, token.LPAREN, // operand
|
||||||
token.LBRACK, token.STRUCT, // composite type
|
token.LBRACK, token.STRUCT, // composite type
|
||||||
token.MUL, token.AND, token.ARROW, token.ADD, token.SUB, token.XOR: // unary operators
|
token.MUL, token.AND, token.ARROW, token.ADD, token.SUB, token.XOR: // unary operators
|
||||||
return p.parseSimpleStmt(true);
|
return p.parseSimpleStmt(true);
|
||||||
case token.GO:
|
case token.GO:
|
||||||
return p.parseGoStmt();
|
return p.parseGoStmt();
|
||||||
|
|
@ -1692,7 +1710,7 @@ func (p *parser) parseStmt() ast.Stmt {
|
||||||
|
|
||||||
// no statement found
|
// no statement found
|
||||||
p.errorExpected(p.pos, "statement");
|
p.errorExpected(p.pos, "statement");
|
||||||
p.next(); // make progress
|
p.next(); // make progress
|
||||||
return &ast.BadStmt{p.pos};
|
return &ast.BadStmt{p.pos};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1732,7 +1750,7 @@ func parseImportSpec(p *parser, doc *ast.CommentGroup, getSemi bool) (spec ast.S
|
||||||
if p.tok == token.STRING {
|
if p.tok == token.STRING {
|
||||||
path = p.parseStringList(nil);
|
path = p.parseStringList(nil);
|
||||||
} else {
|
} else {
|
||||||
p.expect(token.STRING); // use expect() error handling
|
p.expect(token.STRING); // use expect() error handling
|
||||||
}
|
}
|
||||||
|
|
||||||
comment, gotSemi := p.parseComment(getSemi);
|
comment, gotSemi := p.parseComment(getSemi);
|
||||||
|
|
@ -1804,7 +1822,7 @@ func (p *parser) parseGenDecl(keyword token.Token, f parseSpecFunction, getSemi
|
||||||
p.next();
|
p.next();
|
||||||
for p.tok != token.RPAREN && p.tok != token.EOF {
|
for p.tok != token.RPAREN && p.tok != token.EOF {
|
||||||
doc := p.leadComment;
|
doc := p.leadComment;
|
||||||
spec, semi := f(p, doc, true); // consume semicolon if any
|
spec, semi := f(p, doc, true); // consume semicolon if any
|
||||||
list.Push(spec);
|
list.Push(spec);
|
||||||
if !semi {
|
if !semi {
|
||||||
break;
|
break;
|
||||||
|
|
@ -1914,7 +1932,7 @@ func (p *parser) parseDecl(getSemi bool) (decl ast.Decl, gotSemi bool) {
|
||||||
p.errorExpected(pos, "declaration");
|
p.errorExpected(pos, "declaration");
|
||||||
decl = &ast.BadDecl{pos};
|
decl = &ast.BadDecl{pos};
|
||||||
gotSemi = getSemi && p.tok == token.SEMICOLON;
|
gotSemi = getSemi && p.tok == token.SEMICOLON;
|
||||||
p.next(); // make progress in any case
|
p.next(); // make progress in any case
|
||||||
return decl, gotSemi;
|
return decl, gotSemi;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1967,14 +1985,14 @@ func (p *parser) parseFile() *ast.File {
|
||||||
// import decls
|
// import decls
|
||||||
list := vector.New(0);
|
list := vector.New(0);
|
||||||
for p.tok == token.IMPORT {
|
for p.tok == token.IMPORT {
|
||||||
decl, _ := p.parseGenDecl(token.IMPORT, parseImportSpec, true); // consume optional semicolon
|
decl, _ := p.parseGenDecl(token.IMPORT, parseImportSpec, true); // consume optional semicolon
|
||||||
list.Push(decl);
|
list.Push(decl);
|
||||||
}
|
}
|
||||||
|
|
||||||
if p.mode & ImportsOnly == 0 {
|
if p.mode & ImportsOnly == 0 {
|
||||||
// rest of package body
|
// rest of package body
|
||||||
for p.tok != token.EOF {
|
for p.tok != token.EOF {
|
||||||
decl, _ := p.parseDecl(true); // consume optional semicolon
|
decl, _ := p.parseDecl(true); // consume optional semicolon
|
||||||
list.Push(decl);
|
list.Push(decl);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,15 @@ const (
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
// Other outstanding formatting issues:
|
||||||
|
// - replacement of expression spacing algorithm with rsc's algorithm
|
||||||
|
// - support for one-line composite types (e.g. structs) as composite literals types
|
||||||
|
// - better comment formatting for /*-style comments at the end of a line (e.g. a declaration)
|
||||||
|
// when the comment spans multiple lines
|
||||||
|
// - formatting of expression lists; especially for string lists (stringListMode)
|
||||||
|
// - blank after { and before } in one-line composite literals probably looks better
|
||||||
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
// Common AST nodes.
|
// Common AST nodes.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ import (
|
||||||
|
|
||||||
|
|
||||||
const /* class */ (
|
const /* class */ (
|
||||||
special = iota;
|
special = iota;
|
||||||
literal;
|
literal;
|
||||||
operator;
|
operator;
|
||||||
keyword;
|
keyword;
|
||||||
|
|
@ -22,144 +22,150 @@ const /* class */ (
|
||||||
|
|
||||||
func tokenclass(tok token.Token) int {
|
func tokenclass(tok token.Token) int {
|
||||||
switch {
|
switch {
|
||||||
case tok.IsLiteral(): return literal;
|
case tok.IsLiteral():
|
||||||
case tok.IsOperator(): return operator;
|
return literal;
|
||||||
case tok.IsKeyword(): return keyword;
|
case tok.IsOperator():
|
||||||
|
return operator;
|
||||||
|
case tok.IsKeyword():
|
||||||
|
return keyword;
|
||||||
}
|
}
|
||||||
return special;
|
return special;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
type elt struct {
|
type elt struct {
|
||||||
tok token.Token;
|
tok token.Token;
|
||||||
lit string;
|
lit string;
|
||||||
class int;
|
class int;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
var tokens = [...]elt{
|
var tokens = [...]elt{
|
||||||
// Special tokens
|
// Special tokens
|
||||||
elt{ token.COMMENT, "/* a comment */", special },
|
elt{token.COMMENT, "/* a comment */", special},
|
||||||
elt{ token.COMMENT, "// a comment \n", special },
|
elt{token.COMMENT, "// a comment \n", special},
|
||||||
|
|
||||||
// Identifiers and basic type literals
|
// Identifiers and basic type literals
|
||||||
elt{ token.IDENT, "foobar", literal },
|
elt{token.IDENT, "foobar", literal},
|
||||||
elt{ token.IDENT, "a۰۱۸", literal },
|
elt{token.IDENT, "a۰۱۸", literal},
|
||||||
elt{ token.IDENT, "foo६४", literal },
|
elt{token.IDENT, "foo६४", literal},
|
||||||
elt{ token.IDENT, "bar9876", literal },
|
elt{token.IDENT, "bar9876", literal},
|
||||||
elt{ token.INT, "0", literal },
|
elt{token.INT, "0", literal},
|
||||||
elt{ token.INT, "01234567", literal },
|
elt{token.INT, "01234567", literal},
|
||||||
elt{ token.INT, "0xcafebabe", literal },
|
elt{token.INT, "0xcafebabe", literal},
|
||||||
elt{ token.FLOAT, "0.", literal },
|
elt{token.FLOAT, "0.", literal},
|
||||||
elt{ token.FLOAT, ".0", literal },
|
elt{token.FLOAT, ".0", literal},
|
||||||
elt{ token.FLOAT, "3.14159265", literal },
|
elt{token.FLOAT, "3.14159265", literal},
|
||||||
elt{ token.FLOAT, "1e0", literal },
|
elt{token.FLOAT, "1e0", literal},
|
||||||
elt{ token.FLOAT, "1e+100", literal },
|
elt{token.FLOAT, "1e+100", literal},
|
||||||
elt{ token.FLOAT, "1e-100", literal },
|
elt{token.FLOAT, "1e-100", literal},
|
||||||
elt{ token.FLOAT, "2.71828e-1000", literal },
|
elt{token.FLOAT, "2.71828e-1000", literal},
|
||||||
elt{ token.CHAR, "'a'", literal },
|
elt{token.CHAR, "'a'", literal},
|
||||||
elt{ token.CHAR, "'\\000'", literal },
|
elt{token.CHAR, "'\\000'", literal},
|
||||||
elt{ token.CHAR, "'\\xFF'", literal },
|
elt{token.CHAR, "'\\xFF'", literal},
|
||||||
elt{ token.CHAR, "'\\uff16'", literal },
|
elt{token.CHAR, "'\\uff16'", literal},
|
||||||
elt{ token.CHAR, "'\\U0000ff16'", literal },
|
elt{token.CHAR, "'\\U0000ff16'", literal},
|
||||||
elt{ token.STRING, "`foobar`", literal },
|
elt{token.STRING, "`foobar`", literal},
|
||||||
elt{ token.STRING, "`" `foo
|
elt{token.STRING, "`" `foo
|
||||||
bar` "`", literal },
|
bar`
|
||||||
|
"`",
|
||||||
|
literal,
|
||||||
|
},
|
||||||
|
|
||||||
// Operators and delimitors
|
// Operators and delimitors
|
||||||
elt{ token.ADD, "+", operator },
|
elt{token.ADD, "+", operator},
|
||||||
elt{ token.SUB, "-", operator },
|
elt{token.SUB, "-", operator},
|
||||||
elt{ token.MUL, "*", operator },
|
elt{token.MUL, "*", operator},
|
||||||
elt{ token.QUO, "/", operator },
|
elt{token.QUO, "/", operator},
|
||||||
elt{ token.REM, "%", operator },
|
elt{token.REM, "%", operator},
|
||||||
|
|
||||||
elt{ token.AND, "&", operator },
|
elt{token.AND, "&", operator},
|
||||||
elt{ token.OR, "|", operator },
|
elt{token.OR, "|", operator},
|
||||||
elt{ token.XOR, "^", operator },
|
elt{token.XOR, "^", operator},
|
||||||
elt{ token.SHL, "<<", operator },
|
elt{token.SHL, "<<", operator},
|
||||||
elt{ token.SHR, ">>", operator },
|
elt{token.SHR, ">>", operator},
|
||||||
elt{ token.AND_NOT, "&^", operator },
|
elt{token.AND_NOT, "&^", operator},
|
||||||
|
|
||||||
elt{ token.ADD_ASSIGN, "+=", operator },
|
elt{token.ADD_ASSIGN, "+=", operator},
|
||||||
elt{ token.SUB_ASSIGN, "-=", operator },
|
elt{token.SUB_ASSIGN, "-=", operator},
|
||||||
elt{ token.MUL_ASSIGN, "*=", operator },
|
elt{token.MUL_ASSIGN, "*=", operator},
|
||||||
elt{ token.QUO_ASSIGN, "/=", operator },
|
elt{token.QUO_ASSIGN, "/=", operator},
|
||||||
elt{ token.REM_ASSIGN, "%=", operator },
|
elt{token.REM_ASSIGN, "%=", operator},
|
||||||
|
|
||||||
elt{ token.AND_ASSIGN, "&=", operator },
|
elt{token.AND_ASSIGN, "&=", operator},
|
||||||
elt{ token.OR_ASSIGN, "|=", operator },
|
elt{token.OR_ASSIGN, "|=", operator},
|
||||||
elt{ token.XOR_ASSIGN, "^=", operator },
|
elt{token.XOR_ASSIGN, "^=", operator},
|
||||||
elt{ token.SHL_ASSIGN, "<<=", operator },
|
elt{token.SHL_ASSIGN, "<<=", operator},
|
||||||
elt{ token.SHR_ASSIGN, ">>=", operator },
|
elt{token.SHR_ASSIGN, ">>=", operator},
|
||||||
elt{ token.AND_NOT_ASSIGN, "&^=", operator },
|
elt{token.AND_NOT_ASSIGN, "&^=", operator},
|
||||||
|
|
||||||
elt{ token.LAND, "&&", operator },
|
elt{token.LAND, "&&", operator},
|
||||||
elt{ token.LOR, "||", operator },
|
elt{token.LOR, "||", operator},
|
||||||
elt{ token.ARROW, "<-", operator },
|
elt{token.ARROW, "<-", operator},
|
||||||
elt{ token.INC, "++", operator },
|
elt{token.INC, "++", operator},
|
||||||
elt{ token.DEC, "--", operator },
|
elt{token.DEC, "--", operator},
|
||||||
|
|
||||||
elt{ token.EQL, "==", operator },
|
elt{token.EQL, "==", operator},
|
||||||
elt{ token.LSS, "<", operator },
|
elt{token.LSS, "<", operator},
|
||||||
elt{ token.GTR, ">", operator },
|
elt{token.GTR, ">", operator},
|
||||||
elt{ token.ASSIGN, "=", operator },
|
elt{token.ASSIGN, "=", operator},
|
||||||
elt{ token.NOT, "!", operator },
|
elt{token.NOT, "!", operator},
|
||||||
|
|
||||||
elt{ token.NEQ, "!=", operator },
|
elt{token.NEQ, "!=", operator},
|
||||||
elt{ token.LEQ, "<=", operator },
|
elt{token.LEQ, "<=", operator},
|
||||||
elt{ token.GEQ, ">=", operator },
|
elt{token.GEQ, ">=", operator},
|
||||||
elt{ token.DEFINE, ":=", operator },
|
elt{token.DEFINE, ":=", operator},
|
||||||
elt{ token.ELLIPSIS, "...", operator },
|
elt{token.ELLIPSIS, "...", operator},
|
||||||
|
|
||||||
elt{ token.LPAREN, "(", operator },
|
elt{token.LPAREN, "(", operator},
|
||||||
elt{ token.LBRACK, "[", operator },
|
elt{token.LBRACK, "[", operator},
|
||||||
elt{ token.LBRACE, "{", operator },
|
elt{token.LBRACE, "{", operator},
|
||||||
elt{ token.COMMA, ",", operator },
|
elt{token.COMMA, ",", operator},
|
||||||
elt{ token.PERIOD, ".", operator },
|
elt{token.PERIOD, ".", operator},
|
||||||
|
|
||||||
elt{ token.RPAREN, ")", operator },
|
elt{token.RPAREN, ")", operator},
|
||||||
elt{ token.RBRACK, "]", operator },
|
elt{token.RBRACK, "]", operator},
|
||||||
elt{ token.RBRACE, "}", operator },
|
elt{token.RBRACE, "}", operator},
|
||||||
elt{ token.SEMICOLON, ";", operator },
|
elt{token.SEMICOLON, ";", operator},
|
||||||
elt{ token.COLON, ":", operator },
|
elt{token.COLON, ":", operator},
|
||||||
|
|
||||||
// Keywords
|
// Keywords
|
||||||
elt{ token.BREAK, "break", keyword },
|
elt{token.BREAK, "break", keyword},
|
||||||
elt{ token.CASE, "case", keyword },
|
elt{token.CASE, "case", keyword},
|
||||||
elt{ token.CHAN, "chan", keyword },
|
elt{token.CHAN, "chan", keyword},
|
||||||
elt{ token.CONST, "const", keyword },
|
elt{token.CONST, "const", keyword},
|
||||||
elt{ token.CONTINUE, "continue", keyword },
|
elt{token.CONTINUE, "continue", keyword},
|
||||||
|
|
||||||
elt{ token.DEFAULT, "default", keyword },
|
elt{token.DEFAULT, "default", keyword},
|
||||||
elt{ token.DEFER, "defer", keyword },
|
elt{token.DEFER, "defer", keyword},
|
||||||
elt{ token.ELSE, "else", keyword },
|
elt{token.ELSE, "else", keyword},
|
||||||
elt{ token.FALLTHROUGH, "fallthrough", keyword },
|
elt{token.FALLTHROUGH, "fallthrough", keyword},
|
||||||
elt{ token.FOR, "for", keyword },
|
elt{token.FOR, "for", keyword},
|
||||||
|
|
||||||
elt{ token.FUNC, "func", keyword },
|
elt{token.FUNC, "func", keyword},
|
||||||
elt{ token.GO, "go", keyword },
|
elt{token.GO, "go", keyword},
|
||||||
elt{ token.GOTO, "goto", keyword },
|
elt{token.GOTO, "goto", keyword},
|
||||||
elt{ token.IF, "if", keyword },
|
elt{token.IF, "if", keyword},
|
||||||
elt{ token.IMPORT, "import", keyword },
|
elt{token.IMPORT, "import", keyword},
|
||||||
|
|
||||||
elt{ token.INTERFACE, "interface", keyword },
|
elt{token.INTERFACE, "interface", keyword},
|
||||||
elt{ token.MAP, "map", keyword },
|
elt{token.MAP, "map", keyword},
|
||||||
elt{ token.PACKAGE, "package", keyword },
|
elt{token.PACKAGE, "package", keyword},
|
||||||
elt{ token.RANGE, "range", keyword },
|
elt{token.RANGE, "range", keyword},
|
||||||
elt{ token.RETURN, "return", keyword },
|
elt{token.RETURN, "return", keyword},
|
||||||
|
|
||||||
elt{ token.SELECT, "select", keyword },
|
elt{token.SELECT, "select", keyword},
|
||||||
elt{ token.STRUCT, "struct", keyword },
|
elt{token.STRUCT, "struct", keyword},
|
||||||
elt{ token.SWITCH, "switch", keyword },
|
elt{token.SWITCH, "switch", keyword},
|
||||||
elt{ token.TYPE, "type", keyword },
|
elt{token.TYPE, "type", keyword},
|
||||||
elt{ token.VAR, "var", keyword },
|
elt{token.VAR, "var", keyword},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const whitespace = " \t \n\n\n"; // to separate tokens
|
const whitespace = " \t \n\n\n" // to separate tokens
|
||||||
|
|
||||||
type TestErrorHandler struct {
|
type TestErrorHandler struct {
|
||||||
t *testing.T
|
t *testing.T;
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *TestErrorHandler) Error(pos token.Position, msg string) {
|
func (h *TestErrorHandler) Error(pos token.Position, msg string) {
|
||||||
|
|
@ -188,7 +194,7 @@ func checkPos(t *testing.T, lit string, pos, expected token.Position) {
|
||||||
if pos.Line != expected.Line {
|
if pos.Line != expected.Line {
|
||||||
t.Errorf("bad line for %s: got %d, expected %d", lit, pos.Line, expected.Line);
|
t.Errorf("bad line for %s: got %d, expected %d", lit, pos.Line, expected.Line);
|
||||||
}
|
}
|
||||||
if pos.Column!= expected.Column {
|
if pos.Column != expected.Column {
|
||||||
t.Errorf("bad column for %s: got %d, expected %d", lit, pos.Column, expected.Column);
|
t.Errorf("bad column for %s: got %d, expected %d", lit, pos.Column, expected.Column);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -207,7 +213,7 @@ func TestScan(t *testing.T) {
|
||||||
index := 0;
|
index := 0;
|
||||||
epos := token.Position{"", 0, 1, 1};
|
epos := token.Position{"", 0, 1, 1};
|
||||||
nerrors := Tokenize("", strings.Bytes(src), &TestErrorHandler{t}, ScanComments,
|
nerrors := Tokenize("", strings.Bytes(src), &TestErrorHandler{t}, ScanComments,
|
||||||
func (pos token.Position, tok token.Token, litb []byte) bool {
|
func(pos token.Position, tok token.Token, litb []byte) bool {
|
||||||
e := elt{token.EOF, "", special};
|
e := elt{token.EOF, "", special};
|
||||||
if index < len(tokens) {
|
if index < len(tokens) {
|
||||||
e = tokens[index];
|
e = tokens[index];
|
||||||
|
|
@ -227,7 +233,7 @@ func TestScan(t *testing.T) {
|
||||||
if tokenclass(tok) != e.class {
|
if tokenclass(tok) != e.class {
|
||||||
t.Errorf("bad class for %s: got %d, expected %d", lit, tokenclass(tok), e.class);
|
t.Errorf("bad class for %s: got %d, expected %d", lit, tokenclass(tok), e.class);
|
||||||
}
|
}
|
||||||
epos.Offset += len(lit) + len(whitespace);
|
epos.Offset += len(lit)+len(whitespace);
|
||||||
epos.Line += NewlineCount(lit) + whitespace_linecount;
|
epos.Line += NewlineCount(lit) + whitespace_linecount;
|
||||||
if tok == token.COMMENT && litb[1] == '/' {
|
if tok == token.COMMENT && litb[1] == '/' {
|
||||||
// correct for unaccounted '/n' in //-style comment
|
// correct for unaccounted '/n' in //-style comment
|
||||||
|
|
@ -236,8 +242,7 @@ func TestScan(t *testing.T) {
|
||||||
}
|
}
|
||||||
index++;
|
index++;
|
||||||
return tok != token.EOF;
|
return tok != token.EOF;
|
||||||
}
|
});
|
||||||
);
|
|
||||||
if nerrors != 0 {
|
if nerrors != 0 {
|
||||||
t.Errorf("found %d errors", nerrors);
|
t.Errorf("found %d errors", nerrors);
|
||||||
}
|
}
|
||||||
|
|
@ -245,28 +250,28 @@ func TestScan(t *testing.T) {
|
||||||
|
|
||||||
|
|
||||||
type seg struct {
|
type seg struct {
|
||||||
srcline string; // a line of source text
|
srcline string; // a line of source text
|
||||||
filename string; // filename for current token
|
filename string; // filename for current token
|
||||||
line int; // line number for current token
|
line int; // line number for current token
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
var segments = []seg{
|
var segments = []seg{
|
||||||
// exactly one token per line since the test consumes one token per segment
|
// exactly one token per line since the test consumes one token per segment
|
||||||
seg{ " line1", "TestLineComments", 1 },
|
seg{" line1", "TestLineComments", 1},
|
||||||
seg{ "\nline2", "TestLineComments", 2 },
|
seg{"\nline2", "TestLineComments", 2},
|
||||||
seg{ "\nline3 //line File1.go:100", "TestLineComments", 3 }, // bad line comment, ignored
|
seg{"\nline3 //line File1.go:100", "TestLineComments", 3}, // bad line comment, ignored
|
||||||
seg{ "\nline4", "TestLineComments", 4 },
|
seg{"\nline4", "TestLineComments", 4},
|
||||||
seg{ "\n//line File1.go:100\n line100", "File1.go", 100 },
|
seg{"\n//line File1.go:100\n line100", "File1.go", 100},
|
||||||
seg{ "\n//line File2.go:200\n line200", "File2.go", 200 },
|
seg{"\n//line File2.go:200\n line200", "File2.go", 200},
|
||||||
seg{ "\n//line :1\n line1", "", 1 },
|
seg{"\n//line :1\n line1", "", 1},
|
||||||
seg{ "\n//line foo:42\n line42", "foo", 42 },
|
seg{"\n//line foo:42\n line42", "foo", 42},
|
||||||
seg{ "\n //line foo:42\n line44", "foo", 44 }, // bad line comment, ignored
|
seg{"\n //line foo:42\n line44", "foo", 44}, // bad line comment, ignored
|
||||||
seg{ "\n//line foo 42\n line46", "foo", 46 }, // bad line comment, ignored
|
seg{"\n//line foo 42\n line46", "foo", 46}, // bad line comment, ignored
|
||||||
seg{ "\n//line foo:42 extra text\n line48", "foo", 48 }, // bad line comment, ignored
|
seg{"\n//line foo:42 extra text\n line48", "foo", 48}, // bad line comment, ignored
|
||||||
seg{ "\n//line foo:42\n line42", "foo", 42 },
|
seg{"\n//line foo:42\n line42", "foo", 42},
|
||||||
seg{ "\n//line foo:42\n line42", "foo", 42 },
|
seg{"\n//line foo:42\n line42", "foo", 42},
|
||||||
seg{ "\n//line File1.go:100\n line100", "File1.go", 100 },
|
seg{"\n//line File1.go:100\n line100", "File1.go", 100},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -298,16 +303,16 @@ func TestInit(t *testing.T) {
|
||||||
|
|
||||||
// 1st init
|
// 1st init
|
||||||
s.Init("", strings.Bytes("if true { }"), nil, 0);
|
s.Init("", strings.Bytes("if true { }"), nil, 0);
|
||||||
s.Scan(); // if
|
s.Scan(); // if
|
||||||
s.Scan(); // true
|
s.Scan(); // true
|
||||||
_, tok, _ := s.Scan(); // {
|
_, tok, _ := s.Scan(); // {
|
||||||
if tok != token.LBRACE {
|
if tok != token.LBRACE {
|
||||||
t.Errorf("bad token: got %s, expected %s", tok.String(), token.LBRACE);
|
t.Errorf("bad token: got %s, expected %s", tok.String(), token.LBRACE);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2nd init
|
// 2nd init
|
||||||
s.Init("", strings.Bytes("go true { ]"), nil, 0);
|
s.Init("", strings.Bytes("go true { ]"), nil, 0);
|
||||||
_, tok, _ = s.Scan(); // go
|
_, tok, _ = s.Scan(); // go
|
||||||
if tok != token.GO {
|
if tok != token.GO {
|
||||||
t.Errorf("bad token: got %s, expected %s", tok.String(), token.GO);
|
t.Errorf("bad token: got %s, expected %s", tok.String(), token.GO);
|
||||||
}
|
}
|
||||||
|
|
@ -340,23 +345,19 @@ func TestIllegalChars(t *testing.T) {
|
||||||
|
|
||||||
|
|
||||||
func TestStdErrorHander(t *testing.T) {
|
func TestStdErrorHander(t *testing.T) {
|
||||||
const src =
|
const src = "@\n" // illegal character, cause an error
|
||||||
"@\n" // illegal character, cause an error
|
"@ @\n" // two errors on the same line
|
||||||
"@ @\n" // two errors on the same line
|
|
||||||
"//line File2:20\n"
|
"//line File2:20\n"
|
||||||
"@\n" // different file, but same line
|
"@\n" // different file, but same line
|
||||||
"//line File2:1\n"
|
"//line File2:1\n"
|
||||||
"@ @\n" // same file, decreasing line number
|
"@ @\n" // same file, decreasing line number
|
||||||
"//line File1:1\n"
|
"//line File1:1\n"
|
||||||
"@ @ @" // original file, line 1 again
|
"@ @ @"; // original file, line 1 again
|
||||||
;
|
|
||||||
|
|
||||||
v := NewErrorVector();
|
v := NewErrorVector();
|
||||||
nerrors := Tokenize("File1", strings.Bytes(src), v, 0,
|
nerrors := Tokenize("File1", strings.Bytes(src), v, 0,
|
||||||
func (pos token.Position, tok token.Token, litb []byte) bool {
|
func(pos token.Position, tok token.Token, litb []byte) bool { return tok != token.EOF });
|
||||||
return tok != token.EOF;
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
list := v.GetErrorList(Raw);
|
list := v.GetErrorList(Raw);
|
||||||
if len(list) != 9 {
|
if len(list) != 9 {
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,8 @@ const testInput = `
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
|
||||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||||
<body xmlns:foo="ns1" xmlns="ns2" xmlns:tag="ns3" ` "\r\n\t" ` >
|
<body xmlns:foo="ns1" xmlns="ns2" xmlns:tag="ns3" `
|
||||||
|
"\r\n\t" ` >
|
||||||
<hello lang="en">World <>'" 白鵬翔</hello>
|
<hello lang="en">World <>'" 白鵬翔</hello>
|
||||||
<goodbye />
|
<goodbye />
|
||||||
<outer foo:attr="value" xmlns:tag="ns4">
|
<outer foo:attr="value" xmlns:tag="ns4">
|
||||||
|
|
@ -90,8 +91,8 @@ var cookedTokens = []Token{
|
||||||
}
|
}
|
||||||
|
|
||||||
type stringReader struct {
|
type stringReader struct {
|
||||||
s string;
|
s string;
|
||||||
off int;
|
off int;
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *stringReader) Read(b []byte) (n int, err os.Error) {
|
func (r *stringReader) Read(b []byte) (n int, err os.Error) {
|
||||||
|
|
@ -116,7 +117,7 @@ func (r *stringReader) ReadByte() (b byte, err os.Error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func StringReader(s string) io.Reader {
|
func StringReader(s string) io.Reader {
|
||||||
return &stringReader{s, 0}
|
return &stringReader{s, 0};
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRawToken(t *testing.T) {
|
func TestRawToken(t *testing.T) {
|
||||||
|
|
@ -146,4 +147,3 @@ func TestToken(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue