Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in
Toggle navigation
G
golang
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Commits
Issue Boards
Open sidebar
go
golang
Commits
fce91186
Commit
fce91186
authored
Jul 29, 2008
by
Robert Griesemer
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
- handling of pointer forward decls
- some comments added to bug cases - added notes R=r OCL=13543 CL=13543
parent
f436ade2
Show whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
116 additions
and
77 deletions
+116
-77
bug041.go
test/bugs/bug041.go
+8
-0
bug042.go
test/bugs/bug042.go
+8
-0
export.go
usr/gri/gosrc/export.go
+5
-5
globals.go
usr/gri/gosrc/globals.go
+2
-2
parser.go
usr/gri/gosrc/parser.go
+93
-70
No files found.
test/bugs/bug041.go
View file @
fce91186
...
@@ -13,3 +13,11 @@ type S struct {
...
@@ -13,3 +13,11 @@ type S struct {
func
main
()
{
func
main
()
{
var
s
S
;
var
s
S
;
}
}
/*
Another problem with implicit forward declarations (as in this program on line 6)
is that it is not clear in which scope the type (here "T") should be declared.
This is the main reason why we should not allow implicit forward declarations at all,
and instead have an explicit type forward declaration. For more on this subject
see bug042.go.
*/
test/bugs/bug042.go
View file @
fce91186
...
@@ -18,3 +18,11 @@ type T struct {
...
@@ -18,3 +18,11 @@ type T struct {
func
main
()
{
func
main
()
{
var
s
S
;
var
s
S
;
}
}
/*
Per discussion w/ Ken, some time ago, we came to the conclusion that explicit
forward declarations (as on line 5 in this program) are preferrable over
implicit forward declarations because they make it explicit in which scope a
type is to be declared fully, eventually. As an aside, the machinery for it is
almost free in the compiler (one extra 'if' as far as I can tell).
*/
usr/gri/gosrc/export.go
View file @
fce91186
...
@@ -115,7 +115,7 @@ func (E *Exporter) WriteScope(scope *Globals.Scope) {
...
@@ -115,7 +115,7 @@ func (E *Exporter) WriteScope(scope *Globals.Scope) {
// determine number of objects to export
// determine number of objects to export
n
:=
0
;
n
:=
0
;
for
p
:=
scope
.
entries
.
first
;
p
!=
nil
;
p
=
p
.
next
{
for
p
:=
scope
.
entries
.
first
;
p
!=
nil
;
p
=
p
.
next
{
if
p
.
obj
.
mark
{
if
p
.
obj
.
exported
{
n
++
;
n
++
;
}
}
}
}
...
@@ -123,7 +123,7 @@ func (E *Exporter) WriteScope(scope *Globals.Scope) {
...
@@ -123,7 +123,7 @@ func (E *Exporter) WriteScope(scope *Globals.Scope) {
// export the objects, if any
// export the objects, if any
if
n
>
0
{
if
n
>
0
{
for
p
:=
scope
.
entries
.
first
;
p
!=
nil
;
p
=
p
.
next
{
for
p
:=
scope
.
entries
.
first
;
p
!=
nil
;
p
=
p
.
next
{
if
p
.
obj
.
mark
{
if
p
.
obj
.
exported
{
E
.
WriteObject
(
p
.
obj
);
E
.
WriteObject
(
p
.
obj
);
}
}
}
}
...
@@ -136,8 +136,8 @@ func (E *Exporter) WriteScope(scope *Globals.Scope) {
...
@@ -136,8 +136,8 @@ func (E *Exporter) WriteScope(scope *Globals.Scope) {
func
(
E
*
Exporter
)
WriteObject
(
obj
*
Globals
.
Object
)
{
func
(
E
*
Exporter
)
WriteObject
(
obj
*
Globals
.
Object
)
{
if
obj
==
nil
||
!
obj
.
mark
{
if
obj
==
nil
||
!
obj
.
exported
{
panic
"obj == nil || !obj.
mark
"
;
panic
"obj == nil || !obj.
exported
"
;
}
}
if
obj
.
kind
==
Object
.
TYPE
&&
obj
.
typ
.
obj
==
obj
{
if
obj
.
kind
==
Object
.
TYPE
&&
obj
.
typ
.
obj
==
obj
{
...
@@ -274,7 +274,7 @@ func (E *Exporter) Export(comp* Globals.Compilation, file_name string) {
...
@@ -274,7 +274,7 @@ func (E *Exporter) Export(comp* Globals.Compilation, file_name string) {
pkg
:=
comp
.
pkgs
[
0
];
pkg
:=
comp
.
pkgs
[
0
];
E
.
WritePackage
(
pkg
);
E
.
WritePackage
(
pkg
);
for
p
:=
pkg
.
scope
.
entries
.
first
;
p
!=
nil
;
p
=
p
.
next
{
for
p
:=
pkg
.
scope
.
entries
.
first
;
p
!=
nil
;
p
=
p
.
next
{
if
p
.
obj
.
mark
{
if
p
.
obj
.
exported
{
E
.
WriteObject
(
p
.
obj
);
E
.
WriteObject
(
p
.
obj
);
}
}
}
}
...
...
usr/gri/gosrc/globals.go
View file @
fce91186
...
@@ -15,7 +15,7 @@ package Globals
...
@@ -15,7 +15,7 @@ package Globals
export
Object
export
Object
type
Object
struct
{
type
Object
struct
{
mark
bool
;
// mark => object marked for export
exported
bool
;
pos
int
;
// source position
pos
int
;
// source position
kind
int
;
kind
int
;
ident
string
;
ident
string
;
...
@@ -89,7 +89,7 @@ type Compilation struct {
...
@@ -89,7 +89,7 @@ type Compilation struct {
export
NewObject
export
NewObject
func
NewObject
(
pos
,
kind
int
,
ident
string
)
*
Object
{
func
NewObject
(
pos
,
kind
int
,
ident
string
)
*
Object
{
obj
:=
new
(
Object
);
obj
:=
new
(
Object
);
obj
.
mark
=
false
;
obj
.
exported
=
false
;
obj
.
pos
=
pos
;
obj
.
pos
=
pos
;
obj
.
kind
=
kind
;
obj
.
kind
=
kind
;
obj
.
ident
=
ident
;
obj
.
ident
=
ident
;
...
...
usr/gri/gosrc/parser.go
View file @
fce91186
...
@@ -29,6 +29,7 @@ type Parser struct {
...
@@ -29,6 +29,7 @@ type Parser struct {
// Semantic analysis
// Semantic analysis
top_scope
*
Globals
.
Scope
;
top_scope
*
Globals
.
Scope
;
undef_types
*
Globals
.
List
;
exports
*
Globals
.
List
;
exports
*
Globals
.
List
;
}
}
...
@@ -77,6 +78,7 @@ func (P *Parser) Open(comp *Globals.Compilation, S *Scanner.Scanner, verbose int
...
@@ -77,6 +78,7 @@ func (P *Parser) Open(comp *Globals.Compilation, S *Scanner.Scanner, verbose int
P
.
S
=
S
;
P
.
S
=
S
;
P
.
Next
();
P
.
Next
();
P
.
top_scope
=
Universe
.
scope
;
P
.
top_scope
=
Universe
.
scope
;
P
.
undef_types
=
Globals
.
NewList
();
P
.
exports
=
Globals
.
NewList
();
P
.
exports
=
Globals
.
NewList
();
}
}
...
@@ -244,7 +246,7 @@ func (P *Parser) ParseQualifiedIdent(pos int, ident string) *Globals.Object {
...
@@ -244,7 +246,7 @@ func (P *Parser) ParseQualifiedIdent(pos int, ident string) *Globals.Object {
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// Types
// Types
func
(
P
*
Parser
)
ParseType
()
*
Globals
.
Type
{
func
(
P
*
Parser
)
ParseType
()
*
Globals
.
Type
{
P
.
Trace
(
"Type"
);
P
.
Trace
(
"Type"
);
typ
:=
P
.
TryType
();
typ
:=
P
.
TryType
();
...
@@ -262,10 +264,11 @@ func (P *Parser) ParseTypeName() *Globals.Type {
...
@@ -262,10 +264,11 @@ func (P *Parser) ParseTypeName() *Globals.Type {
P
.
Trace
(
"TypeName"
);
P
.
Trace
(
"TypeName"
);
if
EnableSemanticTests
{
if
EnableSemanticTests
{
pos
:=
P
.
pos
;
obj
:=
P
.
ParseQualifiedIdent
(
-
1
,
""
);
obj
:=
P
.
ParseQualifiedIdent
(
-
1
,
""
);
typ
:=
obj
.
typ
;
typ
:=
obj
.
typ
;
if
obj
.
kind
!=
Object
.
TYPE
{
if
obj
.
kind
!=
Object
.
TYPE
{
P
.
Error
(
obj
.
pos
,
`"`
+
obj
.
ident
+
`" is not a type`
);
P
.
Error
(
pos
,
"qualified identifier does not denote a type"
);
typ
=
Universe
.
bad_t
;
typ
=
Universe
.
bad_t
;
}
}
P
.
Ecart
();
P
.
Ecart
();
...
@@ -571,12 +574,38 @@ func (P *Parser) ParsePointerType() *Globals.Type {
...
@@ -571,12 +574,38 @@ func (P *Parser) ParsePointerType() *Globals.Type {
P
.
Trace
(
"PointerType"
);
P
.
Trace
(
"PointerType"
);
P
.
Expect
(
Scanner
.
MUL
);
P
.
Expect
(
Scanner
.
MUL
);
typ
:=
Universe
.
undef_t
;
typ
:=
Globals
.
NewType
(
Type
.
POINTER
);
if
(
EnableSemanticTests
&&
P
.
tok
==
Scanner
.
IDENT
&&
P
.
Lookup
(
P
.
val
)
==
nil
)
{
// forward declaration
if
EnableSemanticTests
{
panic
"UNIMPLEMENTED *forward_declared_type"
;
if
P
.
tok
==
Scanner
.
IDENT
{
if
P
.
Lookup
(
P
.
val
)
==
nil
{
// implicit forward declaration
// TODO very problematic: in which scope should the
// type object be declared? It's different if this
// is inside a struct or say in a var declaration.
// This code is only here for "compatibility" with 6g.
pos
:=
P
.
pos
;
obj
:=
Globals
.
NewObject
(
pos
,
Object
.
TYPE
,
P
.
ParseIdent
());
obj
.
typ
=
Globals
.
NewType
(
Type
.
UNDEF
);
obj
.
typ
.
obj
=
obj
;
// primary type object
typ
.
elt
=
obj
.
typ
;
// TODO obj should be declared, but scope is not clear
}
else
{
// type name
// (ParseType() doesn't permit incomplete types,
// so call ParseTypeName() here)
typ
.
elt
=
P
.
ParseTypeName
();
}
}
else
{
typ
.
elt
=
P
.
ParseType
();
}
// collect undefined pointer types
if
typ
.
elt
.
form
==
Type
.
UNDEF
{
P
.
undef_types
.
AddTyp
(
typ
);
}
}
else
{
}
else
{
typ
=
Globals
.
NewType
(
Type
.
POINTER
);
typ
.
elt
=
P
.
ParseType
();
typ
.
elt
=
P
.
ParseType
();
}
}
...
@@ -589,6 +618,7 @@ func (P *Parser) ParsePointerType() *Globals.Type {
...
@@ -589,6 +618,7 @@ func (P *Parser) ParsePointerType() *Globals.Type {
func
(
P
*
Parser
)
TryType
()
*
Globals
.
Type
{
func
(
P
*
Parser
)
TryType
()
*
Globals
.
Type
{
P
.
Trace
(
"Type (try)"
);
P
.
Trace
(
"Type (try)"
);
pos
:=
P
.
pos
;
var
typ
*
Globals
.
Type
=
nil
;
var
typ
*
Globals
.
Type
=
nil
;
switch
P
.
tok
{
switch
P
.
tok
{
case
Scanner
.
IDENT
:
typ
=
P
.
ParseTypeName
();
case
Scanner
.
IDENT
:
typ
=
P
.
ParseTypeName
();
...
@@ -601,6 +631,10 @@ func (P *Parser) TryType() *Globals.Type {
...
@@ -601,6 +631,10 @@ func (P *Parser) TryType() *Globals.Type {
case
Scanner
.
MUL
:
typ
=
P
.
ParsePointerType
();
case
Scanner
.
MUL
:
typ
=
P
.
ParsePointerType
();
}
}
if
typ
!=
nil
&&
typ
.
form
==
Type
.
UNDEF
{
P
.
Error
(
pos
,
"incomplete type"
);
}
P
.
Ecart
();
P
.
Ecart
();
return
typ
;
return
typ
;
}
}
...
@@ -1464,7 +1498,7 @@ func (P *Parser) ParseConstSpec(exported bool) {
...
@@ -1464,7 +1498,7 @@ func (P *Parser) ParseConstSpec(exported bool) {
typ
:=
P
.
TryType
();
typ
:=
P
.
TryType
();
if
typ
!=
nil
{
if
typ
!=
nil
{
for
p
:=
list
.
first
;
p
!=
nil
;
p
=
p
.
next
{
for
p
:=
list
.
first
;
p
!=
nil
;
p
=
p
.
next
{
p
.
obj
.
mark
=
exported
;
p
.
obj
.
exported
=
exported
;
p
.
obj
.
typ
=
typ
;
// TODO should use/have set_type()!
p
.
obj
.
typ
=
typ
;
// TODO should use/have set_type()!
}
}
}
}
...
@@ -1477,27 +1511,6 @@ func (P *Parser) ParseConstSpec(exported bool) {
...
@@ -1477,27 +1511,6 @@ func (P *Parser) ParseConstSpec(exported bool) {
}
}
func
(
P
*
Parser
)
ParseConstDecl
(
exported
bool
)
{
P
.
Trace
(
"ConstDecl"
);
P
.
Expect
(
Scanner
.
CONST
);
if
P
.
tok
==
Scanner
.
LPAREN
{
P
.
Next
();
for
P
.
tok
==
Scanner
.
IDENT
{
P
.
ParseConstSpec
(
exported
);
if
P
.
tok
!=
Scanner
.
RPAREN
{
P
.
Expect
(
Scanner
.
SEMICOLON
);
}
}
P
.
Next
();
}
else
{
P
.
ParseConstSpec
(
exported
);
}
P
.
Ecart
();
}
func
(
P
*
Parser
)
ParseTypeSpec
(
exported
bool
)
{
func
(
P
*
Parser
)
ParseTypeSpec
(
exported
bool
)
{
P
.
Trace
(
"TypeSpec"
);
P
.
Trace
(
"TypeSpec"
);
...
@@ -1505,22 +1518,23 @@ func (P *Parser) ParseTypeSpec(exported bool) {
...
@@ -1505,22 +1518,23 @@ func (P *Parser) ParseTypeSpec(exported bool) {
ident
:=
P
.
ParseIdent
();
ident
:=
P
.
ParseIdent
();
obj
:=
P
.
top_scope
.
Lookup
(
ident
);
// only lookup in top scope!
obj
:=
P
.
top_scope
.
Lookup
(
ident
);
// only lookup in top scope!
if
obj
!=
nil
{
if
obj
!=
nil
{
// ok if forward declared type
//
name already declared -
ok if forward declared type
if
obj
.
kind
!=
Object
.
TYPE
||
obj
.
typ
.
form
!=
Type
.
UNDEF
{
if
obj
.
kind
!=
Object
.
TYPE
||
obj
.
typ
.
form
!=
Type
.
UNDEF
{
// TODO use obj.pos to refer to decl pos in error msg!
// TODO use obj.pos to refer to decl pos in error msg!
P
.
Error
(
pos
,
`"`
+
ident
+
`" is declared already`
);
P
.
Error
(
pos
,
`"`
+
ident
+
`" is declared already`
);
}
}
}
else
{
}
else
{
obj
=
Globals
.
NewObject
(
pos
,
Object
.
TYPE
,
ident
);
obj
=
Globals
.
NewObject
(
pos
,
Object
.
TYPE
,
ident
);
obj
.
mark
=
exported
;
obj
.
exported
=
exported
;
obj
.
typ
=
Universe
.
undef_t
;
// TODO fix this
obj
.
typ
=
Globals
.
NewType
(
Type
.
UNDEF
);
P
.
top_scope
.
Insert
(
obj
);
obj
.
typ
.
obj
=
obj
;
// primary type object
P
.
Declare
(
obj
);
}
}
typ
:=
P
.
TryType
();
// no type if we have a forward decl
typ
:=
P
.
TryType
();
// nil if we have an explicit forward declaration
if
typ
!=
nil
{
if
typ
!=
nil
{
// TODO what about the name of incomplete types?
obj
.
typ
=
typ
;
obj
.
typ
=
typ
;
// TODO should use/have set_typ()!
if
typ
.
obj
==
nil
{
if
typ
.
obj
==
nil
{
typ
.
obj
=
obj
;
// primary type object
typ
.
obj
=
obj
;
// primary type object
}
}
...
@@ -1530,27 +1544,6 @@ func (P *Parser) ParseTypeSpec(exported bool) {
...
@@ -1530,27 +1544,6 @@ func (P *Parser) ParseTypeSpec(exported bool) {
}
}
func
(
P
*
Parser
)
ParseTypeDecl
(
exported
bool
)
{
P
.
Trace
(
"TypeDecl"
);
P
.
Expect
(
Scanner
.
TYPE
);
if
P
.
tok
==
Scanner
.
LPAREN
{
P
.
Next
();
for
P
.
tok
==
Scanner
.
IDENT
{
P
.
ParseTypeSpec
(
exported
);
if
P
.
tok
!=
Scanner
.
RPAREN
{
P
.
Expect
(
Scanner
.
SEMICOLON
);
}
}
P
.
Next
();
}
else
{
P
.
ParseTypeSpec
(
exported
);
}
P
.
Ecart
();
}
func
(
P
*
Parser
)
ParseVarSpec
(
exported
bool
)
{
func
(
P
*
Parser
)
ParseVarSpec
(
exported
bool
)
{
P
.
Trace
(
"VarSpec"
);
P
.
Trace
(
"VarSpec"
);
...
@@ -1573,21 +1566,32 @@ func (P *Parser) ParseVarSpec(exported bool) {
...
@@ -1573,21 +1566,32 @@ func (P *Parser) ParseVarSpec(exported bool) {
}
}
func
(
P
*
Parser
)
ParseVarDecl
(
exported
bool
)
{
// TODO With method variables, we wouldn't need this dispatch function.
P
.
Trace
(
"VarDecl"
);
func
(
P
*
Parser
)
ParseSpec
(
exported
bool
,
keyword
int
)
{
switch
keyword
{
case
Scanner
.
CONST
:
P
.
ParseConstSpec
(
exported
);
case
Scanner
.
TYPE
:
P
.
ParseTypeSpec
(
exported
);
case
Scanner
.
VAR
:
P
.
ParseVarSpec
(
exported
);
default
:
panic
"UNREACHABLE"
;
}
}
func
(
P
*
Parser
)
ParseDecl
(
exported
bool
,
keyword
int
)
{
P
.
Trace
(
"Decl"
);
P
.
Expect
(
Scanner
.
VAR
);
P
.
Expect
(
keyword
);
if
P
.
tok
==
Scanner
.
LPAREN
{
if
P
.
tok
==
Scanner
.
LPAREN
{
P
.
Next
();
P
.
Next
();
for
P
.
tok
==
Scanner
.
IDENT
{
for
P
.
tok
==
Scanner
.
IDENT
{
P
.
Parse
VarSpec
(
exporte
d
);
P
.
Parse
Spec
(
exported
,
keywor
d
);
if
P
.
tok
!=
Scanner
.
RPAREN
{
if
P
.
tok
!=
Scanner
.
RPAREN
{
P
.
Expect
(
Scanner
.
SEMICOLON
);
P
.
Expect
(
Scanner
.
SEMICOLON
);
}
}
}
}
P
.
Next
();
P
.
Next
();
}
else
{
}
else
{
P
.
Parse
VarSpec
(
exporte
d
);
P
.
Parse
Spec
(
exported
,
keywor
d
);
}
}
P
.
Ecart
();
P
.
Ecart
();
...
@@ -1643,12 +1647,8 @@ func (P *Parser) ParseDeclaration() {
...
@@ -1643,12 +1647,8 @@ func (P *Parser) ParseDeclaration() {
exported
=
true
;
exported
=
true
;
}
}
switch
P
.
tok
{
switch
P
.
tok
{
case
Scanner
.
CONST
:
case
Scanner
.
CONST
,
Scanner
.
TYPE
,
Scanner
.
VAR
:
P
.
ParseConstDecl
(
exported
);
P
.
ParseDecl
(
exported
,
P
.
tok
);
case
Scanner
.
TYPE
:
P
.
ParseTypeDecl
(
exported
);
case
Scanner
.
VAR
:
P
.
ParseVarDecl
(
exported
);
case
Scanner
.
FUNC
:
case
Scanner
.
FUNC
:
P
.
ParseFuncDecl
(
exported
);
P
.
ParseFuncDecl
(
exported
);
case
Scanner
.
EXPORT
:
case
Scanner
.
EXPORT
:
...
@@ -1676,6 +1676,28 @@ func (P *Parser) ParseDeclaration() {
...
@@ -1676,6 +1676,28 @@ func (P *Parser) ParseDeclaration() {
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// Program
// Program
func
(
P
*
Parser
)
ResolveUndefTypes
()
{
if
!
EnableSemanticTests
{
return
;
}
for
p
:=
P
.
undef_types
.
first
;
p
!=
nil
;
p
=
p
.
next
{
typ
:=
p
.
typ
;
if
typ
.
form
!=
Type
.
POINTER
{
panic
"unresolved types should be pointers only"
;
}
if
typ
.
elt
.
form
!=
Type
.
UNDEF
{
panic
"unresolved pointer should point to undefined type"
;
}
obj
:=
typ
.
elt
.
obj
;
typ
.
elt
=
obj
.
typ
;
if
typ
.
elt
.
form
==
Type
.
UNDEF
{
P
.
Error
(
obj
.
pos
,
`"`
+
obj
.
ident
+
`" is not declared`
);
}
}
}
func
(
P
*
Parser
)
MarkExports
()
{
func
(
P
*
Parser
)
MarkExports
()
{
if
!
EnableSemanticTests
{
if
!
EnableSemanticTests
{
return
;
return
;
...
@@ -1685,7 +1707,7 @@ func (P *Parser) MarkExports() {
...
@@ -1685,7 +1707,7 @@ func (P *Parser) MarkExports() {
for
p
:=
P
.
exports
.
first
;
p
!=
nil
;
p
=
p
.
next
{
for
p
:=
P
.
exports
.
first
;
p
!=
nil
;
p
=
p
.
next
{
obj
:=
scope
.
Lookup
(
p
.
str
);
obj
:=
scope
.
Lookup
(
p
.
str
);
if
obj
!=
nil
{
if
obj
!=
nil
{
obj
.
mark
=
true
;
obj
.
exported
=
true
;
// For now we export deep
// For now we export deep
// TODO this should change eventually - we need selective export
// TODO this should change eventually - we need selective export
if
obj
.
kind
==
Object
.
TYPE
{
if
obj
.
kind
==
Object
.
TYPE
{
...
@@ -1693,7 +1715,7 @@ func (P *Parser) MarkExports() {
...
@@ -1693,7 +1715,7 @@ func (P *Parser) MarkExports() {
if
typ
.
form
==
Type
.
STRUCT
||
typ
.
form
==
Type
.
INTERFACE
{
if
typ
.
form
==
Type
.
STRUCT
||
typ
.
form
==
Type
.
INTERFACE
{
scope
:=
typ
.
scope
;
scope
:=
typ
.
scope
;
for
p
:=
scope
.
entries
.
first
;
p
!=
nil
;
p
=
p
.
next
{
for
p
:=
scope
.
entries
.
first
;
p
!=
nil
;
p
=
p
.
next
{
p
.
obj
.
mark
=
true
;
p
.
obj
.
exported
=
true
;
}
}
}
}
}
}
...
@@ -1726,6 +1748,7 @@ func (P *Parser) ParseProgram() {
...
@@ -1726,6 +1748,7 @@ func (P *Parser) ParseProgram() {
P
.
Optional
(
Scanner
.
SEMICOLON
);
P
.
Optional
(
Scanner
.
SEMICOLON
);
}
}
P
.
ResolveUndefTypes
();
P
.
MarkExports
();
P
.
MarkExports
();
P
.
CloseScope
();
P
.
CloseScope
();
}
}
...
...
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