type errorHandler struct {
filename string;
- src []byte;
columns bool;
errline int;
errors vector.Vector;
}
-func (h *errorHandler) Init(filename string, src []byte, columns bool) {
+func (h *errorHandler) Init(filename string, columns bool) {
h.filename = filename;
- h.src = src;
h.columns = columns;
h.errors.Init(0);
}
}
-func Compile(src_file string, flags *Flags) (*ast.Package, ErrorList) {
- src, ok := Platform.ReadSourceFile(src_file);
- if !ok {
- print("cannot open ", src_file, "\n");
+func Compile(filename string, flags *Flags) (*ast.Package, ErrorList) {
+ src, os_err := os.Open(filename, os.O_RDONLY, 0);
+ defer src.Close();
+ if os_err != nil {
+ fmt.Printf("cannot open %s (%s)\n", filename, os_err.String());
return nil, nil;
}
var err errorHandler;
- err.Init(src_file, src, flags.Columns);
+ err.Init(filename, flags.Columns);
- var scanner scanner.Scanner;
- scanner.Init(src, &err, true);
-
- mode := uint(0);
+ mode := parser.ParseComments;
if flags.Verbose {
mode |= parser.Trace;
}
- prog, nerrs := parser.Parse(&scanner, &err, mode);
+ prog, ok2 := parser.Parse(src, &err, mode);
- if err.errors.Len() == 0 {
+ if ok2 {
TypeChecker.CheckProgram(&err, prog);
}
package parser
import (
+ "ast";
"fmt";
- "vector";
+ "io";
+ "scanner";
"token";
- "ast";
+ "vector";
)
-// An implementation of a Scanner must be provided to the Parser.
-// The parser calls Scan() repeatedly until token.EOF is returned.
-// Scan must return the current token position pos, the token value
-// tok, and the corresponding token literal string lit; lit can be
-// undefined/nil unless the token is a literal (tok.IsLiteral() == true).
-//
-type Scanner interface {
- Scan() (pos token.Position, tok token.Token, lit []byte);
-}
-
-
// An implementation of an ErrorHandler may be provided to the parser.
// If a syntax error is encountered and a handler was installed, Error
// is called with a position and an error message. The position points
// The parser structure holds the parser's internal state.
type parser struct {
- scanner Scanner;
+ scanner scanner.Scanner;
err ErrorHandler; // nil if no handler installed
errorCount int;
". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . "
". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ";
const n = uint(len(dots));
-
fmt.Printf("%5d:%3d: ", p.pos.Line, p.pos.Column);
i := 2*p.indent;
for ; i > n; i -= n {
- fmt.Print(dots[0 : i%n]);
+ fmt.Print(dots);
}
fmt.Print(dots[0 : i]);
fmt.Println(a);
// ----------------------------------------------------------------------------
// Packages
-// A set of flags (or 0) must be provided via the mode parameter to
-// the Parse function. They control the amount of source code parsed
-// and other optional parser functionality.
+// The mode parameter to the Parse function is a set of flags (or 0).
+// They control the amount of source code parsed and other optional
+// parser functionality.
//
const (
- PackageClauseOnly = 1 << iota; // parsing stops after package clause
+ PackageClauseOnly uint = 1 << iota; // parsing stops after package clause
ImportsOnly; // parsing stops after import declarations
+ ParseComments; // parse comments and add them to AST
Trace; // print a trace of parsed productions
)
// ----------------------------------------------------------------------------
// Parsing of entire programs.
-// Parse invokes the Go parser. It calls the scanner's Scan method repeatedly
-// to obtain a token sequence which is parsed according to Go syntax. If an
-// error handler is provided (err != nil), it is invoked for each syntax error
-// encountered.
+func readSource(src interface{}, err ErrorHandler) []byte {
+ errmsg := "could not read input src";
+
+ switch s := src.(type) {
+ case string:
+ return io.StringBytes(s);
+ case []byte:
+ return s;
+ case *io.ByteBuffer:
+ // is io.Read, but src is already available in []byte form
+ if s != nil {
+ return s.Data();
+ }
+ case io.Read:
+ var buf io.ByteBuffer;
+ n, os_err := io.Copy(s, &buf);
+ if os_err == nil {
+ return buf.Data();
+ }
+ errmsg = os_err.String();
+ }
+
+ if err != nil {
+ err.Error(noPos, errmsg);
+ }
+ return nil;
+}
+
+
+// Parse parses a Go program.
//
-// Parse returns an AST and the number of syntax errors encountered. If the
-// error count is 0, the result is the correct AST for the token sequence
-// returned by the scanner (*). If the error count is > 0, the AST may only
-// be constructed partially, with ast.BadX nodes representing the fragments
-// of source code that contained syntax errors.
+// The program source src may be provided in a variety of formats. At the
+// moment the following types are supported: string, []byte, and io.Read.
//
-// The mode parameter controls the amount of source text parsed and other
-// optional parser functionality.
+// The ErrorHandler err, if not nil, is invoked if src cannot be read and
+// for each syntax error found. The mode parameter controls the amount of
+// source text parsed and other optional parser functionality.
//
-// (*) Note that a scanner may find lexical syntax errors but still return
-// a legal token sequence. To be sure there are no syntax errors in the
-// source (and not just the token sequence corresponding to the source)
-// both the parser and scanner error count must be 0.
+// Parse returns an AST and the boolean value true if no errors occured;
+// it returns a partial AST (or nil if the source couldn't be read) and
+// the boolean value false to indicate failure.
+//
+// If syntax errors were found, the AST may only be constructed partially,
+// with ast.BadX nodes representing the fragments of erroneous source code.
//
-func Parse(scanner Scanner, err ErrorHandler, mode uint) (*ast.Package, int) {
+func Parse(src interface{}, err ErrorHandler, mode uint) (*ast.Package, bool) {
+ data := readSource(src, err);
+
// initialize parser state
var p parser;
- p.scanner = scanner;
+ p.scanner.Init(data, err, mode & ParseComments != 0);
p.err = err;
p.mode = mode;
p.trace = mode & Trace != 0; // for convenience (p.trace is used frequently)
p.next();
// parse program
- pak := p.parsePackage();
- return pak, p.errorCount;
+ prog := p.parsePackage();
+ return prog, p.scanner.ErrorCount == 0 && p.errorCount == 0;
}