compilation.go 3.89 KB
Newer Older
Robert Griesemer's avatar
Robert Griesemer committed
1 2 3 4 5 6
// 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

7
import "array"
8 9
import OS "os"
import Platform "platform"
Robert Griesemer's avatar
Robert Griesemer committed
10 11 12 13 14
import Scanner "scanner"
import Parser "parser"
import AST "ast"


15 16 17 18 19 20
func assert(b bool) {
	if !b {
		panic("assertion failed");
	}
}

Robert Griesemer's avatar
Robert Griesemer committed
21 22 23 24 25 26 27 28 29 30 31

export type Flags struct {
	verbose bool;
	sixg bool;
	deps bool;
	columns bool;
	testmode bool;
	tokenchan bool;
}


32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113
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");
}


114 115 116 117 118 119
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;
	}
120 121 122
	
	var err ErrorHandler;
	err.Init(src_file, src, flags.columns);
Robert Griesemer's avatar
Robert Griesemer committed
123 124

	var scanner Scanner.Scanner;
125
	scanner.Init(&err, src, true, flags.testmode);
Robert Griesemer's avatar
Robert Griesemer committed
126 127 128 129 130 131 132

	var tstream *<-chan *Scanner.Token;
	if flags.tokenchan {
		tstream = scanner.TokenStream();
	}

	var parser Parser.Parser;
133 134 135
	parser.Open(flags.verbose, flags.sixg, flags.deps, &scanner, tstream);

	prog := parser.ParseProgram();
136
	return prog, err.nerrors;
137 138
}

Robert Griesemer's avatar
Robert Griesemer committed
139

140 141 142 143 144 145 146 147 148 149
func FileExists(name string) bool {
	fd, err := OS.Open(name, OS.O_RDONLY, 0);
	if err == nil {
		fd.Close();
		return true;
	}
	return false;
}


150
func AddDeps(globalset *map [string] bool, wset *array.Array, src_file string, flags *Flags) {
151 152 153 154 155 156 157 158 159
	dummy, found := globalset[src_file];
	if !found {
		globalset[src_file] = true;
		
		prog, nerrors := Compile(src_file, flags);
		if nerrors > 0 {
			return;
		}
		
160
		nimports := prog.decls.Len();
161 162 163 164 165
		if nimports > 0 {
			print(src_file, ".6:\t");
			
			localset := new(map [string] bool);
			for i := 0; i < nimports; i++ {
166
				decl := prog.decls.At(i).(*AST.Decl);
167 168 169 170 171 172 173 174 175
				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") {
176
						wset.Push(src);
177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195
						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);
196 197 198
	wset := array.New(0);
	wset.Push(src_file);
	for wset.Len() > 0 {
199 200
		AddDeps(globalset, wset, wset.Pop().(string), flags);
	}
Robert Griesemer's avatar
Robert Griesemer committed
201
}