Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
go
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
go
Commits
3aa892c4
Commit
3aa892c4
authored
Apr 24, 2009
by
Robert Griesemer
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
daily snapshot:
- more work on template-driven ast printing R=r OCL=27851 CL=27851
parent
b03b541b
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
314 additions
and
149 deletions
+314
-149
usr/gri/pretty/ast.txt
usr/gri/pretty/ast.txt
+36
-10
usr/gri/pretty/format.go
usr/gri/pretty/format.go
+278
-139
No files found.
usr/gri/pretty/ast.txt
View file @
3aa892c4
//
TODO prefix decl doesn't work
//
string =
//
ast .
//
"%s" ;
ast.Ident
=
pointer
=
Value .
^ ;
a
st.Program
=
a
rray
=
"package " Name "\n" { Decls "\n\n" } .
^ ;
ast.GenDecl
=
//token.Token
=
"def " .
// "token<%d>" ; // this should be a Go-installed formatter
ast.FuncDecl =
ast
"func " .
;
\ No newline at end of file
Comments =
"comments\n" ;
Ident =
Value ;
Program =
"package " Name "\n\n" { Decls "\n\n" } ;
GenDecl =
Doc
Tok " (\n"
")\n";
FuncType =
"(" { Params } ")" ;
BlockStmt =
"{\n" "}\n" ;
FuncDecl =
"func " Name Type [ " " Body ] ;
Decl =
^ ;
\ No newline at end of file
usr/gri/pretty/format.go
View file @
3aa892c4
...
@@ -17,39 +17,88 @@ import (
...
@@ -17,39 +17,88 @@ import (
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
// Format
// Format
// node kind
// A production expression is built from the following nodes.
const
(
//
self
=
iota
;
type
(
alternative
;
expr
interface
{
sequence
;
implements_expr
();
field
;
};
literal
;
option
;
empty
struct
{
repetition
;
};
alternative
struct
{
x
,
y
expr
;
};
sequence
struct
{
x
,
y
expr
;
};
field
struct
{
name
string
;
// including "^", "*"
format
expr
;
// nil if no format specified
};
literal
struct
{
// TODO should there be other types or should it all be string literals?
value
[]
byte
;
};
option
struct
{
x
expr
};
repetition
struct
{
x
expr
};
// TODO custom formats are not yet used
custom
struct
{
name
string
;
f
func
(
w
io
.
Write
,
value
interface
{},
name
string
)
bool
};
)
)
type
node
struct
{
// These methods are used to enforce the "implements" relationship for
kind
int
;
// better compile-time type checking.
name
string
;
// field name
//
value
[]
byte
;
// literal value
// TODO If we had a basic accessor mechanism in the language (a field
x
,
y
*
node
;
// "f T" automatically implements a corresponding accessor "f() T", this
}
// could be expressed more easily by simply providing the field.
//
func
(
x
*
empty
)
implements_expr
()
{}
func
(
x
*
alternative
)
implements_expr
()
{}
func
(
x
*
sequence
)
implements_expr
()
{}
func
(
x
*
field
)
implements_expr
()
{}
func
(
x
*
literal
)
implements_expr
()
{}
func
(
x
*
option
)
implements_expr
()
{}
func
(
x
*
repetition
)
implements_expr
()
{}
func
(
x
*
custom
)
implements_expr
()
{}
// A Format is a set of production
node
s.
// A Format is a set of production
expression
s.
type
Format
map
[
string
]
*
node
;
type
Format
map
[
string
]
expr
;
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
// Parsing
// Parsing
/* TODO
- EBNF vs Kleene notation
- default formatters for basic types (may imply scopes so we can override)
- installable custom formatters (like for template.go)
- format strings
*/
/* Format = { Production } .
/* Format = { Production } .
Production =
DottedName [ "=" Expression ] ".
" .
Production =
Name [ "=" [ Expression ] ] ";
" .
DottedName = name { "." name
} .
Name = identifier { "." identifier
} .
Expression = Term { "|" Term } .
Expression = Term { "|" Term } .
Term = Factor { Factor } .
Term = Factor { Factor } .
Factor = "*" | name | string_literal | Group | Option | Repetition .
Factor = string_literal | Field | Group | Option | Repetition .
Field = ( "^" | "*" | Name ) [ ":" Expression ] .
Group = "(" Expression ")" .
Group = "(" Expression ")" .
Option = "[" Expression "]" .
Option = "[" Expression "]" .
Repetition = "{" Expression "}" .
Repetition = "{" Expression "}" .
...
@@ -109,30 +158,30 @@ func (p *parser) expect(tok token.Token) token.Position {
...
@@ -109,30 +158,30 @@ func (p *parser) expect(tok token.Token) token.Position {
}
}
func
(
p
*
parser
)
parse
Name
()
string
{
func
(
p
*
parser
)
parse
Identifier
()
string
{
name
:=
string
(
p
.
lit
);
name
:=
string
(
p
.
lit
);
p
.
expect
(
token
.
IDENT
);
p
.
expect
(
token
.
IDENT
);
return
name
;
return
name
;
}
}
func
(
p
*
parser
)
parse
Dotted
Name
()
string
{
func
(
p
*
parser
)
parseName
()
string
{
name
:=
p
.
parse
Name
();
name
:=
p
.
parse
Identifier
();
for
p
.
tok
==
token
.
PERIOD
{
for
p
.
tok
==
token
.
PERIOD
{
p
.
next
();
p
.
next
();
name
=
name
+
"."
+
p
.
parse
Name
();
name
=
name
+
"."
+
p
.
parse
Identifier
();
}
}
return
name
;
return
name
;
}
}
// TODO should have WriteByte in ByteBuffer instead!
// TODO WriteByte should be a ByteBuffer method
var
(
func
writeByte
(
buf
*
io
.
ByteBuffer
,
b
byte
)
{
newlineByte
=
[]
byte
{
'\n'
};
buf
.
Write
([]
byte
{
b
});
tabByte
=
[]
byte
{
'\t'
};
}
)
// TODO make this complete
func
escapeString
(
s
[]
byte
)
[]
byte
{
func
escapeString
(
s
[]
byte
)
[]
byte
{
// the string syntax is correct since it comes from the scannner
// the string syntax is correct since it comes from the scannner
var
buf
io
.
ByteBuffer
;
var
buf
io
.
ByteBuffer
;
...
@@ -141,14 +190,13 @@ func escapeString(s []byte) []byte {
...
@@ -141,14 +190,13 @@ func escapeString(s []byte) []byte {
if
s
[
i
]
==
'\\'
{
if
s
[
i
]
==
'\\'
{
buf
.
Write
(
s
[
i0
:
i
]);
buf
.
Write
(
s
[
i0
:
i
]);
i
++
;
i
++
;
var
esc
byte
;
switch
s
[
i
]
{
switch
s
[
i
]
{
case
'n'
:
case
'n'
:
esc
=
'\n'
;
buf
.
Write
(
newlineByte
);
case
't'
:
esc
=
'\t'
;
case
't'
:
default
:
panic
(
"unhandled escape:"
,
string
(
s
[
i
]));
buf
.
Write
(
tabByte
);
default
:
panic
(
"unhandled escape:"
,
string
(
s
[
i
]));
}
}
writeByte
(
&
buf
,
esc
);
i
++
;
i
++
;
i0
=
i
;
i0
=
i
;
}
else
{
}
else
{
...
@@ -182,32 +230,54 @@ func (p *parser) parseValue() []byte {
...
@@ -182,32 +230,54 @@ func (p *parser) parseValue() []byte {
}
}
func
(
p
*
parser
)
parseExpr
ession
()
*
node
func
(
p
*
parser
)
parseExpr
()
expr
func
(
p
*
parser
)
parseFactor
()
(
x
*
node
)
{
func
(
p
*
parser
)
parseField
()
expr
{
var
name
string
;
switch
p
.
tok
{
switch
p
.
tok
{
case
token
.
XOR
:
name
=
"^"
;
p
.
next
();
case
token
.
MUL
:
case
token
.
MUL
:
x
=
&
node
{
self
,
""
,
nil
,
nil
,
nil
}
;
name
=
"*"
;
p
.
next
();
case
token
.
IDENT
:
case
token
.
IDENT
:
x
=
&
node
{
field
,
p
.
parseName
(),
nil
,
nil
,
nil
};
name
=
p
.
parseName
();
default
:
panic
(
"unreachable"
);
}
var
format
expr
;
if
p
.
tok
==
token
.
COLON
{
p
.
next
();
format
=
p
.
parseExpr
();
}
return
&
field
{
name
,
format
};
}
func
(
p
*
parser
)
parseFactor
()
(
x
expr
)
{
switch
p
.
tok
{
case
token
.
XOR
,
token
.
MUL
,
token
.
IDENT
:
x
=
p
.
parseField
();
case
token
.
STRING
:
case
token
.
STRING
:
x
=
&
node
{
literal
,
""
,
p
.
parseValue
(),
nil
,
nil
};
x
=
&
literal
{
p
.
parseValue
()
};
case
token
.
LPAREN
:
case
token
.
LPAREN
:
p
.
next
();
p
.
next
();
x
=
p
.
parseExpr
ession
();
x
=
p
.
parseExpr
();
p
.
expect
(
token
.
RPAREN
);
p
.
expect
(
token
.
RPAREN
);
case
token
.
LBRACK
:
case
token
.
LBRACK
:
p
.
next
();
p
.
next
();
x
=
&
node
{
option
,
""
,
nil
,
p
.
parseExpression
(),
nil
};
x
=
&
option
{
p
.
parseExpr
()
};
p
.
expect
(
token
.
RBRACK
);
p
.
expect
(
token
.
RBRACK
);
case
token
.
LBRACE
:
case
token
.
LBRACE
:
p
.
next
();
p
.
next
();
x
=
&
node
{
repetition
,
""
,
nil
,
p
.
parseExpression
(),
nil
};
x
=
&
repetition
{
p
.
parseExpr
()
};
p
.
expect
(
token
.
RBRACE
);
p
.
expect
(
token
.
RBRACE
);
default
:
default
:
...
@@ -219,46 +289,52 @@ func (p *parser) parseFactor() (x *node) {
...
@@ -219,46 +289,52 @@ func (p *parser) parseFactor() (x *node) {
}
}
func
(
p
*
parser
)
parseTerm
()
*
node
{
func
(
p
*
parser
)
parseTerm
()
expr
{
x
:=
p
.
parseFactor
();
x
:=
p
.
parseFactor
();
for
p
.
tok
==
token
.
IDENT
||
for
p
.
tok
==
token
.
XOR
||
p
.
tok
==
token
.
MUL
||
p
.
tok
==
token
.
IDENT
||
p
.
tok
==
token
.
STRING
||
p
.
tok
==
token
.
STRING
||
p
.
tok
==
token
.
LPAREN
||
p
.
tok
==
token
.
LPAREN
||
p
.
tok
==
token
.
LBRACK
||
p
.
tok
==
token
.
LBRACK
||
p
.
tok
==
token
.
LBRACE
p
.
tok
==
token
.
LBRACE
{
{
y
:=
p
.
parseFactor
();
y
:=
p
.
parseFactor
();
x
=
&
node
{
sequence
,
""
,
nil
,
x
,
y
};
x
=
&
sequence
{
x
,
y
};
}
}
return
x
;
return
x
;
}
}
func
(
p
*
parser
)
parseExpr
ession
()
*
node
{
func
(
p
*
parser
)
parseExpr
()
expr
{
x
:=
p
.
parseTerm
();
x
:=
p
.
parseTerm
();
for
p
.
tok
==
token
.
OR
{
for
p
.
tok
==
token
.
OR
{
p
.
next
();
p
.
next
();
y
:=
p
.
parseTerm
();
y
:=
p
.
parseTerm
();
x
=
&
node
{
alternative
,
""
,
nil
,
x
,
y
};
x
=
&
alternative
{
x
,
y
};
}
}
return
x
;
return
x
;
}
}
func
(
p
*
parser
)
parseProduction
()
(
string
,
*
node
)
{
func
(
p
*
parser
)
parseProduction
()
(
string
,
expr
)
{
name
:=
p
.
parse
Dotted
Name
();
name
:=
p
.
parseName
();
var
x
*
node
;
var
x
expr
;
if
p
.
tok
==
token
.
ASSIGN
{
if
p
.
tok
==
token
.
ASSIGN
{
p
.
next
();
p
.
next
();
x
=
p
.
parseExpression
();
if
p
.
tok
==
token
.
SEMICOLON
{
x
=
&
empty
{};
}
else
{
x
=
p
.
parseExpr
();
}
}
}
p
.
expect
(
token
.
PERIOD
);
p
.
expect
(
token
.
SEMICOLON
);
return
name
,
x
;
return
name
,
x
;
}
}
...
@@ -365,118 +441,181 @@ func getField(v reflect.StructValue, fieldname string) reflect.Value {
...
@@ -365,118 +441,181 @@ func getField(v reflect.StructValue, fieldname string) reflect.Value {
}
}
func
(
f
Format
)
apply
(
w
io
.
Write
,
v
reflect
.
Value
)
bool
func
typename
(
value
reflect
.
Value
)
string
{
name
:=
value
.
Type
()
.
Name
();
// Returns true if a non-empty field value was found.
if
name
!=
""
{
func
(
f
Format
)
print
(
w
io
.
Write
,
x
*
node
,
v
reflect
.
Value
,
index
int
)
bool
{
return
name
;
switch
x
.
kind
{
}
case
self
:
panic
(
"self"
);
case
alternative
:
switch
value
.
Kind
()
{
// print the contents of the first alternative with a non-empty field
case
reflect
.
ArrayKind
:
name
=
"array"
;
var
buf
io
.
ByteBuffer
;
case
reflect
.
BoolKind
:
name
=
"bool"
;
if
!
f
.
print
(
&
buf
,
x
.
x
,
v
,
-
1
)
{
case
reflect
.
ChanKind
:
name
=
"chan"
;
f
.
print
(
&
buf
,
x
.
y
,
v
,
-
1
);
case
reflect
.
DotDotDotKind
:
name
=
"..."
;
}
case
reflect
.
FloatKind
:
name
=
"float"
;
w
.
Write
(
buf
.
Data
());
case
reflect
.
Float32Kind
:
name
=
"float32"
;
case
reflect
.
Float64Kind
:
name
=
"float64"
;
case
reflect
.
FuncKind
:
name
=
"func"
;
case
reflect
.
IntKind
:
name
=
"int"
;
case
reflect
.
Int16Kind
:
name
=
"int16"
;
case
reflect
.
Int32Kind
:
name
=
"int32"
;
case
reflect
.
Int64Kind
:
name
=
"int64"
;
case
reflect
.
Int8Kind
:
name
=
"int8"
;
case
reflect
.
InterfaceKind
:
name
=
"interface"
;
case
reflect
.
MapKind
:
name
=
"map"
;
case
reflect
.
PtrKind
:
name
=
"pointer"
;
case
reflect
.
StringKind
:
name
=
"string"
;
case
reflect
.
StructKind
:
name
=
"struct"
;
case
reflect
.
UintKind
:
name
=
"uint"
;
case
reflect
.
Uint16Kind
:
name
=
"uint16"
;
case
reflect
.
Uint32Kind
:
name
=
"uint32"
;
case
reflect
.
Uint64Kind
:
name
=
"uint64"
;
case
reflect
.
Uint8Kind
:
name
=
"uint8"
;
case
reflect
.
UintptrKind
:
name
=
"uintptr"
;
}
return
name
;
}
case
sequence
:
f
.
print
(
w
,
x
.
x
,
v
,
-
1
);
f
.
print
(
w
,
x
.
y
,
v
,
-
1
);
case
field
:
var
defaultFormat
=
&
literal
{
io
.
StringBytes
(
"%v"
)};
if
sv
,
is_struct
:=
v
.
(
reflect
.
StructValue
);
is_struct
{
return
f
.
apply
(
w
,
getField
(
sv
,
x
.
name
));
}
else
{
panicln
(
"not in a struct - field:"
,
x
.
name
);
}
case
literal
:
func
(
f
Format
)
getFormat
(
value
reflect
.
Value
)
expr
{
w
.
Write
(
x
.
value
);
if
format
,
found
:=
f
[
typename
(
value
)];
found
{
return
format
;
}
// no format found
return
defaultFormat
;
}
case
option
:
// print the contents of the option if there is a non-empty field
var
buf
io
.
ByteBuffer
;
if
f
.
print
(
&
buf
,
x
.
x
,
v
,
-
1
)
{
w
.
Write
(
buf
.
Data
());
}
case
repetition
:
// Count the number of printf-style '%' formatters in s.
// print the contents of the repetition while there is a non-empty field
// The result is 0, 1, or 2 (where 2 stands for 2 or more).
for
i
:=
0
;
;
i
++
{
//
var
buf
io
.
ByteBuffer
;
func
percentCount
(
s
[]
byte
)
int
{
if
f
.
print
(
&
buf
,
x
.
x
,
v
,
i
)
{
n
:=
0
;
w
.
Write
(
buf
.
Data
());
for
i
:=
0
;
n
<
2
&&
i
<
len
(
s
);
i
++
{
}
else
{
// TODO should not count "%%"'s
break
;
if
s
[
i
]
==
'%'
{
}
n
++
;
}
}
default
:
panic
(
"unreachable"
);
}
}
return
n
;
return
false
;
}
}
func
(
f
Format
)
Dump
()
{
func
printf
(
w
io
.
Write
,
format
[]
byte
,
value
reflect
.
Value
)
{
for
name
,
x
:=
range
f
{
// TODO this seems a bit of a hack
println
(
name
,
x
);
if
percentCount
(
format
)
==
1
{
// exactly one '%' format specifier - try to use it
fmt
.
Fprintf
(
w
,
string
(
format
),
value
.
Interface
());
}
else
{
// 0 or more then 1 '%' format specifier - ignore them
w
.
Write
(
format
);
}
}
}
}
func
(
f
Format
)
apply
(
w
io
.
Write
,
v
reflect
.
Value
)
bool
{
// Returns true if a non-empty field value was found.
println
(
"apply typename:"
,
v
.
Type
()
.
Name
());
func
(
f
Format
)
print
(
w
io
.
Write
,
format
expr
,
value
reflect
.
Value
,
index
int
)
bool
{
switch
t
:=
format
.
(
type
)
{
case
*
empty
:
return
true
;
if
x
,
found
:=
f
[
v
.
Type
()
.
Name
()];
found
{
case
*
alternative
:
// format using corresponding production
// print the contents of the first alternative with a non-empty field
f
.
print
(
w
,
x
,
v
,
-
1
);
var
buf
io
.
ByteBuffer
;
b
:=
f
.
print
(
&
buf
,
t
.
x
,
value
,
index
);
}
else
{
if
!
b
{
// format using default formats
b
=
f
.
print
(
&
buf
,
t
.
y
,
value
,
index
);
switch
x
:=
v
.
(
type
)
{
}
case
reflect
.
ArrayValue
:
if
b
{
if
x
.
Len
()
==
0
{
w
.
Write
(
buf
.
Data
());
return
false
;
}
}
return
index
<
0
||
b
;
for
i
:=
0
;
i
<
x
.
Len
();
i
++
{
f
.
apply
(
w
,
x
.
Elem
(
i
));
case
*
sequence
:
b1
:=
f
.
print
(
w
,
t
.
x
,
value
,
index
);
b2
:=
f
.
print
(
w
,
t
.
y
,
value
,
index
);
return
index
<
0
||
b1
&&
b2
;
case
*
field
:
var
x
reflect
.
Value
;
switch
t
.
name
{
case
"^"
:
if
v
,
is_ptr
:=
value
.
(
reflect
.
PtrValue
);
is_ptr
{
if
v
.
Get
()
==
nil
{
return
false
;
}
x
=
v
.
Sub
();
}
else
if
v
,
is_array
:=
value
.
(
reflect
.
ArrayValue
);
is_array
{
if
index
<
0
||
v
.
Len
()
<=
index
{
return
false
;
}
x
=
v
.
Elem
(
index
);
}
else
if
v
,
is_interface
:=
value
.
(
reflect
.
InterfaceValue
);
is_interface
{
if
v
.
Get
()
==
nil
{
return
false
;
}
x
=
v
.
Value
();
}
else
{
panic
(
"not a ptr, array, or interface"
);
// TODO fix this
}
}
case
"*"
:
case
reflect
.
StringValue
:
x
=
value
;
w
.
Write
(
io
.
StringBytes
(
x
.
Get
()));
default
:
if
v
,
is_struct
:=
value
.
(
reflect
.
StructValue
);
is_struct
{
case
reflect
.
IntValue
:
x
=
getField
(
v
,
t
.
name
);
// TODO is this the correct way to check the right type?
// or should it be t, ok := x.Interface().(token.Token) instead?
if
x
.
Type
()
.
Name
()
==
"token.Token"
{
fmt
.
Fprintf
(
w
,
"%s"
,
token
.
Token
(
x
.
Get
())
.
String
());
}
else
{
}
else
{
fmt
.
Fprintf
(
w
,
"%d"
,
x
.
Get
());
panic
(
"not a struct"
);
// TODO fix this
}
}
}
format
=
t
.
format
;
if
format
==
nil
{
format
=
f
.
getFormat
(
x
);
}
b
:=
f
.
print
(
w
,
format
,
x
,
index
);
return
index
<
0
||
b
;
case
reflect
.
InterfaceValue
:
case
*
literal
:
f
.
apply
(
w
,
x
.
Value
());
printf
(
w
,
t
.
value
,
value
);
return
true
;
case
reflect
.
PtrValue
:
case
*
option
:
// TODO is this the correct way to check nil ptr?
// print the contents of the option if there is a non-empty field
if
x
.
Get
()
==
nil
{
var
buf
io
.
ByteBuffer
;
return
false
;
b
:=
f
.
print
(
&
buf
,
t
.
x
,
value
,
-
1
);
}
if
b
{
return
f
.
apply
(
w
,
x
.
Sub
());
w
.
Write
(
buf
.
Data
());
}
return
index
<
0
||
b
;
default
:
case
*
repetition
:
panicln
(
"unsupported kind:"
,
v
.
Kind
());
// print the contents of the repetition while there is a non-empty field
b
:=
false
;
for
i
:=
0
;
;
i
++
{
var
buf
io
.
ByteBuffer
;
if
f
.
print
(
&
buf
,
t
.
x
,
value
,
i
)
{
w
.
Write
(
buf
.
Data
());
b
=
true
;
}
else
{
break
;
}
}
}
return
index
<
0
||
b
;
case
*
custom
:
b
:=
t
.
f
(
w
,
value
.
Interface
(),
t
.
name
);
return
index
<
0
||
b
;
}
}
return
true
;
panic
(
"unreachable"
);
return
false
;
}
}
func
(
f
Format
)
Apply
(
w
io
.
Write
,
data
interface
{})
{
func
(
f
Format
)
Apply
(
w
io
.
Write
,
data
interface
{})
{
f
.
apply
(
w
,
reflect
.
NewValue
(
data
));
value
:=
reflect
.
NewValue
(
data
);
f
.
print
(
w
,
f
.
getFormat
(
value
),
value
,
-
1
);
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment