// 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 Globals // The following types should really be in their respective files // (object.go, type.go, scope.go, package.go, compilation.go, etc.) but // they refer to each other and we don't know how to handle forward // declared pointers across packages yet. // ---------------------------------------------------------------------------- type Type struct type Scope struct type Elem struct type Compilation struct // Object represents a language object, such as a constant, variable, type, // etc. (kind). An objects is (pre-)declared at a particular position in the // source code (pos), has a name (ident), a type (typ), and a package number // or nesting level (pnolev). type Object struct { exported bool; pos int; // source position (< 0 if unknown position) kind int; ident string; typ *Type; // nil for packages pnolev int; // >= 0: package no., <= 0: function nesting level, 0: global level } type Type struct { ref int; // for exporting only: >= 0 means already exported form int; size int; // in bytes len int; // array length, no. of function/method parameters (w/o recv) aux int; // channel info obj *Object; // primary type object or NULL key *Type; // alias base type or map key elt *Type; // aliased type, array, map, channel or pointer element type, function result type, tuple function type scope *Scope; // forwards, structs, interfaces, functions } type Package struct { ref int; // for exporting only: >= 0 means already exported file_name string; key string; obj *Object; scope *Scope; // holds the (global) objects in this package } type List struct { len int; first, last *Elem; }; type Scope struct { parent *Scope; entries *List; // entries map[string] *Object; // doesn't work properly } type Flags struct { debug bool; object_file string; update_packages bool; print_interface bool; verbosity uint; sixg bool; token_chan bool; } type Environment struct { Error *(comp *Compilation, pos int, msg string); Import *(comp *Compilation, pkg_file string) *Package; Export *(comp *Compilation, pkg_file string); Compile *(comp *Compilation, src_file string); } type Compilation struct { // environment flags *Flags; env *Environment; // TODO rethink the need for this here src_file string; src string; // Error handling nerrors int; // number of errors reported errpos int; // last error position // TODO use open arrays eventually pkg_list [256] *Package; // pkg_list[0] is the current package pkg_ref int; } type Expr interface { op() int; // node operation pos() int; // source position typ() *Type; // ... more to come here } type Stat interface { // ... more to come here } // TODO This is hideous! We need to have a decent way to do lists. // Ideally open arrays that allow '+'. type Elem struct { next *Elem; val int; str string; obj *Object; typ *Type; expr Expr } // ---------------------------------------------------------------------------- // Creation var Universe_void_t *Type // initialized by Universe to Universe.void_t func NewObject(pos, kind int, ident string) *Object { obj := new(Object); obj.exported = false; obj.pos = pos; obj.kind = kind; obj.ident = ident; obj.typ = Universe_void_t; obj.pnolev = 0; return obj; } func NewType(form int) *Type { typ := new(Type); typ.ref = -1; // not yet exported typ.form = form; return typ; } func NewPackage(file_name string, obj *Object, scope *Scope) *Package { pkg := new(Package); pkg.ref = -1; // not yet exported pkg.file_name = file_name; pkg.key = ""; // empty key means package forward declaration pkg.obj = obj; pkg.scope = scope; return pkg; } func NewList() *List { return new(List); } func NewScope(parent *Scope) *Scope { scope := new(Scope); scope.parent = parent; scope.entries = NewList(); return scope; } // ---------------------------------------------------------------------------- // Object methods func (obj *Object) Copy() *Object { copy := new(Object); copy.exported = obj.exported; copy.pos = obj.pos; copy.kind = obj.kind; copy.ident = obj.ident; copy.typ = obj.typ; copy.pnolev = obj.pnolev; return copy; } // ---------------------------------------------------------------------------- // List methods func (L *List) at(i int) *Elem { if i < 0 || L.len <= i { panic("index out of bounds"); } p := L.first; for ; i > 0; i-- { p = p.next; } return p; } func (L *List) Clear() { L.len, L.first, L.last = 0, nil, nil; } func (L *List) Add() *Elem { L.len++; e := new(Elem); if L.first == nil { L.first = e; } else { L.last.next = e; } L.last = e; return e; } func (L *List) IntAt(i int) int { return L.at(i).val; } func (L *List) StrAt(i int) string { return L.at(i).str; } func (L *List) ObjAt(i int) *Object { return L.at(i).obj; } func (L *List) TypAt(i int) *Type { return L.at(i).typ; } func (L *List) ExprAt(i int) Expr { return L.at(i).expr; } func (L *List) AddInt(val int) { L.Add().val = val; } func (L *List) AddStr(str string) { L.Add().str = str; } func (L *List) AddObj(obj *Object) { L.Add().obj = obj; } func (L *List) AddTyp(typ *Type) { L.Add().typ = typ; } func (L *List) AddExpr(expr Expr) { L.Add().expr = expr; } // ---------------------------------------------------------------------------- // Scope methods func (scope *Scope) Lookup(ident string) *Object { for p := scope.entries.first; p != nil; p = p.next { if p.obj.ident == ident { return p.obj; } } return nil; } func (scope *Scope) Add(obj* Object) { scope.entries.AddObj(obj); } func (scope *Scope) Insert(obj *Object) { if scope.Lookup(obj.ident) != nil { panic("obj already inserted"); } scope.Add(obj); } func (scope *Scope) InsertImport(obj *Object) *Object { p := scope.Lookup(obj.ident); if p == nil { scope.Add(obj); p = obj; } return p; } func (scope *Scope) Print() { print("scope {"); for p := scope.entries.first; p != nil; p = p.next { print("\n ", p.obj.ident); } print("\n}\n"); } // ---------------------------------------------------------------------------- // Compilation methods func (C *Compilation) Lookup(file_name string) *Package { for i := 0; i < C.pkg_ref; i++ { pkg := C.pkg_list[i]; if pkg.file_name == file_name { return pkg; } } return nil; } func (C *Compilation) Insert(pkg *Package) { if C.Lookup(pkg.file_name) != nil { panic("package already inserted"); } pkg.obj.pnolev = C.pkg_ref; C.pkg_list[C.pkg_ref] = pkg; C.pkg_ref++; }