// 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" import OS "os" import Platform "platform" import Scanner "scanner" import Parser "parser" import AST "ast" func assert(b bool) { if !b { panic("assertion failed"); } } export 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, 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 { 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"); } export 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(); 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 := new(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.s; 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"); } } } export func ComputeDeps(src_file string, flags *Flags) { globalset := new(map [string] bool); wset := array.New(0); wset.Push(src_file); for wset.Len() > 0 { AddDeps(globalset, wset, wset.Pop().(string), flags); } }