func BaseName(s string) string {
// TODO this is not correct for non-ASCII strings!
- i := len(s);
+ i := len(s) - 1;
for i >= 0 && s[i] != '/' {
if s[i] > 128 {
panic "non-ASCII string"
if s[i : len(s)] == ".go" {
s = s[0 : i];
}
- return s + ".7"
-}
-
-
-func Import(C *Globals.Compilation, pkg_name string) (pno int) {
- panic "UNIMPLEMENTED";
-}
-
-
-func Export(C *Globals.Compilation) {
- file_name := FixExt(BaseName(C.src_name)); // strip src dir
- Export.Export(file_name/*, C */);
+ return s + ".7";
}
export Compile
-func Compile(src_name string, verbose int) {
- comp := new(Globals.Compilation);
- comp.src_name = src_name;
- comp.pkg = nil;
- comp.nimports = 0;
-
- src, ok := sys.readfile(src_name);
+func Compile(file_name string, verbose int) {
+ src, ok := sys.readfile(file_name);
if !ok {
- print "cannot open ", src_name, "\n"
+ print "cannot open ", file_name, "\n"
return;
}
- Universe.Init();
+ Universe.Init(); // TODO eventually this should be only needed once
+
+ comp := Globals.NewCompilation();
+ pkg := Globals.NewPackage(file_name);
+ comp.Insert(pkg);
+ if comp.npkgs != 1 {
+ panic "should have exactly one package now";
+ }
- S := new(Scanner.Scanner);
- S.Open(src_name, src);
+ scanner := new(Scanner.Scanner);
+ scanner.Open(file_name, src);
- P := new(Parser.Parser);
- P.Open(S, verbose);
+ parser := new(Parser.Parser);
+ parser.Open(comp, scanner, verbose);
+
+ print "parsing ", file_name, "\n";
+ parser.ParseProgram();
+ if parser.S.nerrors > 0 {
+ return;
+ }
- print "parsing ", src_name, "\n";
- P.ParseProgram();
- //comp.Export();
+ // export
+ export_file_name := FixExt(BaseName(file_name)); // strip file dir
+ Export.Export(comp, export_file_name);
}
pkg.ref = E.pkg_ref;
E.pkg_ref++;
- E.WriteString(pkg.ident);
+ E.WriteString(pkg.obj.ident);
E.WriteString(pkg.file_name);
E.WriteString(pkg.key);
}
export Export
-func Export(file_name string /*comp *Compilation.Compilation*/) {
+func Export(comp *Globals.Compilation, file_name string) {
/*
Exporter exp;
exp.Export(comp, buf);
obj *Object; // primary type object or NULL
key *Object; // maps
elt *Object; // arrays, maps, channels, pointers, references
- scope *Scope; // incomplete types, structs, interfaces, functions, packages
+ scope *Scope; // structs, interfaces, functions
+}
+
+
+export Package
+type Package struct {
+ ref int; // for exporting only: >= 0 means already exported
+ file_name string;
+ key string;
+ obj *Object;
+ scope *Scope;
}
str string;
obj *Object;
typ *Type;
+ pkg *Package;
}
}
-export Package
-type Package struct {
- ref int; // for exporting only: >= 0 means already exported
- file_name string;
- ident string;
- key string;
- scope *Scope;
- pno int;
-}
-
-
export Compilation
type Compilation struct {
- src_name string;
- pkg *Object;
- imports [256] *Package; // TODO need open arrays
- nimports int;
+ // TODO use open arrays eventually
+ pkgs [256] *Package; // pkgs[0] is the current package
+ npkgs int;
}
export NewType
func NewType(form int) *Type {
typ := new(Type);
+ typ.ref = -1;
typ.form = form;
return typ;
}
+export NewPackage;
+func NewPackage(file_name string) *Package {
+ pkg := new(Package);
+ pkg.ref = -1;
+ pkg.file_name = file_name;
+ return pkg;
+}
+
+
export NewList
func NewList() *List {
return new(List);
}
-export NewPackage;
-func NewPackage() *Package {
- pkg := new(Package);
- return pkg;
+export NewCompilation;
+func NewCompilation() *Compilation {
+ comp := new(Compilation);
+ return comp;
}
// Compilation methods
func (C *Compilation) Lookup(file_name string) *Package {
- for i := 0; i < C.nimports; i++ {
- pkg := C.imports[i];
+ for i := 0; i < C.npkgs; i++ {
+ pkg := C.pkgs[i];
if pkg.file_name == file_name {
return pkg;
}
if C.Lookup(pkg.file_name) != nil {
panic "package already inserted";
}
- pkg.pno = C.nimports;
- C.imports[C.nimports] = pkg;
- C.nimports++;
+ C.pkgs[C.npkgs] = pkg;
+ C.npkgs++;
}
export Parser
type Parser struct {
+ comp *Globals.Compilation;
verbose, indent int;
S *Scanner.Scanner;
tok int; // one token look-ahead
beg, end int; // token position
ident string; // last ident seen
top_scope *Globals.Scope;
+ exports *Globals.List;
}
}
-func (P *Parser) Open(S *Scanner.Scanner, verbose int) {
+func (P *Parser) Open(comp *Globals.Compilation, S *Scanner.Scanner, verbose int) {
+ P.comp = comp;
P.verbose = verbose;
P.indent = 0;
P.S = S;
P.Next();
P.top_scope = Universe.scope;
+ P.exports = Globals.NewList();
}
if P.tok == Scanner.LPAREN {
P.Next();
for P.tok != Scanner.RPAREN {
- P.ParseIdent();
+ P.exports.AddStr(P.ParseIdent());
P.Optional(Scanner.COMMA); // TODO this seems wrong
}
P.Next();
} else {
- P.ParseIdent();
+ P.exports.AddStr(P.ParseIdent());
for P.tok == Scanner.COMMA {
P.Next();
- P.ParseIdent();
+ P.exports.AddStr(P.ParseIdent());
}
}
// ----------------------------------------------------------------------------
// Program
+func (P *Parser) MarkExports() {
+ if !EnableSemanticTests {
+ return;
+ }
+
+ scope := P.top_scope;
+ for p := P.exports.first; p != nil; p = p.next {
+ obj := scope.Lookup(p.str);
+ if obj != nil {
+ obj.mark = true;
+ // For now we export deep
+ // TODO this should change eventually - we need selective export
+ if obj.kind == Object.TYPE {
+ typ := obj.typ;
+ if typ.form == Type.STRUCT || typ.form == Type.INTERFACE {
+ scope := typ.scope;
+ for p := scope.entries.first; p != nil; p = p.next {
+ p.obj.mark = true;
+ }
+ }
+ }
+ } else {
+ // TODO need to report proper src position
+ P.Error(0, `"` + p.str + `" is not declared - cannot be exported`);
+ }
+ }
+}
+
+
func (P *Parser) ParseProgram() {
P.Trace("Program");
+
P.OpenScope();
P.Expect(Scanner.PACKAGE);
- P.ParseIdent();
+ pkg := P.comp.pkgs[0];
+ pkg.obj = P.ParseIdentDecl(Object.PACKAGE);
P.Optional(Scanner.SEMICOLON);
{ P.OpenScope();
+ pkg.scope = P.top_scope;
for P.tok == Scanner.IMPORT {
P.ParseImportDecl();
P.Optional(Scanner.SEMICOLON);
P.ParseDeclaration();
P.Optional(Scanner.SEMICOLON);
}
+
+ P.MarkExports();
P.CloseScope();
}
func (S *Scanner) Error(pos int, msg string) {
const errdist = 10;
- if pos > S.errpos + errdist || S.nerrors == 0 {
+ delta := pos - S.errpos; // may be negative!
+ if delta < errdist || delta > errdist || S.nerrors == 0 {
line, col := S.LineCol(pos);
if VerboseMsgs {
print S.filename, ":", line, ":", col, ": ", msg, "\n";
S.Open(filename, src);
P := new(Parser.Parser);
- P.Open(S, verbose);
+ P.Open(nil, S, verbose);
P.ParseProgram();
}