| // Copyright 2009 The Go Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| package Compilation |
| |
| import ( |
| "array"; |
| "utf8"; |
| OS "os"; |
| Platform "platform"; |
| Scanner "scanner"; |
| Parser "parser"; |
| AST "ast"; |
| TypeChecker "typechecker"; |
| ) |
| |
| |
| func assert(b bool) { |
| if !b { |
| panic("assertion failed"); |
| } |
| } |
| |
| |
| type Flags struct { |
| Verbose bool; |
| Sixg bool; |
| Deps bool; |
| Columns bool; |
| Testmode bool; |
| Tokenchan bool; |
| } |
| |
| |
| type errorHandler struct { |
| filename string; |
| src string; |
| nerrors int; |
| nwarnings int; |
| errpos int; |
| columns bool; |
| } |
| |
| |
| func (h *errorHandler) Init(filename, src string, columns bool) { |
| h.filename = filename; |
| h.src = src; |
| h.nerrors = 0; |
| h.nwarnings = 0; |
| h.errpos = 0; |
| h.columns = columns; |
| } |
| |
| |
| // Compute (line, column) information for a given source position. |
| func (h *errorHandler) LineCol(pos int) (line, col int) { |
| line = 1; |
| lpos := 0; |
| |
| src := h.src; |
| if pos > len(src) { |
| pos = len(src); |
| } |
| |
| for i := 0; i < pos; i++ { |
| if src[i] == '\n' { |
| line++; |
| lpos = i; |
| } |
| } |
| |
| return line, utf8.RuneCountInString(src, lpos, pos - lpos); |
| } |
| |
| |
| func (h *errorHandler) ErrorMsg(pos int, msg string) { |
| print(h.filename, ":"); |
| if pos >= 0 { |
| // print position |
| line, col := h.LineCol(pos); |
| print(line, ":"); |
| if h.columns { |
| print(col, ":"); |
| } |
| } |
| print(" ", msg, "\n"); |
| |
| h.nerrors++; |
| h.errpos = pos; |
| |
| if h.nerrors >= 10 { |
| // TODO enable when done with name convention |
| //sys.Exit(1); |
| } |
| } |
| |
| |
| func (h *errorHandler) Error(pos int, msg string) { |
| // only report errors that are sufficiently far away from the previous error |
| // in the hope to avoid most follow-up errors |
| const errdist = 20; |
| delta := pos - h.errpos; // may be negative! |
| if delta < 0 { |
| delta = -delta; |
| } |
| |
| if delta > errdist || h.nerrors == 0 /* always report first error */ { |
| h.ErrorMsg(pos, msg); |
| } |
| } |
| |
| |
| func (h *errorHandler) Warning(pos int, msg string) { |
| panic("UNIMPLEMENTED"); |
| } |
| |
| |
| func Compile(src_file string, flags *Flags) (*AST.Program, int) { |
| src, ok := Platform.ReadSourceFile(src_file); |
| if !ok { |
| print("cannot open ", src_file, "\n"); |
| return nil, 1; |
| } |
| |
| var err errorHandler; |
| err.Init(src_file, src, flags.Columns); |
| |
| var scanner Scanner.Scanner; |
| scanner.Init(&err, src, true, flags.Testmode); |
| |
| var tstream <-chan *Scanner.Token; |
| if flags.Tokenchan { |
| tstream = scanner.TokenStream(); |
| } |
| |
| var parser Parser.Parser; |
| parser.Open(flags.Verbose, flags.Sixg, flags.Deps, &scanner, tstream); |
| |
| prog := parser.ParseProgram(); |
| |
| if err.nerrors == 0 { |
| TypeChecker.CheckProgram(&err, prog); |
| } |
| |
| return prog, err.nerrors; |
| } |
| |
| |
| func fileExists(name string) bool { |
| fd, err := OS.Open(name, OS.O_RDONLY, 0); |
| if err == nil { |
| fd.Close(); |
| return true; |
| } |
| return false; |
| } |
| |
| |
| func addDeps(globalset map [string] bool, wset *array.Array, src_file string, flags *Flags) { |
| dummy, found := globalset[src_file]; |
| if !found { |
| globalset[src_file] = true; |
| |
| prog, nerrors := Compile(src_file, flags); |
| if nerrors > 0 { |
| return; |
| } |
| |
| nimports := prog.Decls.Len(); |
| if nimports > 0 { |
| print(src_file, ".6:\t"); |
| |
| localset := make(map [string] bool); |
| for i := 0; i < nimports; i++ { |
| decl := prog.Decls.At(i).(*AST.Decl); |
| assert(decl.Tok == Scanner.IMPORT && decl.Val.Tok == Scanner.STRING); |
| src := decl.Val.Obj.Ident; |
| src = src[1 : len(src) - 1]; // strip "'s |
| |
| // ignore files when they are seen a 2nd time |
| dummy, found := localset[src]; |
| if !found { |
| localset[src] = true; |
| if fileExists(src + ".go") { |
| wset.Push(src); |
| print(" ", src, ".6"); |
| } else if |
| fileExists(Platform.GOROOT + "/pkg/" + src + ".6") || |
| fileExists(Platform.GOROOT + "/pkg/" + src + ".a") { |
| |
| } else { |
| // TODO should collect these and print later |
| //print("missing file: ", src, "\n"); |
| } |
| } |
| } |
| print("\n\n"); |
| } |
| } |
| } |
| |
| |
| func ComputeDeps(src_file string, flags *Flags) { |
| globalset := make(map [string] bool); |
| wset := array.New(0); |
| wset.Push(src_file); |
| for wset.Len() > 0 { |
| addDeps(globalset, wset, wset.Pop().(string), flags); |
| } |
| } |