Commit 40c93a52 authored by Robert Griesemer's avatar Robert Griesemer

- experiments with forward-declaring types of non-imported packages

- adjusted switch syntax (no repeated case: case: anymore)
- enabled some constant expressions that work now

R=r
OCL=14098
CL=14098
parent fe582137
......@@ -52,7 +52,7 @@ func ReadImport(comp* Globals.Compilation, filename string, update bool) (data s
// see if it just works
data, ok = Platform.ReadSourceFile(filename);
if ok {
comp.env.Compile(comp.flags, comp.env, filename + Platform.src_file_ext);
comp.env.Compile(comp, filename + Platform.src_file_ext);
data, ok = ReadImport(comp, filename, false);
if ok {
return data, ok;
......@@ -73,30 +73,28 @@ export func Import(comp *Globals.Compilation, pkg_file string) *Globals.Package
}
export func Export(comp *Globals.Compilation) string {
panic "UNIMPLEMENTED";
return "";
export func Export(comp *Globals.Compilation, pkg_file string) {
data := Exporter.Export(comp);
ok := Platform.WriteObjectFile(pkg_file, data);
if !ok {
panic "export failed";
}
}
export func Compile(flags *Globals.Flags, env* Globals.Environment, filename string) {
// setup compilation
comp := new(Globals.Compilation);
comp.flags = flags;
comp.env = env;
src, ok := sys.readfile(filename);
export func Compile(comp *Globals.Compilation, src_file string) {
src, ok := Platform.ReadSourceFile(src_file);
if !ok {
print "cannot open ", filename, "\n"
print "cannot open ", src_file, "\n"
return;
}
if flags.verbosity > 0 {
print filename, "\n";
if comp.flags.verbosity > 0 {
print src_file, "\n";
}
scanner := new(Scanner.Scanner);
scanner.Open(filename, src);
scanner.Open(src_file, src);
var tstream *chan *Scanner.Token;
if comp.flags.token_chan {
......@@ -122,5 +120,5 @@ export func Compile(flags *Globals.Flags, env* Globals.Environment, filename str
Printer.PrintObject(comp, comp.pkg_list[0].obj, false);
}
Exporter.Export(comp, filename);
Export(comp, src_file);
}
......@@ -174,6 +174,12 @@ func (E *Exporter) WriteType(typ *Globals.Type) {
}
switch typ.form {
case Type.FORWARD:
// corresponding package must be forward-declared too
if typ.obj == nil || E.comp.pkg_list[typ.obj.pnolev].key != "" {
panic "inconsistency in package.type forward declaration";
}
case Type.ALIAS, Type.MAP:
E.WriteType(typ.aux);
E.WriteType(typ.elt);
......@@ -237,54 +243,7 @@ func (E *Exporter) WriteObject(obj *Globals.Object) {
}
func (E *Exporter) Export(comp* Globals.Compilation, file_name string) {
E.comp = comp;
E.debug = comp.flags.debug;
E.buf_pos = 0;
E.pkg_ref = 0;
E.type_ref = 0;
if E.debug {
print "exporting to ", file_name, "\n";
}
// write magic bits
magic := Platform.MAGIC_obj_file; // TODO remove once len(constant) works
for i := 0; i < len(magic); i++ {
E.WriteByte(magic[i]);
}
// Predeclared types are "pre-exported".
// TODO run the loop below only in debug mode
{ i := 0;
for p := Universe.types.first; p != nil; p = p.next {
if p.typ.ref != i {
panic "incorrect ref for predeclared type";
}
i++;
}
}
E.type_ref = Universe.types.len_;
// export package 0
pkg := comp.pkg_list[0];
E.WritePackage(pkg);
E.WriteScope(pkg.scope);
if E.debug {
print "\n(", E.buf_pos, " bytes)\n";
}
data := string(E.buf)[0 : E.buf_pos];
ok := sys.writefile(file_name, data);
if !ok {
panic "export failed";
}
}
func (E *Exporter) Export2(comp* Globals.Compilation) string {
func (E *Exporter) Export(comp* Globals.Compilation) string {
E.comp = comp;
E.debug = comp.flags.debug;
E.buf_pos = 0;
......@@ -322,13 +281,7 @@ func (E *Exporter) Export2(comp* Globals.Compilation) string {
}
export func Export(comp* Globals.Compilation, pkg_name string) {
var E Exporter;
(&E).Export(comp, Utils.TrimExt(Utils.BaseName(pkg_name), Platform.src_file_ext) + Platform.obj_file_ext);
}
export func Export2(comp* Globals.Compilation) string {
export func Export(comp* Globals.Compilation) string {
var E Exporter;
return (&E).Export2(comp);
return (&E).Export(comp);
}
......@@ -77,8 +77,8 @@ export type Flags struct {
export type Environment struct {
Error *func(comp *Compilation); // TODO complete this
Import *func(comp *Compilation, pkg_file string) *Package;
Export *func(comp *Compilation) string;
Compile *func(flags *Flags, env* Environment, file string);
Export *func(comp *Compilation, pkg_file string);
Compile *func(comp *Compilation, src_file string);
}
......@@ -147,7 +147,7 @@ export func NewPackage(file_name string, obj *Object, scope *Scope) *Package {
pkg := new(Package);
pkg.ref = -1; // not yet exported
pkg.file_name = file_name;
pkg.key = "<the package key>"; // TODO fix this
pkg.key = "<the package key>"; // empty key means package forward declaration
pkg.obj = obj;
pkg.scope = scope;
return pkg;
......
......@@ -89,6 +89,12 @@ func main() {
// compile files
for p := files.first; p != nil; p = p.next {
Compilation.Compile(flags, env, p.str);
// setup compilation
comp := new(Globals.Compilation);
comp.flags = flags;
comp.env = env;
// compile
Compilation.Compile(comp, p.str);
}
}
......@@ -132,9 +132,11 @@ func (I *Importer) ReadPackage() *Globals.Package {
if I.comp.flags.verbosity > 1 {
print `import: implicitly adding package `, ident, ` "`, file_name, `" (pno = `, obj.pnolev, ")\n";
}
} else if key != pkg.key {
} else if key != "" && key != pkg.key {
// the package was imported before but the package
// key has changed
// key has changed (a "" key indicates a forward-
// declared package - it's key is consistent with
// any actual package of the same name)
panic "package key inconsistency";
}
I.pkg_list[I.pkg_ref] = pkg;
......@@ -198,6 +200,10 @@ func (I *Importer) ReadType() *Globals.Type {
I.type_ref++;
switch (typ.form) {
case Type.FORWARD:
typ.scope = Globals.NewScope(nil);
break;
case Type.ALIAS, Type.MAP:
typ.aux = I.ReadType();
typ.elt = I.ReadType();
......
......@@ -715,33 +715,78 @@ func (P *Parser) ParsePointerType() *Globals.Type {
typ := Globals.NewType(Type.POINTER);
var elt *Globals.Type;
if P.semantic_checks && P.tok == Scanner.IDENT {
if P.Lookup(P.val) == nil {
// implicit forward declaration
// create a named forward type
if P.semantic_checks {
if P.tok == Scanner.STRING && !P.comp.flags.sixg {
// implicit package.type forward declaration
// TODO eventually the scanner should strip the quotes
pkg_name := P.val[1 : len(P.val) - 1]; // strip quotes
pkg := P.comp.Lookup(pkg_name);
if pkg == nil {
// package doesn't exist yet - add it to the package list
obj := Globals.NewObject(P.pos, Object.PACKAGE, ".pkg");
pkg = Globals.NewPackage(pkg_name, obj, Globals.NewScope(nil));
pkg.key = ""; // mark as forward-declared package
P.comp.Insert(pkg);
} else {
// package exists already - must be forward declaration
if pkg.key != "" {
P.Error(P.pos, `cannot use implicit package forward declaration for imported package "` + P.val + `"`);
panic "wrong package forward decl";
// TODO introduce dummy package so we can continue safely
}
}
P.Next(); // consume package name
P.Expect(Scanner.PERIOD);
pos, ident := P.ParseIdent();
obj := Globals.NewObject(pos, Object.TYPE, ident);
elt = Globals.NewType(Type.FORWARD);
obj.typ = elt;
elt.obj = obj; // primary type object;
// remember the current scope - resolving the forward
// type must find a matching declaration in this or a less nested scope
elt.scope = P.top_scope;
obj := pkg.scope.Lookup(ident);
if obj == nil {
elt = Globals.NewType(Type.FORWARD);
elt.scope = P.top_scope; // not really needed here, but for consistency
obj = Globals.NewObject(pos, Object.TYPE, ident);
obj.exported = true; // the type name must be visible
obj.typ = elt;
elt.obj = obj; // primary type object;
pkg.scope.Insert(obj);
obj.pnolev = pkg.obj.pnolev;
} else {
if obj.kind != Object.TYPE || obj.typ.form != Type.FORWARD {
panic "inconsistency in package.type forward declaration";
}
elt = obj.typ;
}
} else {
// type name
// (ParseType() (via TryType()) checks for forward types and complains,
// so call ParseTypeName() directly)
// we can only have a foward type here if we refer to the name of a
// yet incomplete type (i.e. if we are in the middle of a type's declaration)
elt = P.ParseTypeName();
}
} else if P.tok == Scanner.IDENT {
if P.Lookup(P.val) == nil {
// implicit type forward declaration
// create a named forward type
pos, ident := P.ParseIdent();
obj := Globals.NewObject(pos, Object.TYPE, ident);
elt = Globals.NewType(Type.FORWARD);
obj.typ = elt;
elt.obj = obj; // primary type object;
// remember the current scope - resolving the forward
// type must find a matching declaration in this or a less nested scope
elt.scope = P.top_scope;
} else {
// type name
// (ParseType() (via TryType()) checks for forward types and complains,
// so call ParseTypeName() directly)
// we can only have a foward type here if we refer to the name of a
// yet incomplete type (i.e. if we are in the middle of a type's declaration)
elt = P.ParseTypeName();
}
// collect uses of pointer types referring to forward types
if elt.form == Type.FORWARD {
P.forward_types.AddTyp(typ);
// collect uses of pointer types referring to forward types
if elt.form == Type.FORWARD {
P.forward_types.AddTyp(typ);
}
} else {
elt = P.ParseType();
}
} else {
elt = P.ParseType();
}
......@@ -1556,22 +1601,10 @@ func (P *Parser) ParseCase() {
}
func (P *Parser) ParseCaseList() {
P.Trace("CaseList");
P.ParseCase();
for P.tok == Scanner.CASE || P.tok == Scanner.DEFAULT {
P.ParseCase();
}
P.Ecart();
}
func (P *Parser) ParseCaseClause() {
P.Trace("CaseClause");
P.ParseCaseList();
P.ParseCase();
if P.tok != Scanner.FALLTHROUGH && P.tok != Scanner.RBRACE {
P.ParseStatementList();
P.Optional(Scanner.SEMICOLON);
......@@ -1796,19 +1829,35 @@ func (P *Parser) ParseConstSpec(exported bool) {
func (P *Parser) ParseTypeSpec(exported bool) {
P.Trace("TypeSpec");
// Immediately after declaration of the type name, the type is
// considered forward-declared. It may be referred to from inside
// the type specification only via a pointer type.
typ := Globals.NewType(Type.FORWARD);
typ.scope = P.top_scope; // not really needed here, but for consistency
var typ *Globals.Type;
pos, ident := P.ParseIdent();
obj := Globals.NewObject(pos, Object.TYPE, ident);
obj.exported = exported;
obj.typ = typ;
typ.obj = obj; // primary type object
P.Declare(obj);
obj := P.Lookup(ident);
if !P.comp.flags.sixg && obj != nil {
if obj.typ.form == Type.FORWARD {
// imported forward-declared type
if !exported {
panic "foo";
}
} else {
panic "bar";
}
} else {
// Immediately after declaration of the type name, the type is
// considered forward-declared. It may be referred to from inside
// the type specification only via a pointer type.
typ = Globals.NewType(Type.FORWARD);
typ.scope = P.top_scope; // not really needed here, but for consistency
obj = Globals.NewObject(pos, Object.TYPE, ident);
obj.exported = exported;
obj.typ = typ;
typ.obj = obj; // primary type object
P.Declare(obj);
}
// If the next token is an identifier and we have a legal program,
// it must be a typename. In that case this declaration introduces
// an alias type.
......
......@@ -4,6 +4,9 @@
package Platform
import Utils "utils"
// ----------------------------------------------------------------------------
// Environment
......@@ -54,7 +57,14 @@ export func ReadObjectFile(filename string) (data string, ok bool) {
}
export func ReadSourceFile(filename string) (data string, ok bool) {
data, ok = sys.readfile(filename + src_file_ext);
export func ReadSourceFile(name string) (data string, ok bool) {
name = Utils.TrimExt(name, src_file_ext) + src_file_ext;
data, ok = sys.readfile(name);
return data, ok;
}
export func WriteObjectFile(name string, data string) bool {
name = Utils.TrimExt(Utils.BaseName(name), src_file_ext) + obj_file_ext;
return sys.writefile(name, data);
}
......@@ -178,7 +178,15 @@ func (P *Printer) PrintObjectStruct(obj *Globals.Object) {
func (P *Printer) PrintObject(obj *Globals.Object) {
if obj.pnolev > 0 {
print P.comp.pkg_list[obj.pnolev].obj.ident, ".";
pkg := P.comp.pkg_list[obj.pnolev];
if pkg.key == "" {
// forward-declared package
print `"`, pkg.file_name, `"`;
} else {
// imported package
print pkg.obj.ident;
}
print "."
}
print obj.ident;
}
......
......@@ -276,12 +276,11 @@ func (S *Scanner) Next() {
Bit3 = 4;
Bit4 = 3;
// TODO 6g constant evaluation incomplete
T1 = 0x00; // (1 << (Bit1 + 1) - 1) ^ 0xFF; // 0000 0000
Tx = 0x80; // (1 << (Bitx + 1) - 1) ^ 0xFF; // 1000 0000
T2 = 0xC0; // (1 << (Bit2 + 1) - 1) ^ 0xFF; // 1100 0000
T3 = 0xE0; // (1 << (Bit3 + 1) - 1) ^ 0xFF; // 1110 0000
T4 = 0xF0; // (1 << (Bit4 + 1) - 1) ^ 0xFF; // 1111 0000
T1 = (1 << (Bit1 + 1) - 1) ^ 0xFF; // 0000 0000
Tx = (1 << (Bitx + 1) - 1) ^ 0xFF; // 1000 0000
T2 = (1 << (Bit2 + 1) - 1) ^ 0xFF; // 1100 0000
T3 = (1 << (Bit3 + 1) - 1) ^ 0xFF; // 1110 0000
T4 = (1 << (Bit4 + 1) - 1) ^ 0xFF; // 1111 0000
Rune1 = 1 << (Bit1 + 0*Bitx) - 1; // 0000 0000 0111 1111
Rune2 = 1 << (Bit2 + 1*Bitx) - 1; // 0000 0111 1111 1111
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment