Commit bc13a1a3 authored by Robert Griesemer's avatar Robert Griesemer

first primitive cut at resolving missing imports automatically:

if an import file is missing, the corresponding source
is compiled automatically, if found

R=r
OCL=13990
CL=13990
parent 4addd946
...@@ -17,18 +17,25 @@ import Printer "printer" ...@@ -17,18 +17,25 @@ import Printer "printer"
import Verifier "verifier" import Verifier "verifier"
export func Compile(comp *Globals.Compilation, file_name string) { export func Compile(flags *Globals.Flags, filename string) {
src, ok := sys.readfile(file_name); // setup compilation
comp := new(Globals.Compilation);
comp.flags = flags;
comp.Compile = &Compile;
src, ok := sys.readfile(filename);
if !ok { if !ok {
print "cannot open ", file_name, "\n" print "cannot open ", filename, "\n"
return; return;
} }
print filename, "\n";
scanner := new(Scanner.Scanner); scanner := new(Scanner.Scanner);
scanner.Open(file_name, src); scanner.Open(filename, src);
var tstream *chan *Scanner.Token; var tstream *chan *Scanner.Token;
if comp.flags.pscan { if comp.flags.token_chan {
tstream = new(chan *Scanner.Token, 100); tstream = new(chan *Scanner.Token, 100);
go scanner.Server(tstream); go scanner.Server(tstream);
} }
...@@ -41,15 +48,15 @@ export func Compile(comp *Globals.Compilation, file_name string) { ...@@ -41,15 +48,15 @@ export func Compile(comp *Globals.Compilation, file_name string) {
return; return;
} }
if !comp.flags.semantic_checks { if !comp.flags.ast {
return; return;
} }
Verifier.Verify(comp); Verifier.Verify(comp);
if comp.flags.print_export { if comp.flags.print_interface {
Printer.PrintObject(comp, comp.pkg_list[0].obj, false); Printer.PrintObject(comp, comp.pkg_list[0].obj, false);
} }
Export.Export(comp, file_name); Export.Export(comp, filename);
} }
...@@ -247,6 +247,12 @@ func (E *Exporter) Export(comp* Globals.Compilation, file_name string) { ...@@ -247,6 +247,12 @@ func (E *Exporter) Export(comp* Globals.Compilation, file_name string) {
print "exporting to ", file_name, "\n"; print "exporting to ", file_name, "\n";
} }
// write magic bits
magic := Globals.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". // Predeclared types are "pre-exported".
// TODO run the loop below only in debug mode // TODO run the loop below only in debug mode
{ i := 0; { i := 0;
...@@ -279,5 +285,5 @@ func (E *Exporter) Export(comp* Globals.Compilation, file_name string) { ...@@ -279,5 +285,5 @@ func (E *Exporter) Export(comp* Globals.Compilation, file_name string) {
export func Export(comp* Globals.Compilation, pkg_name string) { export func Export(comp* Globals.Compilation, pkg_name string) {
var E Exporter; var E Exporter;
(&E).Export(comp, Utils.FixExt(Utils.BaseName(pkg_name))); (&E).Export(comp, Utils.TrimExt(Utils.BaseName(pkg_name), Globals.src_file_ext) + Globals.obj_file_ext);
} }
...@@ -5,6 +5,18 @@ ...@@ -5,6 +5,18 @@
package Globals package Globals
// ----------------------------------------------------------------------------
// Constants
export const (
MAGIC_obj_file = "/*go.7*/"; // anything, really
src_file_ext = ".go";
obj_file_ext = ".7";
)
// ----------------------------------------------------------------------------
// The following types should really be in their respective files // The following types should really be in their respective files
// (object.go, type.go, scope.go, package.go, compilation.go, etc.) but // (object.go, type.go, scope.go, package.go, compilation.go, etc.) but
// they refer to each other and we don't know how to handle forward // they refer to each other and we don't know how to handle forward
...@@ -60,16 +72,28 @@ export type Scope struct { ...@@ -60,16 +72,28 @@ export type Scope struct {
export type Flags struct { export type Flags struct {
debug bool; debug bool;
print_export bool; object_filename string;
semantic_checks bool; update_packages bool;
verbose int; print_interface bool;
sixg bool; // 6g compatibility verbosity uint;
pscan bool; // parallel scanning using a token channel sixg bool;
scan bool;
parse bool;
ast bool;
deps bool;
token_chan bool;
} }
export type Compilation struct { export type Compilation struct {
// envionment
flags *Flags; flags *Flags;
Error *func(comp *Compilation); // TODO complete this
Import *func(comp *Compilation, data string) *Package;
Export *func(comp *Compilation) string;
Compile *func(flags *Flags, filename string); // TODO remove this eventually
// TODO use open arrays eventually // TODO use open arrays eventually
pkg_list [256] *Package; // pkg_list[0] is the current package pkg_list [256] *Package; // pkg_list[0] is the current package
pkg_ref int; pkg_ref int;
...@@ -150,13 +174,6 @@ export func NewScope(parent *Scope) *Scope { ...@@ -150,13 +174,6 @@ export func NewScope(parent *Scope) *Scope {
} }
export func NewCompilation(flags *Flags) *Compilation {
comp := new(Compilation);
comp.flags = flags;
return comp;
}
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// Object methods // Object methods
......
...@@ -9,49 +9,80 @@ import Globals "globals" ...@@ -9,49 +9,80 @@ import Globals "globals"
import Compilation "compilation" import Compilation "compilation"
// For now we are not using the flags package to minimize
// external dependencies, and because the requirements are
// very minimal at this point.
func PrintHelp() { func PrintHelp() {
print "go in go (", Build.time, ")\n"; print
print "usage:\n"; "go (" + Build.time + ")\n" +
print " go { flag | file }\n"; "usage:\n" +
print " -d print debug information\n"; " go { flag } { file }\n" +
print " -p print export\n"; " -d debug mode, additional self tests and prints\n" +
print " -s enable semantic checks\n"; " -o filename explicit object filename\n" +
print " -v verbose mode\n"; " -r recursively update imported packages in current directory\n" +
print " -vv very verbose mode\n"; " -p print package interface\n" +
print " -6g 6g compatibility mode\n"; " -v [0 .. 3] verbosity level\n" +
print " -pscan scan and parse in parallel (use token channel)\n"; " -6g 6g compatibility mode\n" +
" -scan scan only, print tokens\n" +
" -parse parse only, print productions\n" +
" -ast analyse only, print ast\n" +
" -deps print package dependencies\n" +
" -token_chan use token channel to scan and parse in parallel\n";
}
var argno int = 1;
func Next() string {
arg := "";
if argno < sys.argc() {
arg = sys.argv(argno);
argno++;
}
return arg;
} }
func main() { func main() {
if sys.argc() <= 1 { arg := Next();
if arg == "" {
PrintHelp(); PrintHelp();
sys.exit(1); return;
} }
// collect flags and files // collect flags and files
flags := new(Globals.Flags); flags := new(Globals.Flags);
files := Globals.NewList(); files := Globals.NewList();
for i := 1; i < sys.argc(); i++ { for arg != "" {
switch arg := sys.argv(i); arg { switch arg {
case "-d": flags.debug = true; case "-d": flags.debug = true;
case "-p": flags.print_export = true; case "-o": flags.object_filename = Next();
case "-s": flags.semantic_checks = true; print "note: -o flag ignored at the moment\n";
case "-v": flags.verbose = 1; case "-r": flags.update_packages = true;
case "-vv": flags.verbose = 2; case "-p": flags.print_interface = true;
case "-v":
arg = Next();
switch arg {
case "0", "1", "2", "3":
flags.verbosity = uint(arg[0] - '0');
default:
// anything else is considered the next argument
flags.verbosity = 1;
continue;
}
case "-6g": flags.sixg = true; case "-6g": flags.sixg = true;
case "-pscan": flags.pscan = true; case "-scan": flags.scan = true;
print "note: -scan flag ignored at the moment\n";
case "-parse": flags.parse = true;
print "note: -parse flag ignored at the moment\n";
case "-ast": flags.ast = true;
case "-deps": flags.deps = true;
print "note: -deps flag ignored at the moment\n";
case "-token_chan": flags.token_chan = true;
default: files.AddStr(arg); default: files.AddStr(arg);
} }
arg = Next();
} }
// compile files // compile files
for p := files.first; p != nil; p = p.next { for p := files.first; p != nil; p = p.next {
comp := Globals.NewCompilation(flags); Compilation.Compile(flags, p.str);
Compilation.Compile(comp, p.str);
} }
} }
...@@ -264,6 +264,66 @@ func (I *Importer) ReadObject() *Globals.Object { ...@@ -264,6 +264,66 @@ func (I *Importer) ReadObject() *Globals.Object {
} }
func ReadObjectFile(filename string) (data string, ok bool) {
data, ok = sys.readfile(filename + Globals.obj_file_ext);
magic := Globals.MAGIC_obj_file; // TODO remove once len(constant) works
if ok && len(data) >= len(magic) && data[0 : len(magic)] == magic {
return data, ok;
}
return "", false;
}
func ReadSourceFile(filename string) (data string, ok bool) {
data, ok = sys.readfile(filename + Globals.src_file_ext);
return data, ok;
}
func ReadImport(comp* Globals.Compilation, filename string, update bool) (data string, ok bool) {
if filename == "" {
panic "illegal package file name";
}
// see if it just works
data, ok = ReadObjectFile(filename);
if ok {
return data, ok;
}
if filename[0] == '/' {
// absolute path
panic `don't know how to handle absolute import file path "` + filename + `"`;
}
// relative path
// try relative to the $GOROOT/pkg directory
std_filename := Utils.GOROOT + "/pkg/" + filename;
data, ok = ReadObjectFile(std_filename);
if ok {
return data, ok;
}
if !update {
return "", false;
}
// TODO BIG HACK - fix this!
// look for a src file
// see if it just works
data, ok = ReadSourceFile(filename);
if ok {
comp.Compile(comp.flags, filename + Globals.src_file_ext);
data, ok = ReadImport(comp, filename, false);
if ok {
return data, ok;
}
}
return "", false;
}
func (I *Importer) Import(comp* Globals.Compilation, file_name string) *Globals.Package { func (I *Importer) Import(comp* Globals.Compilation, file_name string) *Globals.Package {
I.comp = comp; I.comp = comp;
I.debug = comp.flags.debug; I.debug = comp.flags.debug;
...@@ -276,7 +336,8 @@ func (I *Importer) Import(comp* Globals.Compilation, file_name string) *Globals. ...@@ -276,7 +336,8 @@ func (I *Importer) Import(comp* Globals.Compilation, file_name string) *Globals.
print "importing from ", file_name, "\n"; print "importing from ", file_name, "\n";
} }
buf, ok := sys.readfile(file_name); // read file and check magic bits
buf, ok := ReadImport(comp, file_name, comp.flags.update_packages);
if !ok { if !ok {
return nil; return nil;
} }
...@@ -305,5 +366,5 @@ func (I *Importer) Import(comp* Globals.Compilation, file_name string) *Globals. ...@@ -305,5 +366,5 @@ func (I *Importer) Import(comp* Globals.Compilation, file_name string) *Globals.
export func Import(comp* Globals.Compilation, pkg_name string) *Globals.Package { export func Import(comp* Globals.Compilation, pkg_name string) *Globals.Package {
var I Importer; var I Importer;
return (&I).Import(comp, Utils.FixExt(pkg_name)); return (&I).Import(comp, pkg_name);
} }
...@@ -17,7 +17,7 @@ import AST "ast" ...@@ -17,7 +17,7 @@ import AST "ast"
export type Parser struct { export type Parser struct {
comp *Globals.Compilation; comp *Globals.Compilation;
semantic_checks bool; semantic_checks bool;
verbose, indent int; verbose, indent uint;
S *Scanner.Scanner; S *Scanner.Scanner;
C *chan *Scanner.Token; C *chan *Scanner.Token;
...@@ -78,8 +78,8 @@ func (P *Parser) Next() { ...@@ -78,8 +78,8 @@ func (P *Parser) Next() {
func (P *Parser) Open(comp *Globals.Compilation, S *Scanner.Scanner, C *chan *Scanner.Token) { func (P *Parser) Open(comp *Globals.Compilation, S *Scanner.Scanner, C *chan *Scanner.Token) {
P.comp = comp; P.comp = comp;
P.semantic_checks = comp.flags.semantic_checks; P.semantic_checks = comp.flags.ast;
P.verbose = comp.flags.verbose; P.verbose = comp.flags.verbosity;
P.indent = 0; P.indent = 0;
P.S = S; P.S = S;
P.C = C; P.C = C;
......
...@@ -223,7 +223,7 @@ func init() { ...@@ -223,7 +223,7 @@ func init() {
} }
// Provide column information in error messages for gri only... // Provide column information in error messages for gri only...
VerboseMsgs = Utils.GetEnv("USER") == "gri"; VerboseMsgs = Utils.USER == "gri";
} }
......
...@@ -5,6 +5,34 @@ ...@@ -5,6 +5,34 @@
package Utils package Utils
// Environment
export var
GOARCH,
GOOS,
GOROOT,
USER string;
func GetEnv(key string) string {
n := len(key);
for i := 0; i < sys.envc(); i++ {
v := sys.envv(i);
if v[0 : n] == key {
return v[n + 1 : len(v)]; // +1: trim "="
}
}
return "";
}
func init() {
GOARCH = GetEnv("GOARCH");
GOOS = GetEnv("GOOS");
GOROOT = GetEnv("GOROOT");
USER = GetEnv("USER");
}
export func BaseName(s string) string { export func BaseName(s string) string {
// TODO this is not correct for non-ASCII strings! // TODO this is not correct for non-ASCII strings!
i := len(s) - 1; i := len(s) - 1;
...@@ -18,22 +46,10 @@ export func BaseName(s string) string { ...@@ -18,22 +46,10 @@ export func BaseName(s string) string {
} }
export func FixExt(s string) string { export func TrimExt(s, ext string) string {
i := len(s) - 3; // 3 == len(".go"); i := len(s) - len(ext);
if i >= 0 && s[i : len(s)] == ".go" { if i >= 0 && s[i : len(s)] == ext {
s = s[0 : i]; s = s[0 : i];
} }
return s + ".7"; return s;
}
export func GetEnv(key string) string {
n := len(key);
for i := 0; i < sys.envc(); i++ {
v := sys.envv(i);
if v[0 : n] == key {
return v[n + 1 : len(v)]; // +1: skip "="
}
}
return "";
} }
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