- preparation for setting up types

- moved Object, Type, Scope  out of AST into symboltable
  - moved universe into symboltable
  - removed dead code
- fixed dependency computation (pretty -d filename.go)
- lots of cleanups
- removed tocken channel connection between parser and scanner
  (was cute, but not really needed)

R=r
OCL=24545
CL=24545
This commit is contained in:
Robert Griesemer 2009-02-06 11:10:25 -08:00
parent 5e5476c2fe
commit 187cf78a7c
10 changed files with 496 additions and 428 deletions

View File

@ -29,19 +29,19 @@ pretty.6: platform.6 printer.6 compilation.6
compilation.6: platform.6 scanner.6 parser.6 ast.6 typechecker.6 compilation.6: platform.6 scanner.6 parser.6 ast.6 typechecker.6
ast.6: scanner.6 typechecker.6: ast.6 scanner.6
scanner.6: utils.6 scanner.6: utils.6
parser.6: scanner.6 ast.6 ast.6: scanner.6 symboltable.6
symboltable.6:
parser.6: scanner.6 ast.6 symboltable.6
platform.6: utils.6 platform.6: utils.6
printer.6: scanner.6 ast.6 utils.6 printer.6: utils.6 scanner.6 ast.6 symboltable.6
typechecker.6: ast.6 universe.6
universe.6: ast.6
%.6: %.go %.6: %.go
$(G) $(F) $< $(G) $(F) $<

View File

@ -6,16 +6,12 @@ package AST
import ( import (
"array"; "array";
"utf8";
"unicode";
Scanner "scanner"; Scanner "scanner";
SymbolTable "symboltable";
) )
type ( type (
Object struct;
Type struct;
Block struct; Block struct;
Expr interface; Expr interface;
Decl struct; Decl struct;
@ -32,91 +28,6 @@ func assert(pred bool) {
} }
// ----------------------------------------------------------------------------
// Objects
// Object represents a language object, such as a constant, variable, type, etc.
const /* kind */ (
BADOBJ = iota; // error handling
NONE; // kind unknown
CONST; TYPE; VAR; FIELD; FUNC; BUILTIN; PACKAGE; LABEL;
END; // end of scope (import/export only)
)
func KindStr(kind int) string {
switch kind {
case BADOBJ: return "BADOBJ";
case NONE: return "NONE";
case CONST: return "CONST";
case TYPE: return "TYPE";
case VAR: return "VAR";
case FIELD: return "FIELD";
case FUNC: return "FUNC";
case BUILTIN: return "BUILTIN";
case PACKAGE: return "PACKAGE";
case LABEL: return "LABEL";
case END: return "END";
}
return "<unknown Object kind>";
}
type Object struct {
Id int; // unique id
Pos int; // source position (< 0 if unknown position)
Kind int; // object kind
Ident string;
Typ *Type; // nil for packages
Pnolev int; // >= 0: package no., <= 0: function nesting level, 0: global level
// attached values
Body *Block; // function body
}
func (obj *Object) IsExported() bool {
switch obj.Kind {
case NONE /* FUNC for now */, CONST, TYPE, VAR, FUNC:
ch, size := utf8.DecodeRuneInString(obj.Ident, 0);
return unicode.IsUpper(ch);
}
return false;
}
func (obj* Object) String() string {
if obj != nil {
return
"Object(" +
KindStr(obj.Kind) + ", " +
obj.Ident +
")";
}
return "nil";
}
var Universe_void_typ *Type // initialized by Universe to Universe.void_typ
var objectId int;
func NewObject(pos, kind int, ident string) *Object {
obj := new(Object);
obj.Id = objectId;
objectId++;
obj.Pos = pos;
obj.Kind = kind;
obj.Ident = ident;
obj.Typ = Universe_void_typ; // TODO would it be better to use nil instead?
obj.Pnolev = 0;
return obj;
}
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// All nodes have a source position and a token. // All nodes have a source position and a token.
@ -126,113 +37,20 @@ type Node struct {
} }
// ----------------------------------------------------------------------------
// Scopes
type Scope struct {
Parent *Scope;
entries map[string] *Object;
}
func NewScope(parent *Scope) *Scope {
scope := new(Scope);
scope.Parent = parent;
scope.entries = make(map[string]*Object, 8);
return scope;
}
func (scope *Scope) LookupLocal(ident string) *Object {
obj, found := scope.entries[ident];
if found {
return obj;
}
return nil;
}
func (scope *Scope) Lookup(ident string) *Object {
for scope != nil {
obj := scope.LookupLocal(ident);
if obj != nil {
return obj;
}
scope = scope.Parent;
}
return nil;
}
func (scope *Scope) add(obj* Object) {
scope.entries[obj.Ident] = obj;
}
func (scope *Scope) Insert(obj *Object) {
if scope.LookupLocal(obj.Ident) != nil {
panic("obj already inserted");
}
scope.add(obj);
}
func (scope *Scope) InsertImport(obj *Object) *Object {
p := scope.LookupLocal(obj.Ident);
if p == nil {
scope.add(obj);
p = obj;
}
return p;
}
func (scope *Scope) Print() {
print("scope {");
for key := range scope.entries {
print("\n ", key);
}
print("\n}\n");
}
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// Types // Types
const /* form */ ( const /* form */ (
// internal types
// We should never see one of these.
UNDEF = iota;
// VOID types are used when we don't have a type. Never exported.
// (exported type forms must be > 0)
VOID;
// BADTYPE types are compatible with any type and don't cause further errors. // BADTYPE types are compatible with any type and don't cause further errors.
// They are introduced only as a result of an error in the source code. A // They are introduced only as a result of an error in the source code. A
// correct program cannot have BAD types. // correct program cannot have BAD types.
BADTYPE; BADTYPE = iota;
// FORWARD types are forward-declared (incomplete) types. They can only
// be used as element types of pointer types and must be resolved before
// their internals are accessible.
FORWARD;
// TUPLE types represent multi-valued result types of functions and
// methods.
TUPLE;
// The type of nil.
NIL;
// A type name // A type name
TYPENAME; TYPENAME;
// basic types
BOOL; UINT; INT; FLOAT; STRING; INTEGER;
// composite types // composite types
ALIAS; ARRAY; STRUCT; INTERFACE; MAP; CHANNEL; FUNCTION; METHOD; POINTER; ARRAY; STRUCT; INTERFACE; MAP; CHANNEL; FUNCTION; POINTER;
// open-ended parameter type // open-ended parameter type
ELLIPSIS ELLIPSIS
@ -241,25 +59,14 @@ const /* form */ (
func FormStr(form int) string { func FormStr(form int) string {
switch form { switch form {
case VOID: return "VOID";
case BADTYPE: return "BADTYPE"; case BADTYPE: return "BADTYPE";
case FORWARD: return "FORWARD";
case TUPLE: return "TUPLE";
case NIL: return "NIL";
case TYPENAME: return "TYPENAME"; case TYPENAME: return "TYPENAME";
case BOOL: return "BOOL";
case UINT: return "UINT";
case INT: return "INT";
case FLOAT: return "FLOAT";
case STRING: return "STRING";
case ALIAS: return "ALIAS";
case ARRAY: return "ARRAY"; case ARRAY: return "ARRAY";
case STRUCT: return "STRUCT"; case STRUCT: return "STRUCT";
case INTERFACE: return "INTERFACE"; case INTERFACE: return "INTERFACE";
case MAP: return "MAP"; case MAP: return "MAP";
case CHANNEL: return "CHANNEL"; case CHANNEL: return "CHANNEL";
case FUNCTION: return "FUNCTION"; case FUNCTION: return "FUNCTION";
case METHOD: return "METHOD";
case POINTER: return "POINTER"; case POINTER: return "POINTER";
case ELLIPSIS: return "ELLIPSIS"; case ELLIPSIS: return "ELLIPSIS";
} }
@ -277,11 +84,9 @@ const /* channel mode */ (
type Type struct { type Type struct {
Id int; // unique id Id int; // unique id
Ref int; // for exporting only: >= 0 means already exported
Form int; // type form Form int; // type form
Size int; // size in bytes Size int; // size in bytes
Obj *Object; // primary type object or nil Scope *SymbolTable.Scope; // locals, fields & methods
Scope *Scope; // locals, fields & methods
// syntactic components // syntactic components
Pos int; // source position (< 0 if unknown position) Pos int; // source position (< 0 if unknown position)
@ -300,7 +105,6 @@ func NewType(pos, form int) *Type {
typ.Id = typeId; typ.Id = typeId;
typeId++; typeId++;
typ.Ref = -1; // not yet exported
typ.Pos = pos; typ.Pos = pos;
typ.Form = form; typ.Form = form;
@ -339,7 +143,7 @@ type (
Ident struct { Ident struct {
Pos_ int; Pos_ int;
Obj *Object; Obj *SymbolTable.Object;
}; };
BinaryExpr struct { BinaryExpr struct {

View File

@ -7,7 +7,8 @@ package Compilation
import ( import (
"array"; "array";
"utf8"; "utf8";
OS "os"; "fmt";
"os";
Platform "platform"; Platform "platform";
Scanner "scanner"; Scanner "scanner";
Parser "parser"; Parser "parser";
@ -29,7 +30,6 @@ type Flags struct {
Deps bool; Deps bool;
Columns bool; Columns bool;
Testmode bool; Testmode bool;
Tokenchan bool;
} }
@ -129,13 +129,8 @@ func Compile(src_file string, flags *Flags) (*AST.Program, int) {
var scanner Scanner.Scanner; var scanner Scanner.Scanner;
scanner.Init(&err, src, true, flags.Testmode); scanner.Init(&err, src, true, flags.Testmode);
var tstream <-chan *Scanner.Token;
if flags.Tokenchan {
tstream = scanner.TokenStream();
}
var parser Parser.Parser; var parser Parser.Parser;
parser.Open(flags.Verbose, flags.Sixg, flags.Deps, &scanner, tstream); parser.Open(flags.Verbose, flags.Sixg, flags.Deps, &scanner);
prog := parser.ParseProgram(); prog := parser.ParseProgram();
@ -148,18 +143,36 @@ func Compile(src_file string, flags *Flags) (*AST.Program, int) {
func fileExists(name string) bool { func fileExists(name string) bool {
fd, err := OS.Open(name, OS.O_RDONLY, 0); fd, err := os.Open(name, os.O_RDONLY, 0);
if err == nil { defer fd.Close();
fd.Close(); return err == nil;
return true; }
func printDep(localset map [string] bool, wset *array.Array, decl *AST.Decl) {
src := decl.Val.(*AST.BasicLit).Val;
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);
fmt.Printf(" %s.6", src);
} 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");
}
} }
return false;
} }
func addDeps(globalset map [string] bool, wset *array.Array, src_file string, flags *Flags) { func addDeps(globalset map [string] bool, wset *array.Array, src_file string, flags *Flags) {
panic();
/*
dummy, found := globalset[src_file]; dummy, found := globalset[src_file];
if !found { if !found {
globalset[src_file] = true; globalset[src_file] = true;
@ -171,40 +184,34 @@ func addDeps(globalset map [string] bool, wset *array.Array, src_file string, fl
nimports := prog.Decls.Len(); nimports := prog.Decls.Len();
if nimports > 0 { if nimports > 0 {
print(src_file, ".6:\t"); fmt.Printf("%s.6:\t", src_file);
localset := make(map [string] bool); localset := make(map [string] bool);
for i := 0; i < nimports; i++ { for i := 0; i < nimports; i++ {
decl := prog.Decls.At(i).(*AST.Decl); decl := prog.Decls.At(i).(*AST.Decl);
assert(decl.Tok == Scanner.IMPORT && decl.Val.Tok == Scanner.STRING); assert(decl.Tok == Scanner.IMPORT);
src := decl.Val.Obj.Ident; if decl.List == nil {
src = src[1 : len(src) - 1]; // strip "'s printDep(localset, wset, decl);
} else {
// ignore files when they are seen a 2nd time for j := 0; j < decl.List.Len(); j++ {
dummy, found := localset[src]; printDep(localset, wset, decl.List.At(j).(*AST.Decl));
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"); print("\n\n");
} }
} }
*/
} }
func ComputeDeps(src_file string, flags *Flags) { func ComputeDeps(src_file string, flags *Flags) {
// string ".go" extension, if any
{ n := len(src_file);
if src_file[n-3 : n] == ".go" {
src_file = src_file[0 : n-3];
}
}
// compute deps
globalset := make(map [string] bool); globalset := make(map [string] bool);
wset := array.New(0); wset := array.New(0);
wset.Push(src_file); wset.Push(src_file);

View File

@ -10,6 +10,7 @@ import (
"array"; "array";
Scanner "scanner"; Scanner "scanner";
AST "ast"; AST "ast";
SymbolTable "symboltable";
) )
@ -20,7 +21,6 @@ type Parser struct {
// Scanner // Scanner
scanner *Scanner.Scanner; scanner *Scanner.Scanner;
tokchan <-chan *Scanner.Token;
comments *array.Array; comments *array.Array;
// Scanner.Token // Scanner.Token
@ -36,7 +36,7 @@ type Parser struct {
scope_lev int; // 0 = global scope, 1 = function scope of global functions, etc. scope_lev int; // 0 = global scope, 1 = function scope of global functions, etc.
// Scopes // Scopes
top_scope *AST.Scope; top_scope *SymbolTable.Scope;
}; };
@ -65,7 +65,7 @@ func assert(pred bool) {
func (P *Parser) printIndent() { func (P *Parser) printIndent() {
i := P.indent; i := P.indent;
// reduce tracing time by a factor of 2 // reduce printing time by a factor of 2 or more
for ; i > 10; i -= 10 { for ; i > 10; i -= 10 {
fmt.Printf(". . . . . . . . . . "); fmt.Printf(". . . . . . . . . . ");
} }
@ -91,12 +91,7 @@ func un/*trace*/(P *Parser) {
func (P *Parser) next0() { func (P *Parser) next0() {
if P.tokchan == nil { P.pos, P.tok, P.val = P.scanner.Scan();
P.pos, P.tok, P.val = P.scanner.Scan();
} else {
t := <-P.tokchan;
P.tok, P.pos, P.val = t.Tok, t.Pos, t.Val;
}
P.opt_semi = false; P.opt_semi = false;
if P.trace { if P.trace {
@ -124,14 +119,13 @@ func (P *Parser) next() {
} }
func (P *Parser) Open(trace, sixg, deps bool, scanner *Scanner.Scanner, tokchan <-chan *Scanner.Token) { func (P *Parser) Open(trace, sixg, deps bool, scanner *Scanner.Scanner) {
P.trace = trace; P.trace = trace;
P.sixg = sixg; P.sixg = sixg;
P.deps = deps; P.deps = deps;
P.indent = 0; P.indent = 0;
P.scanner = scanner; P.scanner = scanner;
P.tokchan = tokchan;
P.comments = array.New(0); P.comments = array.New(0);
P.next(); P.next();
@ -169,7 +163,7 @@ func (P *Parser) OptSemicolon() {
// Scopes // Scopes
func (P *Parser) openScope() { func (P *Parser) openScope() {
P.top_scope = AST.NewScope(P.top_scope); P.top_scope = SymbolTable.NewScope(P.top_scope);
} }
@ -178,21 +172,22 @@ func (P *Parser) closeScope() {
} }
func (P *Parser) declareInScope(scope *AST.Scope, x AST.Expr, kind int, typ *AST.Type) { func (P *Parser) declareInScope(scope *SymbolTable.Scope, x AST.Expr, kind int, typ *AST.Type) {
if P.scope_lev < 0 { if P.scope_lev < 0 {
panic("cannot declare objects in other packages"); panic("cannot declare objects in other packages");
} }
if ident, ok := x.(*AST.Ident); ok { // ignore bad exprs if ident, ok := x.(*AST.Ident); ok { // ignore bad exprs
obj := ident.Obj; obj := ident.Obj;
obj.Kind = kind; obj.Kind = kind;
obj.Typ = typ; //TODO fix typ setup!
//obj.Typ = typ;
obj.Pnolev = P.scope_lev; obj.Pnolev = P.scope_lev;
switch { switch {
case scope.LookupLocal(obj.Ident) == nil: case scope.LookupLocal(obj.Ident) == nil:
scope.Insert(obj); scope.Insert(obj);
case kind == AST.TYPE: case kind == SymbolTable.TYPE:
// possibly a forward declaration // possibly a forward declaration
case kind == AST.FUNC: case kind == SymbolTable.FUNC:
// possibly a forward declaration // possibly a forward declaration
default: default:
P.error(obj.Pos, `"` + obj.Ident + `" is declared already`); P.error(obj.Pos, `"` + obj.Ident + `" is declared already`);
@ -263,20 +258,20 @@ func (P *Parser) parseDeclaration() *AST.Decl;
// If scope != nil, lookup identifier in scope. Otherwise create one. // If scope != nil, lookup identifier in scope. Otherwise create one.
func (P *Parser) parseIdent(scope *AST.Scope) *AST.Ident { func (P *Parser) parseIdent(scope *SymbolTable.Scope) *AST.Ident {
if P.trace { if P.trace {
defer un(trace(P, "Ident")); defer un(trace(P, "Ident"));
} }
if P.tok == Scanner.IDENT { if P.tok == Scanner.IDENT {
var obj *AST.Object; var obj *SymbolTable.Object;
if scope != nil { if scope != nil {
obj = scope.Lookup(P.val); obj = scope.Lookup(P.val);
} }
if obj == nil { if obj == nil {
obj = AST.NewObject(P.pos, AST.NONE, P.val); obj = SymbolTable.NewObject(P.pos, SymbolTable.NONE, P.val);
} else { } else {
assert(obj.Kind != AST.NONE); assert(obj.Kind != SymbolTable.NONE);
} }
x := &AST.Ident{P.pos, obj}; x := &AST.Ident{P.pos, obj};
P.next(); P.next();
@ -665,7 +660,7 @@ func (P *Parser) parseStructType() *AST.Type {
P.next(); P.next();
t.List = array.New(0); t.List = array.New(0);
t.Scope = AST.NewScope(nil); t.Scope = SymbolTable.NewScope(nil);
for P.tok != Scanner.RBRACE && P.tok != Scanner.EOF { for P.tok != Scanner.RBRACE && P.tok != Scanner.EOF {
P.parseVarList(t.List, false); P.parseVarList(t.List, false);
if P.tok == Scanner.STRING { if P.tok == Scanner.STRING {
@ -686,7 +681,7 @@ func (P *Parser) parseStructType() *AST.Type {
// enter fields into struct scope // enter fields into struct scope
for i, n := 0, t.List.Len(); i < n; i++ { for i, n := 0, t.List.Len(); i < n; i++ {
if x, ok := t.List.At(i).(*AST.Ident); ok { if x, ok := t.List.At(i).(*AST.Ident); ok {
P.declareInScope(t.Scope, x, AST.FIELD, nil); P.declareInScope(t.Scope, x, SymbolTable.FIELD, nil);
} }
} }
} }
@ -777,7 +772,7 @@ func (P *Parser) parseBlock(ftyp *AST.Type, tok int) *AST.Block {
if ftyp.List != nil { if ftyp.List != nil {
for i, n := 0, ftyp.List.Len(); i < n; i++ { for i, n := 0, ftyp.List.Len(); i < n; i++ {
if x, ok := ftyp.List.At(i).(*AST.Ident); ok { if x, ok := ftyp.List.At(i).(*AST.Ident); ok {
P.declareInScope(P.top_scope, x, AST.VAR, nil); P.declareInScope(P.top_scope, x, SymbolTable.VAR, nil);
} }
} }
} }
@ -1520,13 +1515,13 @@ func (P *Parser) parseVarSpec(d *AST.Decl) {
func (P *Parser) parseSpec(d *AST.Decl) { func (P *Parser) parseSpec(d *AST.Decl) {
kind := AST.NONE; kind := SymbolTable.NONE;
switch d.Tok { switch d.Tok {
case Scanner.IMPORT: P.parseImportSpec(d); kind = AST.PACKAGE; case Scanner.IMPORT: P.parseImportSpec(d); kind = SymbolTable.PACKAGE;
case Scanner.CONST: P.parseConstSpec(d); kind = AST.CONST; case Scanner.CONST: P.parseConstSpec(d); kind = SymbolTable.CONST;
case Scanner.TYPE: P.parseTypeSpec(d); kind = AST.TYPE; case Scanner.TYPE: P.parseTypeSpec(d); kind = SymbolTable.TYPE;
case Scanner.VAR: P.parseVarSpec(d); kind = AST.VAR; case Scanner.VAR: P.parseVarSpec(d); kind = SymbolTable.VAR;
default: unreachable(); default: unreachable();
} }

View File

@ -20,11 +20,9 @@ var (
func init() { func init() {
Flag.BoolVar(&flags.Verbose, "v", false, "verbose mode: trace parsing"); Flag.BoolVar(&flags.Verbose, "v", false, "verbose mode: trace parsing");
Flag.BoolVar(&flags.Sixg, "6g", true, "6g compatibility mode"); Flag.BoolVar(&flags.Sixg, "6g", true, "6g compatibility mode");
//TODO fix this code again Flag.BoolVar(&flags.Deps, "d", false, "print dependency information only");
//Flag.BoolVar(&flags.Deps, "d", false, "print dependency information only");
Flag.BoolVar(&flags.Columns, "columns", Platform.USER == "gri", "print column info in error messages"); Flag.BoolVar(&flags.Columns, "columns", Platform.USER == "gri", "print column info in error messages");
Flag.BoolVar(&flags.Testmode, "t", false, "test mode: interprets /* ERROR */ and /* SYNC */ comments"); Flag.BoolVar(&flags.Testmode, "t", false, "test mode: interprets /* ERROR */ and /* SYNC */ comments");
Flag.BoolVar(&flags.Tokenchan, "token_chan", false, "use token channel for scanner-parser connection");
} }
@ -46,7 +44,7 @@ func main() {
for i := 0; i < Flag.NArg(); i++ { for i := 0; i < Flag.NArg(); i++ {
src_file := Flag.Arg(i); src_file := Flag.Arg(i);
if false /* DISABLED flags.deps */ { if flags.Deps {
Compilation.ComputeDeps(src_file, &flags); Compilation.ComputeDeps(src_file, &flags);
} else { } else {

View File

@ -14,6 +14,7 @@ import (
Utils "utils"; Utils "utils";
Scanner "scanner"; Scanner "scanner";
AST "ast"; AST "ast";
SymbolTable "symboltable";
) )
var ( var (
@ -411,7 +412,7 @@ func (P *Printer) HtmlEpilogue() {
func (P *Printer) HtmlIdentifier(x *AST.Ident) { func (P *Printer) HtmlIdentifier(x *AST.Ident) {
obj := x.Obj; obj := x.Obj;
if *html && obj.Kind != AST.NONE { if *html && obj.Kind != SymbolTable.NONE {
// depending on whether we have a declaration or use, generate different html // depending on whether we have a declaration or use, generate different html
// - no need to htmlEscape ident // - no need to htmlEscape ident
id := Utils.IntToString(obj.Id, 10); id := Utils.IntToString(obj.Id, 10);

View File

@ -107,9 +107,6 @@ const (
TYPE; TYPE;
VAR; VAR;
keywords_end; keywords_end;
// AST use only
EXPRSTAT;
) )
@ -208,8 +205,6 @@ func TokenString(tok int) string {
case SWITCH: return "switch"; case SWITCH: return "switch";
case TYPE: return "type"; case TYPE: return "type";
case VAR: return "var"; case VAR: return "var";
case EXPRSTAT: return "EXPRSTAT";
} }
return "token(" + Utils.IntToString(tok, 10) + ")"; return "token(" + Utils.IntToString(tok, 10) + ")";
@ -754,26 +749,3 @@ loop:
return pos, tok, val; return pos, tok, val;
} }
type Token struct {
Pos int;
Tok int;
Val string;
}
func (S *Scanner) TokenStream() <-chan *Token {
ch := make(chan *Token, 100);
go func(S *Scanner, ch chan <- *Token) {
for {
t := new(Token);
t.Pos, t.Tok, t.Val = S.Scan();
ch <- t;
if t.Tok == EOF {
break;
}
}
}(S, ch);
return ch;
}

View File

@ -0,0 +1,415 @@
// 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 SymbolTable
import (
"utf8";
"unicode";
"array";
)
type Type struct;
// ----------------------------------------------------------------------------
// Support
func assert(pred bool) {
if !pred {
panic("assertion failed");
}
}
// ----------------------------------------------------------------------------
// Objects
// Object represents a language object, such as a constant, variable, type, etc.
const /* kind */ (
BADOBJ = iota; // error handling
NONE; // kind unknown
CONST; TYPE; VAR; FIELD; FUNC; BUILTIN; PACKAGE; LABEL;
END; // end of scope (import/export only)
)
func KindStr(kind int) string {
switch kind {
case BADOBJ: return "BADOBJ";
case NONE: return "NONE";
case CONST: return "CONST";
case TYPE: return "TYPE";
case VAR: return "VAR";
case FIELD: return "FIELD";
case FUNC: return "FUNC";
case BUILTIN: return "BUILTIN";
case PACKAGE: return "PACKAGE";
case LABEL: return "LABEL";
case END: return "END";
}
return "<unknown Object kind>";
}
type Object struct {
Id int; // unique id
Pos int; // source position (< 0 if unknown position)
Kind int; // object kind
Ident string;
Typ *Type; // nil for packages
Pnolev int; // >= 0: package no., <= 0: function nesting level, 0: global level
}
func (obj *Object) IsExported() bool {
switch obj.Kind {
case NONE /* FUNC for now */, CONST, TYPE, VAR, FUNC:
ch, size := utf8.DecodeRuneInString(obj.Ident, 0);
return unicode.IsUpper(ch);
}
return false;
}
func (obj* Object) String() string {
if obj != nil {
return
"Object(" +
KindStr(obj.Kind) + ", " +
obj.Ident +
")";
}
return "nil";
}
var Universe_void_typ *Type // initialized by Universe to Universe.void_typ
var objectId int;
func NewObject(pos, kind int, ident string) *Object {
obj := new(Object);
obj.Id = objectId;
objectId++;
obj.Pos = pos;
obj.Kind = kind;
obj.Ident = ident;
obj.Typ = Universe_void_typ; // TODO would it be better to use nil instead?
obj.Pnolev = 0;
return obj;
}
// ----------------------------------------------------------------------------
// Scopes
type Scope struct {
Parent *Scope;
entries map[string] *Object;
}
func NewScope(parent *Scope) *Scope {
scope := new(Scope);
scope.Parent = parent;
scope.entries = make(map[string] *Object, 8);
return scope;
}
func (scope *Scope) LookupLocal(ident string) *Object {
obj, found := scope.entries[ident];
if found {
return obj;
}
return nil;
}
func (scope *Scope) Lookup(ident string) *Object {
for scope != nil {
obj := scope.LookupLocal(ident);
if obj != nil {
return obj;
}
scope = scope.Parent;
}
return nil;
}
func (scope *Scope) add(obj *Object) {
scope.entries[obj.Ident] = obj;
}
func (scope *Scope) Insert(obj *Object) {
if scope.LookupLocal(obj.Ident) != nil {
panic("obj already inserted");
}
scope.add(obj);
}
func (scope *Scope) InsertImport(obj *Object) *Object {
p := scope.LookupLocal(obj.Ident);
if p == nil {
scope.add(obj);
p = obj;
}
return p;
}
func (scope *Scope) Print() {
print("scope {");
for key := range scope.entries {
print("\n ", key);
}
print("\n}\n");
}
// ----------------------------------------------------------------------------
// Types
const /* form */ (
// internal types
// We should never see one of these.
UNDEF = iota;
// VOID types are used when we don't have a type. Never exported.
// (exported type forms must be > 0)
VOID;
// BADTYPE types are compatible with any type and don't cause further errors.
// They are introduced only as a result of an error in the source code. A
// correct program cannot have BAD types.
BADTYPE;
// FORWARD types are forward-declared (incomplete) types. They can only
// be used as element types of pointer types and must be resolved before
// their internals are accessible.
FORWARD;
// TUPLE types represent multi-valued result types of functions and
// methods.
TUPLE;
// The type of nil.
NIL;
// A type name
TYPENAME;
// basic types
BOOL; UINT; INT; FLOAT; STRING; INTEGER;
// composite types
ALIAS; ARRAY; STRUCT; INTERFACE; MAP; CHANNEL; FUNCTION; METHOD; POINTER;
// open-ended parameter type
ELLIPSIS
)
func FormStr(form int) string {
switch form {
case VOID: return "VOID";
case BADTYPE: return "BADTYPE";
case FORWARD: return "FORWARD";
case TUPLE: return "TUPLE";
case NIL: return "NIL";
case TYPENAME: return "TYPENAME";
case BOOL: return "BOOL";
case UINT: return "UINT";
case INT: return "INT";
case FLOAT: return "FLOAT";
case STRING: return "STRING";
case ALIAS: return "ALIAS";
case ARRAY: return "ARRAY";
case STRUCT: return "STRUCT";
case INTERFACE: return "INTERFACE";
case MAP: return "MAP";
case CHANNEL: return "CHANNEL";
case FUNCTION: return "FUNCTION";
case METHOD: return "METHOD";
case POINTER: return "POINTER";
case ELLIPSIS: return "ELLIPSIS";
}
return "<unknown Type form>";
}
const /* channel mode */ (
FULL = iota;
SEND;
RECV;
)
type Type struct {
Id int; // unique id
Ref int; // for exporting only: >= 0 means already exported
Form int; // type form
Size int; // size in bytes
Obj *Object; // primary type object or nil
Scope *Scope; // locals, fields & methods
// syntactic components
Pos int; // source position (< 0 if unknown position)
Len int; // array length
Mode int; // channel mode
Key *Type; // receiver type or map key
Elt *Type; // type name type, array, map, channel or pointer element type, function result type
List *array.Array; End int; // struct fields, interface methods, function parameters
}
var typeId int;
func NewType(pos, form int) *Type {
typ := new(Type);
typ.Id = typeId;
typeId++;
typ.Ref = -1; // not yet exported
typ.Pos = pos;
typ.Form = form;
return typ;
}
func (typ* Type) String() string {
if typ != nil {
return
"Type(" +
FormStr(typ.Form) +
")";
}
return "nil";
}
// ----------------------------------------------------------------------------
// Universe scope
var (
Universe *Scope;
PredeclaredTypes array.Array;
// internal types
Void_typ,
Bad_typ,
Nil_typ,
// basic types
Bool_typ,
Uint8_typ,
Uint16_typ,
Uint32_typ,
Uint64_typ,
Int8_typ,
Int16_typ,
Int32_typ,
Int64_typ,
Float32_typ,
Float64_typ,
Float80_typ,
String_typ,
Integer_typ,
// convenience types
Byte_typ,
Uint_typ,
Int_typ,
Float_typ,
Uintptr_typ *Type;
True_obj,
False_obj,
Iota_obj,
Nil_obj *Object;
)
func declObj(kind int, ident string, typ *Type) *Object {
obj := NewObject(-1 /* no source pos */, kind, ident);
obj.Typ = typ;
if kind == TYPE && typ.Obj == nil {
typ.Obj = obj; // set primary type object
}
Universe.Insert(obj);
return obj
}
func declType(form int, ident string, size int) *Type {
typ := NewType(-1 /* no source pos */, form);
typ.Size = size;
return declObj(TYPE, ident, typ).Typ;
}
func register(typ *Type) *Type {
typ.Ref = PredeclaredTypes.Len();
PredeclaredTypes.Push(typ);
return typ;
}
func init() {
Universe = NewScope(nil); // universe has no parent
PredeclaredTypes.Init(32);
// Interal types
Void_typ = NewType(-1 /* no source pos */, VOID);
Universe_void_typ = Void_typ;
Bad_typ = NewType(-1 /* no source pos */, BADTYPE);
Nil_typ = NewType(-1 /* no source pos */, NIL);
// Basic types
Bool_typ = register(declType(BOOL, "bool", 1));
Uint8_typ = register(declType(UINT, "uint8", 1));
Uint16_typ = register(declType(UINT, "uint16", 2));
Uint32_typ = register(declType(UINT, "uint32", 4));
Uint64_typ = register(declType(UINT, "uint64", 8));
Int8_typ = register(declType(INT, "int8", 1));
Int16_typ = register(declType(INT, "int16", 2));
Int32_typ = register(declType(INT, "int32", 4));
Int64_typ = register(declType(INT, "int64", 8));
Float32_typ = register(declType(FLOAT, "float32", 4));
Float64_typ = register(declType(FLOAT, "float64", 8));
Float80_typ = register(declType(FLOAT, "float80", 10));
String_typ = register(declType(STRING, "string", 8));
Integer_typ = register(declType(INTEGER, "integer", 8));
// All but 'byte' should be platform-dependent, eventually.
Byte_typ = register(declType(UINT, "byte", 1));
Uint_typ = register(declType(UINT, "uint", 4));
Int_typ = register(declType(INT, "int", 4));
Float_typ = register(declType(FLOAT, "float", 4));
Uintptr_typ = register(declType(UINT, "uintptr", 8));
// Predeclared constants
True_obj = declObj(CONST, "true", Bool_typ);
False_obj = declObj(CONST, "false", Bool_typ);
Iota_obj = declObj(CONST, "iota", Int_typ);
Nil_obj = declObj(CONST, "nil", Nil_typ);
// Builtin functions
declObj(BUILTIN, "len", Void_typ);
declObj(BUILTIN, "new", Void_typ);
declObj(BUILTIN, "panic", Void_typ);
declObj(BUILTIN, "print", Void_typ);
// scope.Print();
}

View File

@ -7,7 +7,6 @@ package TypeChecker
import ( import (
AST "ast"; AST "ast";
Scanner "scanner"; Scanner "scanner";
Universe "universe";
) )

View File

@ -1,123 +0,0 @@
// 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 Universe
import (
"array";
AST "ast";
)
var (
Scope *AST.Scope;
Types array.Array;
// internal types
Void_typ,
Bad_typ,
Nil_typ,
// basic types
Bool_typ,
Uint8_typ,
Uint16_typ,
Uint32_typ,
Uint64_typ,
Int8_typ,
Int16_typ,
Int32_typ,
Int64_typ,
Float32_typ,
Float64_typ,
Float80_typ,
String_typ,
Integer_typ,
// convenience types
Byte_typ,
Uint_typ,
Int_typ,
Float_typ,
Uintptr_typ *AST.Type;
True_obj,
False_obj,
Iota_obj,
Nil_obj *AST.Object;
)
func declObj(kind int, ident string, typ *AST.Type) *AST.Object {
obj := AST.NewObject(-1 /* no source pos */, kind, ident);
obj.Typ = typ;
if kind == AST.TYPE && typ.Obj == nil {
typ.Obj = obj; // set primary type object
}
Scope.Insert(obj);
return obj
}
func declType(form int, ident string, size int) *AST.Type {
typ := AST.NewType(-1 /* no source pos */, form);
typ.Size = size;
return declObj(AST.TYPE, ident, typ).Typ;
}
func register(typ *AST.Type) *AST.Type {
typ.Ref = Types.Len();
Types.Push(typ);
return typ;
}
func init() {
Scope = AST.NewScope(nil); // universe has no parent
Types.Init(32);
// Interal types
Void_typ = AST.NewType(-1 /* no source pos */, AST.VOID);
AST.Universe_void_typ = Void_typ;
Bad_typ = AST.NewType(-1 /* no source pos */, AST.BADTYPE);
Nil_typ = AST.NewType(-1 /* no source pos */, AST.NIL);
// Basic types
Bool_typ = register(declType(AST.BOOL, "bool", 1));
Uint8_typ = register(declType(AST.UINT, "uint8", 1));
Uint16_typ = register(declType(AST.UINT, "uint16", 2));
Uint32_typ = register(declType(AST.UINT, "uint32", 4));
Uint64_typ = register(declType(AST.UINT, "uint64", 8));
Int8_typ = register(declType(AST.INT, "int8", 1));
Int16_typ = register(declType(AST.INT, "int16", 2));
Int32_typ = register(declType(AST.INT, "int32", 4));
Int64_typ = register(declType(AST.INT, "int64", 8));
Float32_typ = register(declType(AST.FLOAT, "float32", 4));
Float64_typ = register(declType(AST.FLOAT, "float64", 8));
Float80_typ = register(declType(AST.FLOAT, "float80", 10));
String_typ = register(declType(AST.STRING, "string", 8));
Integer_typ = register(declType(AST.INTEGER, "integer", 8));
// All but 'byte' should be platform-dependent, eventually.
Byte_typ = register(declType(AST.UINT, "byte", 1));
Uint_typ = register(declType(AST.UINT, "uint", 4));
Int_typ = register(declType(AST.INT, "int", 4));
Float_typ = register(declType(AST.FLOAT, "float", 4));
Uintptr_typ = register(declType(AST.UINT, "uintptr", 8));
// Predeclared constants
True_obj = declObj(AST.CONST, "true", Bool_typ);
False_obj = declObj(AST.CONST, "false", Bool_typ);
Iota_obj = declObj(AST.CONST, "iota", Int_typ);
Nil_obj = declObj(AST.CONST, "nil", Nil_typ);
// Builtin functions
declObj(AST.BUILTIN, "len", Void_typ);
declObj(AST.BUILTIN, "new", Void_typ);
declObj(AST.BUILTIN, "panic", Void_typ);
declObj(AST.BUILTIN, "print", Void_typ);
// scope.Print();
}