mirror of
				https://github.com/golang/go.git
				synced 2025-10-31 16:50:58 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			211 lines
		
	
	
	
		
			4 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			211 lines
		
	
	
	
		
			4 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| // 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);
 | |
| 	}
 | |
| }
 | 
