- make code in gosrc compile again, check in all pending changes
  (this code doesn't match the existing language at this point,
  but it's a large code base which compiles - will eventually go
  away)
- enable compilation of it again in run.bash

R=r
DELTA=1147  (534 added, 311 deleted, 302 changed)
OCL=22176
CL=22176
diff --git a/usr/gri/gosrc/ast.go b/usr/gri/gosrc/ast.go
index b1d495b..06c2968 100644
--- a/usr/gri/gosrc/ast.go
+++ b/usr/gri/gosrc/ast.go
@@ -5,12 +5,26 @@
 package AST
 
 import Globals "globals"
+import GlobalObject "object"
+import Type "type"
 import Universe "universe"
 
 
 // ----------------------------------------------------------------------------
 // Expressions
 
+export const /* op */ (
+	LITERAL = iota;
+	OBJECT;
+	DEREF;
+	SELECT;
+	CALL;
+	TUPLE;
+)
+
+
+// ----------------------------------------------------------------------------
+// Literals
 
 export type Literal struct {
 	pos_ int;
@@ -22,18 +36,13 @@
 }
 
 
-func (x *Literal) pos() int {
-	return x.pos_;
-}
-
-
-func (x *Literal) typ() *Globals.Type {
-	return x.typ_;
-}
+func (x *Literal) op() int  { return LITERAL; }
+func (x *Literal) pos() int  { return x.pos_; }
+func (x *Literal) typ() *Globals.Type  { return x.typ_; }
 
 
 export func NewLiteral(pos int, typ *Globals.Type) *Literal {
-	x := new(*Literal);
+	x := new(Literal);
 	x.pos_ = pos;
 	x.typ_ = typ;
 	return x;
@@ -43,6 +52,9 @@
 export var Bad, True, False, Nil *Literal;
 
 
+// ----------------------------------------------------------------------------
+// Objects
+
 // NOTE We could use Globals.Object directly if we'd added a typ()
 // method to its interface. However, this would require renaming the
 // typ field everywhere... - Need to think about accessors again.
@@ -52,24 +64,43 @@
 }
 
 
-func (x *Object) pos() int {
-	return x.pos_;
-}
-
-
-func (x *Object) typ() *Globals.Type {
-	return x.obj.typ;
-}
+func (x *Object) op() int  { return OBJECT; }
+func (x *Object) pos() int  { return x.pos_; }
+func (x *Object) typ() *Globals.Type  { return x.obj.typ; }
 
 
 export func NewObject(pos int, obj* Globals.Object) *Object {
-	x := new(*Object);
+	x := new(Object);
 	x.pos_ = pos;
 	x.obj = obj;
 	return x;
 }
 
 
+// ----------------------------------------------------------------------------
+// Derefs
+
+// TODO model Deref as unary operation?
+export type Deref struct {
+	ptr_ Globals.Expr;
+}
+
+
+func (x *Deref) op() int  { return DEREF; }
+func (x *Deref) pos() int { return x.ptr_.pos(); }
+func (x *Deref) typ() *Globals.Type  { return x.ptr_.typ().elt; }
+
+
+export func NewDeref(ptr Globals.Expr) *Deref {
+	x := new(Deref);
+	x.ptr_ = ptr;
+	return x;
+}
+
+
+// ----------------------------------------------------------------------------
+// Selectors
+
 // TODO model Selector as binary operation?
 export type Selector struct {
 	pos_ int;
@@ -77,39 +108,87 @@
 }
 
 
-func (x *Selector) pos() int {
-	return x.pos_;
-}
-
-
-func (x *Selector) typ() *Globals.Type {
-	return x.typ_;
-}
+func (x *Selector) op() int  { return SELECT; }
+func (x *Selector) pos() int  { return x.pos_; }
+func (x *Selector) typ() *Globals.Type  { return x.typ_; }
 
 
 export func NewSelector(pos int, typ *Globals.Type) *Selector {
-	x := new(*Selector);
+	x := new(Selector);
 	x.pos_ = pos;
 	x.typ_ = typ;
 	return x;
 }
 
 
+// ----------------------------------------------------------------------------
+// Calls
+
+export type Call struct {
+	recv, callee Globals.Expr;
+	args *Globals.List;
+}
+
+
+func (x *Call) op() int  { return CALL; }
+func (x *Call) pos() int  { return 0; }
+func (x *Call) typ() *Globals.Type  { return nil; }
+
+
+export func NewCall(args *Globals.List) *Call {
+	x := new(Call);
+	x.args = args;
+	return x;
+}
+
+
+// ----------------------------------------------------------------------------
+// Binary expressions
+
 export type BinaryExpr struct {
+	op_ int;
 	pos_ int;
 	typ_ *Globals.Type;
-	op int;
 	x, y Globals.Expr;
 }
 
 
-func (x *BinaryExpr) pos() int {
-	return x.pos_;
+func (x *BinaryExpr) op() int  { return x.op_; }
+func (x *BinaryExpr) pos() int  { return x.pos_; }
+func (x *BinaryExpr) typ() *Globals.Type  {	return x.typ_; }
+
+
+// ----------------------------------------------------------------------------
+// Tuples
+
+export type Tuple struct {
+	typ_ *Globals.Type;
+	list *Globals.List;
 }
 
 
-func (x *BinaryExpr) typ() *Globals.Type {
-	return x.typ_;
+func (x *Tuple) op() int  {	return TUPLE; }
+func (x *Tuple) pos() int  { return x.list.first.expr.pos(); }
+func (x *Tuple) typ() *Globals.Type  { return x.typ_; }
+
+
+export func NewTuple(list *Globals.List) *Tuple {
+	// make corresponding tuple type
+	scope := Globals.NewScope(nil);
+	for p := list.first; p != nil; p = p.next {
+		x := p.expr;
+		obj := Globals.NewObject(x.pos(), GlobalObject.FIELD, "");
+		obj.typ = x.typ();
+		scope.Add(obj);
+	}
+	typ := Globals.NewType(Type.TUPLE);
+	typ.scope = scope;
+	
+	// create the tuple
+	x := new(Tuple);
+	x.typ_ = typ;
+	x.list = list;
+	return x;
 }
 
 
diff --git a/usr/gri/gosrc/compilation.go b/usr/gri/gosrc/compilation.go
index e72aa46..76298f7 100644
--- a/usr/gri/gosrc/compilation.go
+++ b/usr/gri/gosrc/compilation.go
@@ -19,6 +19,54 @@
 import Verifier "verifier"
 
 
+// Compute (line, column) information for a given source position.
+func LineCol(src string, pos int) (line, col int) {
+	line = 1;
+	lpos := 0;
+	
+	if pos > len(src) {
+		pos = len(src);
+	}
+
+	for i := 0; i < pos; i++ {
+		if src[i] == '\n' {
+			line++;
+			lpos = i;
+		}
+	}
+	
+	return line, pos - lpos;
+}
+
+
+export func Error(comp *Globals.Compilation, pos int, msg string) {
+	const errdist = 10;
+	delta := pos - comp.errpos;  // may be negative!
+	if delta < 0 {
+		delta = -delta;
+	}
+	if delta > errdist || comp.nerrors == 0 /* always report first error */ {
+		print(comp.src_file);
+		if pos >= 0 {
+			// print position
+			line, col := LineCol(comp.src, pos);
+			if Platform.USER == "gri" {
+				print(":", line, ":", col);
+			} else {
+				print(":", line);
+			}
+		}
+		print(": ", msg, "\n");
+		comp.nerrors++;
+		comp.errpos = pos;
+	}
+	
+	if comp.nerrors >= 10 {
+		sys.exit(1);
+	}
+}
+
+
 func ReadImport(comp* Globals.Compilation, filename string, update bool) (data string, ok bool) {
 	if filename == "" {
 		panic("illegal package file name");
@@ -83,34 +131,38 @@
 
 
 export func Compile(comp *Globals.Compilation, src_file string) {
+	// TODO This is incorrect: When compiling with the -r flag, we are
+	// calling this function recursively w/o setting up a new comp - this
+	// is broken and leads to an assertion error (more then one package
+	// upon parsing of the package header).
+	
 	src, ok := Platform.ReadSourceFile(src_file);
 	if !ok {
 		print("cannot open ", src_file, "\n");
 		return;
 	}
 
+	comp.src_file = src_file;
+	comp.src = src;
+	
 	if comp.flags.verbosity > 0 {
 		print(src_file, "\n");
 	}
 
-	scanner := new(*Scanner.Scanner);
+	scanner := new(Scanner.Scanner);
 	scanner.Open(src_file, src);
 
 	var tstream chan *Scanner.Token;
 	if comp.flags.token_chan {
-		tstream = new(chan *Scanner.Token, 100);
+		tstream = make(chan *Scanner.Token, 100);
 		go scanner.Server(tstream);
 	}
 
-	parser := new(*Parser.Parser);
+	parser := new(Parser.Parser);
 	parser.Open(comp, scanner, tstream);
 
 	parser.ParseProgram();
-	if parser.S.nerrors > 0 {
-		return;
-	}
-
-	if !comp.flags.ast {
+	if parser.scanner.nerrors > 0 {
 		return;
 	}
 
diff --git a/usr/gri/gosrc/export.go b/usr/gri/gosrc/export.go
index 97f9d1b..6b5cee2 100755
--- a/usr/gri/gosrc/export.go
+++ b/usr/gri/gosrc/export.go
@@ -174,6 +174,9 @@
 	}
 	
 	switch typ.form {
+	case Type.VOID:
+		// for now until we have enough of the front-end working.
+		
 	case Type.FORWARD:
 		// corresponding package must be forward-declared too
 		if typ.obj == nil || E.comp.pkg_list[typ.obj.pnolev].key != "" {
@@ -181,25 +184,29 @@
 		}
 		
 	case Type.ALIAS, Type.MAP:
-		E.WriteType(typ.aux);
+		E.WriteType(typ.key);
+		E.WriteType(typ.elt);
+
+	case Type.TUPLE:
 		E.WriteType(typ.elt);
 
 	case Type.ARRAY:
-		E.WriteInt(typ.len_);
+		E.WriteInt(typ.len);
 		E.WriteType(typ.elt);
 
 	case Type.CHANNEL:
-		E.WriteInt(typ.flags);
+		E.WriteInt(typ.aux);
 		E.WriteType(typ.elt);
 
-	case Type.FUNCTION:
-		E.WriteInt(typ.flags);
+	case Type.FUNCTION, Type.METHOD:
+		E.WriteInt(typ.len);
+		E.WriteType(typ.elt);
 		E.WriteScope(typ.scope);
 		
 	case Type.STRUCT, Type.INTERFACE:
 		E.WriteScope(typ.scope);
 
-	case Type.POINTER, Type.REFERENCE:
+	case Type.POINTER:
 		E.WriteType(typ.elt);
 
 	default:
@@ -266,7 +273,7 @@
 			i++;
 		}
 	}
-	E.type_ref = Universe.types.len_;
+	E.type_ref = Universe.types.len;
 	
 	// export package 0
 	pkg := comp.pkg_list[0];
diff --git a/usr/gri/gosrc/expr.go b/usr/gri/gosrc/expr.go
new file mode 100755
index 0000000..2cf40df
--- /dev/null
+++ b/usr/gri/gosrc/expr.go
@@ -0,0 +1,164 @@
+// 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 Expr
+
+import Globals "globals"
+import Universe "universe"
+import Object "object"
+import Type "type"
+import AST "ast"
+
+
+// TODO the following shortcuts below don't work due to 6g/6l bugs
+//type Compilation Globals.Compilation
+//type Expr Globals.Expr
+
+
+func Error(comp *Globals.Compilation, pos int, msg string) {
+	comp.env.Error(comp, pos, msg);
+}
+
+
+export func Deref(comp *Globals.Compilation, x Globals.Expr) Globals.Expr {
+	switch typ := x.typ(); typ.form {
+	case Type.BAD:
+		// ignore
+		
+	case Type.POINTER:
+		x = AST.NewDeref(x);
+		
+	default:
+		Error(comp, x.pos(), `"*" not applicable (typ.form = ` + Type.FormStr(typ.form) + `)`);
+		x = AST.Bad;
+	}
+	
+	return x;
+}
+
+
+export func Select(comp *Globals.Compilation, x Globals.Expr, pos int, selector string) Globals.Expr {
+	if x.typ().form == Type.POINTER {
+		x = Deref(comp, x);
+	}
+
+	switch typ := x.typ(); typ.form {
+	case Type.BAD:
+		// ignore
+
+	case Type.STRUCT, Type.INTERFACE:
+		obj := typ.scope.Lookup(selector);
+		if obj != nil {
+			x = AST.NewSelector(x.pos(), obj.typ);
+			
+		} else {
+			Error(comp, pos, `no field/method "` + selector + `"`);
+			x = AST.Bad;
+		}
+
+	default:
+		Error(comp, pos, `"." not applicable (typ.form = ` + Type.FormStr(typ.form) + `)`);
+		x = AST.Bad;
+	}
+	
+	return x;
+}
+
+
+export func AssertType(comp *Globals.Compilation, x Globals.Expr, pos int, typ *Globals.Type) Globals.Expr {
+	return AST.Bad;
+}
+
+
+export func Index(comp *Globals.Compilation, x, i Globals.Expr) Globals.Expr {
+	if x.typ().form == Type.POINTER {
+		x = Deref(comp, x);
+	}
+
+	switch typ := x.typ(); typ.form {
+	case Type.BAD:
+		// ignore
+		
+	case Type.STRING, Type.ARRAY:
+		x = AST.Bad;
+		
+	case Type.MAP:
+		if Type.Equal(typ.key, i.typ()) {
+			// x = AST.NewSubscript(x, i1);
+			x = AST.Bad;
+			
+		} else {
+			Error(comp, x.pos(), "map key type mismatch");
+			x = AST.Bad;
+		}
+		
+	default:
+		Error(comp, x.pos(), `"[]" not applicable (typ.form = ` + Type.FormStr(typ.form) + `)`);
+		x = AST.Bad;
+	}
+	return x;
+}
+
+
+export func Slice(comp *Globals.Compilation, x, i, j Globals.Expr) Globals.Expr {
+	if x.typ().form == Type.POINTER {
+		x = Deref(comp, x);
+	}
+
+	switch typ := x.typ(); typ.form {
+	case Type.BAD:
+		// ignore
+		break;
+	case Type.STRING, Type.ARRAY:
+		x = AST.Bad;
+		
+	case Type.MAP:
+		if Type.Equal(typ.key, i.typ()) {
+			// x = AST.NewSubscript(x, i1);
+			x = AST.Bad;
+			
+		} else {
+			Error(comp, x.pos(), "map key type mismatch");
+			x = AST.Bad;
+		}
+		
+	default:
+		Error(comp, x.pos(), `"[:]" not applicable (typ.form = ` + Type.FormStr(typ.form) + `)`);
+		x = AST.Bad;
+	}
+	return x;
+}
+
+
+export func Call(comp *Globals.Compilation, x Globals.Expr, args *Globals.List) Globals.Expr {
+	if x.typ().form == Type.POINTER {
+		x = Deref(comp, x);
+	}
+	
+	if x.op() == AST.OBJECT && x.(*AST.Object).obj.kind == Object.BUILTIN {
+		panic("builtin call - UNIMPLEMENTED");
+	}
+	
+	typ := x.typ();
+	if typ.form == Type.FUNCTION || typ.form == Type.METHOD {
+		// TODO check args against parameters
+	}
+	
+	return AST.Bad;
+}
+
+
+export func UnaryExpr(comp *Globals.Compilation, x Globals.Expr) Globals.Expr {
+	return AST.Bad;
+}
+
+
+export func BinaryExpr(comp *Globals.Compilation, x, y Globals.Expr) Globals.Expr {
+	e := new(AST.BinaryExpr);
+	e.typ_ = x.typ();  // TODO fix this
+	//e.op = P.tok;  // TODO should we use tokens or separate operator constants?
+	e.x = x;
+	e.y = y;
+	return e;
+}
diff --git a/usr/gri/gosrc/globals.go b/usr/gri/gosrc/globals.go
index 809e01f..15e8d06 100644
--- a/usr/gri/gosrc/globals.go
+++ b/usr/gri/gosrc/globals.go
@@ -18,6 +18,11 @@
 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).
+
 export type Object struct {
 	exported bool;
 	pos int;  // source position (< 0 if unknown position)
@@ -31,12 +36,12 @@
 export type Type struct {
 	ref int;  // for exporting only: >= 0 means already exported
 	form int;
-	flags int;  // channels, functions
 	size int;  // in bytes
-	len_ int;  // array length, no. of parameters (w/o recv)
+	len int;  // array length, no. of function/method parameters (w/o recv)
+	aux int;  // channel info
 	obj *Object;  // primary type object or NULL
-	aux *Type;  // alias base type or map key
-	elt *Type;  // aliases, arrays, maps, channels, pointers
+	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
 }
 
@@ -51,7 +56,7 @@
 
 
 export type List struct {
-	len_ int;
+	len int;
 	first, last *Elem;
 };
 
@@ -70,17 +75,12 @@
 	print_interface bool;
 	verbosity uint;
 	sixg bool;
-
-	scan bool;
-	parse bool;
-	ast bool;
-	deps bool;
 	token_chan bool;
 }
 
 
 export type Environment struct {
-	Error *(comp *Compilation);  // TODO complete this
+	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);
@@ -91,7 +91,15 @@
 	// 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;
@@ -99,6 +107,7 @@
 
 
 export type Expr interface {
+	op() int;  // node operation
 	pos() int;  // source position
 	typ() *Type;
 	// ... more to come here
@@ -113,7 +122,7 @@
 // TODO This is hideous! We need to have a decent way to do lists.
 // Ideally open arrays that allow '+'.
 
-type Elem struct {
+export type Elem struct {
 	next *Elem;
 	val int;
 	str string;
@@ -129,7 +138,7 @@
 export var Universe_void_t *Type  // initialized by Universe to Universe.void_t
 
 export func NewObject(pos, kind int, ident string) *Object {
-	obj := new(*Object);
+	obj := new(Object);
 	obj.exported = false;
 	obj.pos = pos;
 	obj.kind = kind;
@@ -141,7 +150,7 @@
 
 
 export func NewType(form int) *Type {
-	typ := new(*Type);
+	typ := new(Type);
 	typ.ref = -1;  // not yet exported
 	typ.form = form;
 	return typ;
@@ -149,7 +158,7 @@
 
 
 export func NewPackage(file_name string, obj *Object, scope *Scope) *Package {
-	pkg := new(*Package);
+	pkg := new(Package);
 	pkg.ref = -1;  // not yet exported
 	pkg.file_name = file_name;
 	pkg.key = "<the package key>";  // empty key means package forward declaration
@@ -160,12 +169,12 @@
 
 
 export func NewList() *List {
-	return new(*List);
+	return new(List);
 }
 
 
 export func NewScope(parent *Scope) *Scope {
-	scope := new(*Scope);
+	scope := new(Scope);
 	scope.parent = parent;
 	scope.entries = NewList();
 	return scope;
@@ -176,7 +185,7 @@
 // Object methods
 
 func (obj *Object) Copy() *Object {
-	copy := new(*Object);
+	copy := new(Object);
 	copy.exported = obj.exported;
 	copy.pos = obj.pos;
 	copy.kind = obj.kind;
@@ -191,7 +200,7 @@
 // List methods
 
 func (L *List) at(i int) *Elem {
-	if i < 0 || L.len_ <= i {
+	if i < 0 || L.len <= i {
 		panic("index out of bounds");
 	}
 
@@ -205,13 +214,13 @@
 
 
 func (L *List) Clear() {
-	L.len_, L.first, L.last = 0, nil, nil;
+	L.len, L.first, L.last = 0, nil, nil;
 }
 
 
 func (L *List) Add() *Elem {
-	L.len_++;
-	e := new(*Elem);
+	L.len++;
+	e := new(Elem);
 	if L.first == nil {
 		L.first = e;
 	} else {
@@ -242,6 +251,11 @@
 }
 
 
+func (L *List) ExprAt(i int) Expr {
+	return L.at(i).expr;
+}
+
+
 func (L *List) AddInt(val int) {
 	L.Add().val = val;
 }
@@ -280,18 +294,23 @@
 }
 
 
+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.entries.AddObj(obj);
+	scope.Add(obj);
 }
 
 
 func (scope *Scope) InsertImport(obj *Object) *Object {
 	 p := scope.Lookup(obj.ident);
 	 if p == nil {
-		scope.Insert(obj);
+		scope.Add(obj);
 		p = obj;
 	 }
 	 return p;
diff --git a/usr/gri/gosrc/go.go b/usr/gri/gosrc/go.go
index 537c327..f1e67bc 100644
--- a/usr/gri/gosrc/go.go
+++ b/usr/gri/gosrc/go.go
@@ -20,10 +20,6 @@
 		"  -p             print package interface\n" +
 		"  -v [0 .. 3]    verbosity level\n" +
 		"  -6g            6g compatibility mode\n" +
-		"  -scan          scan only, print tokens\n" +
-		"  -parse         parse only, print productions\n" +
-		"  -ast           analyse only, print ast\n" +
-		"  -deps          print package dependencies\n" +
 		"  -token_chan    use token channel to scan and parse in parallel\n"
 	);
 }
@@ -49,7 +45,7 @@
 	}
 
 	// collect flags and files
-	flags := new(*Globals.Flags);
+	flags := new(Globals.Flags);
 	files := Globals.NewList();
 	for arg != "" {
 	    switch arg {
@@ -69,13 +65,6 @@
 				continue;
 			}
 		case "-6g": flags.sixg = true;
-		case "-scan": flags.scan = true;
-			print("note: -scan flag ignored at the moment\n");
-		case "-parse": flags.parse = true;
-			print("note: -parse flag ignored at the moment\n");
-		case "-ast": flags.ast = true;
-		case "-deps": flags.deps = true;
-			print("note: -deps flag ignored at the moment\n");
 		case "-token_chan": flags.token_chan = true;
 		default: files.AddStr(arg);
 		}
@@ -83,7 +72,8 @@
 	}
 
 	// setup environment
-	env := new(*Globals.Environment);
+	env := new(Globals.Environment);
+	env.Error = &Compilation.Error;
 	env.Import = &Compilation.Import;
 	env.Export = &Compilation.Export;
 	env.Compile = &Compilation.Compile;
@@ -91,7 +81,7 @@
 	// compile files
 	for p := files.first; p != nil; p = p.next {
 		// setup compilation
-		comp := new(*Globals.Compilation);
+		comp := new(Globals.Compilation);
 		comp.flags = flags;
 		comp.env = env;
 
diff --git a/usr/gri/gosrc/import.go b/usr/gri/gosrc/import.go
index b947c51..104f3d7 100755
--- a/usr/gri/gosrc/import.go
+++ b/usr/gri/gosrc/import.go
@@ -200,24 +200,32 @@
 	I.type_ref++;
 
 	switch (typ.form) {
+	case Type.VOID:
+		// for now until we have enough of the front-end working
+		// change the form to BAD to avoid error messages
+		typ.form = Type.BAD;
+		
 	case Type.FORWARD:
 		typ.scope = Globals.NewScope(nil);
-		break;
+		
+	case Type.TUPLE:
+		typ.elt = I.ReadType();
 		
 	case Type.ALIAS, Type.MAP:
-		typ.aux = I.ReadType();
+		typ.key = I.ReadType();
 		typ.elt = I.ReadType();
 
 	case Type.ARRAY:
-		typ.len_ = I.ReadInt();
+		typ.len = I.ReadInt();
 		typ.elt = I.ReadType();
 
 	case Type.CHANNEL:
-		typ.flags = I.ReadInt();
+		typ.aux = I.ReadInt();
 		typ.elt = I.ReadType();
 
-	case Type.FUNCTION:
-		typ.flags = I.ReadInt();
+	case Type.FUNCTION, Type.METHOD:
+		typ.len = I.ReadInt();
+		typ.elt = I.ReadType();
 		typ.scope = Globals.NewScope(nil);
 		I.ReadScope(typ.scope, false);
 
@@ -225,7 +233,7 @@
 		typ.scope = Globals.NewScope(nil);
 		I.ReadScope(typ.scope, false);
 
-	case Type.POINTER, Type.REFERENCE:
+	case Type.POINTER:
 		typ.elt = I.ReadType();
 
 	default:
diff --git a/usr/gri/gosrc/object.go b/usr/gri/gosrc/object.go
index 81fab9a..220f4c8 100755
--- a/usr/gri/gosrc/object.go
+++ b/usr/gri/gosrc/object.go
@@ -9,7 +9,7 @@
 
 export const /* kind */ (
 	BAD = iota;  // error handling
-	CONST; TYPE; VAR; FIELD; FUNC; PACKAGE; LABEL;
+	CONST; TYPE; VAR; FIELD; FUNC; BUILTIN; PACKAGE; LABEL;
 	END;  // end of scope (import/export only)
 )
 
@@ -27,6 +27,7 @@
 	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";
diff --git a/usr/gri/gosrc/parser.go b/usr/gri/gosrc/parser.go
index 06a51b6..4ba0d99 100644
--- a/usr/gri/gosrc/parser.go
+++ b/usr/gri/gosrc/parser.go
@@ -12,16 +12,16 @@
 import Universe "universe"
 import Import "import"
 import AST "ast"
+import Expr "expr"
 
 
 export type Parser struct {
 	comp *Globals.Compilation;
-	semantic_checks bool;
 	verbose bool;
 	indent uint;
-	S *Scanner.Scanner;
-	C chan *Scanner.Token;
-
+	scanner *Scanner.Scanner;
+	tokchan chan *Scanner.Token;
+	
 	// Token
 	tok int;  // one token look-ahead
 	pos int;  // token source position
@@ -50,12 +50,12 @@
 		P.PrintIndent();
 		print(msg, " {\n");
 	}
-	P.indent++;
+	P.indent++;  // always, so proper identation is always checked
 }
 
 
 func (P *Parser) Ecart() {
-	P.indent--;
+	P.indent--;  // always, so proper identation is always checked
 	if P.verbose {
 		P.PrintIndent();
 		print("}\n");
@@ -64,10 +64,10 @@
 
 
 func (P *Parser) Next() {
-	if P.C == nil {
-		P.tok, P.pos, P.val = P.S.Scan();
+	if P.tokchan == nil {
+		P.tok, P.pos, P.val = P.scanner.Scan();
 	} else {
-		t := <- P.C;
+		t := <- P.tokchan;
 		P.tok, P.pos, P.val = t.tok, t.pos, t.val;
 	}
 	if P.verbose {
@@ -77,13 +77,12 @@
 }
 
 
-func (P *Parser) Open(comp *Globals.Compilation, S *Scanner.Scanner, C chan *Scanner.Token) {
+func (P *Parser) Open(comp *Globals.Compilation, scanner *Scanner.Scanner, tokchan chan *Scanner.Token) {
 	P.comp = comp;
-	P.semantic_checks = comp.flags.ast;
 	P.verbose = comp.flags.verbosity > 2;
 	P.indent = 0;
-	P.S = S;
-	P.C = C;
+	P.scanner = scanner;
+	P.tokchan = tokchan;
 	P.Next();
 	P.level = 0;
 	P.top_scope = Universe.scope;
@@ -93,7 +92,7 @@
 
 
 func (P *Parser) Error(pos int, msg string) {
-	P.S.Error(pos, msg);
+	P.scanner.Error(pos, msg);
 }
 
 
@@ -137,9 +136,6 @@
 
 
 func (P *Parser) DeclareInScope(scope *Globals.Scope, obj *Globals.Object) {
-	if !P.semantic_checks {
-		return;
-	}
 	if P.level > 0 {
 		panic("cannot declare objects in other packages");
 	}
@@ -157,27 +153,32 @@
 }
 
 
-func MakeFunctionType(sig *Globals.Scope, p0, r0 int, check_recv bool) *Globals.Type {
-	// Determine if we have a receiver or not.
-	// TODO do we still need this?
-	if p0 > 0 && check_recv {
-		// method
-		if p0 != 1 {
-			panic("p0 != 1");
+func MakeFunctionType(sig *Globals.Scope, p0, r0 int) *Globals.Type {
+	form := Type.FUNCTION;
+	if p0 == 1 {
+		form = Type.METHOD;
+	} else {
+		if p0 != 0 {
+			panic("incorrect p0");
 		}
 	}
-
-	typ := Globals.NewType(Type.FUNCTION);
-	if p0 == 0 {
-		typ.flags = 0;
-	} else {
-		typ.flags = Type.RECV;
-	}
-	typ.len_ = r0 - p0;
+	typ := Globals.NewType(form);
+	typ.len = r0 - p0;
 	typ.scope = sig;
 
-	// parameters are always exported (they can't be accessed w/o the function
-	// or function type being exported)
+	// set result type
+	if sig.entries.len - r0 == 1 {
+		// exactly one result value
+		typ.elt = sig.entries.last.obj.typ;
+	} else {
+		// 0 or >1 result values - create a tuple referring to this type
+		tup := Globals.NewType(Type.TUPLE);
+		tup.elt = typ;
+		typ.elt = tup;
+	}
+
+	// parameters/results are always exported (they can't be accessed
+	// w/o the function or function type being exported)
 	for p := sig.entries.first; p != nil; p = p.next {
 		p.obj.exported = true;
 	}
@@ -189,9 +190,9 @@
 func (P *Parser) DeclareFunc(pos int, ident string, typ *Globals.Type) *Globals.Object {
 	// determine scope
 	scope := P.top_scope;
-	if typ.flags & Type.RECV != 0 {
-		// method - declare in corresponding struct
-		if typ.scope.entries.len_ < 1 {
+	if typ.form == Type.METHOD {
+		// declare in corresponding struct
+		if typ.scope.entries.len < 1 {
 			panic("no recv in signature?");
 		}
 		recv_typ := typ.scope.entries.first.obj.typ;
@@ -213,7 +214,7 @@
 
 	// obj != NULL: possibly a forward declaration
 	if obj.kind != Object.FUNC {
-		P.Error(-1, `"` + ident + `" is declared already`);
+		P.Error(pos, `"` + ident + `" is declared already`);
 		// continue but do not insert this function into the scope
 		obj = Globals.NewObject(-1, Object.FUNC, ident);
 		obj.typ = typ;
@@ -313,43 +314,31 @@
 		pos, ident = P.ParseIdent(false);
 	}
 
-	if P.semantic_checks {
-		obj := P.Lookup(ident);
-		if obj == nil {
-			P.Error(pos, `"` + ident + `" is not declared`);
-			obj = Globals.NewObject(pos, Object.BAD, ident);
-		}
-
-		if obj.kind == Object.PACKAGE && P.tok == Scanner.PERIOD {
-			if obj.pnolev < 0 {
-				panic("obj.pnolev < 0");
-			}
-			pkg := P.comp.pkg_list[obj.pnolev];
-			//if pkg.obj.ident != ident {
-			//	panic("pkg.obj.ident != ident");
-			//}
-			P.Next();  // consume "."
-			pos, ident = P.ParseIdent(false);
-			obj = pkg.scope.Lookup(ident);
-			if obj == nil {
-				P.Error(pos, `"` + ident + `" is not declared in package "` + pkg.obj.ident + `"`);
-				obj = Globals.NewObject(pos, Object.BAD, ident);
-			}
-		}
-
-		P.Ecart();
-		return obj;
-
-	} else {
-		if P.tok == Scanner.PERIOD {
-			P.Next();
-			P.ParseIdent(false);
-		}
-		P.Ecart();
-		return nil;
+	obj := P.Lookup(ident);
+	if obj == nil {
+		P.Error(pos, `"` + ident + `" is not declared`);
+		obj = Globals.NewObject(pos, Object.BAD, ident);
 	}
 
-	panic("UNREACHABLE");
+	if obj.kind == Object.PACKAGE && P.tok == Scanner.PERIOD {
+		if obj.pnolev < 0 {
+			panic("obj.pnolev < 0");
+		}
+		pkg := P.comp.pkg_list[obj.pnolev];
+		//if pkg.obj.ident != ident {
+		//	panic("pkg.obj.ident != ident");
+		//}
+		P.Next();  // consume "."
+		pos, ident = P.ParseIdent(false);
+		obj = pkg.scope.Lookup(ident);
+		if obj == nil {
+			P.Error(pos, `"` + ident + `" is not declared in package "` + pkg.obj.ident + `"`);
+			obj = Globals.NewObject(pos, Object.BAD, ident);
+		}
+	}
+
+	P.Ecart();
+	return obj;
 }
 
 
@@ -376,19 +365,17 @@
 	pos := P.pos;
 	typ := P.ParseType();
 
-	if P.semantic_checks {
-		switch typ.form {
-		case Type.ARRAY:
-			if P.comp.flags.sixg || typ.len_ >= 0 {
-				break;
-			}
-			// open arrays must be pointers
-			fallthrough;
-
-		case Type.MAP, Type.CHANNEL, Type.FUNCTION:
-			P.Error(pos, "must be pointer to this type");
-			typ = Universe.bad_t;
+	switch typ.form {
+	case Type.ARRAY:
+		if P.comp.flags.sixg || typ.len >= 0 {
+			break;
 		}
+		// open arrays must be pointers
+		fallthrough;
+		
+	case Type.MAP, Type.CHANNEL, Type.FUNCTION:
+		P.Error(pos, "must be pointer to this type");
+		typ = Universe.bad_t;
 	}
 
 	P.Ecart();
@@ -399,23 +386,16 @@
 func (P *Parser) ParseTypeName() *Globals.Type {
 	P.Trace("TypeName");
 
-	if P.semantic_checks {
-		pos := P.pos;
-		obj := P.ParseQualifiedIdent(-1, "");
-		typ := obj.typ;
-		if obj.kind != Object.TYPE {
-			P.Error(pos, "qualified identifier does not denote a type");
-			typ = Universe.bad_t;
-		}
-		P.Ecart();
-		return typ;
-	} else {
-		P.ParseQualifiedIdent(-1, "");
-		P.Ecart();
-		return Universe.bad_t;
+	pos := P.pos;
+	obj := P.ParseQualifiedIdent(-1, "");
+	typ := obj.typ;
+	if obj.kind != Object.TYPE {
+		P.Error(pos, "qualified identifier does not denote a type");
+		typ = Universe.bad_t;
 	}
 
-	panic("UNREACHABLE");
+	P.Ecart();
+	return typ;
 }
 
 
@@ -425,7 +405,7 @@
 	P.Expect(Scanner.LBRACK);
 	typ := Globals.NewType(Type.ARRAY);
 	if P.tok != Scanner.RBRACK {
-		// TODO set typ.len_
+		// TODO set typ.len
 		P.ParseExpression();
 	}
 	P.Expect(Scanner.RBRACK);
@@ -443,15 +423,15 @@
 	if P.tok == Scanner.CHAN {
 		P.Next();
 		if P.tok == Scanner.ARROW {
-			typ.flags = Type.SEND;
+			typ.aux = Type.SEND;
 			P.Next();
 		} else {
-			typ.flags = Type.SEND + Type.RECV;
+			typ.aux = Type.SEND + Type.RECV;
 		}
 	} else {
 		P.Expect(Scanner.ARROW);
 		P.Expect(Scanner.CHAN);
-		typ.flags = Type.RECV;
+		typ.aux = Type.RECV;
 	}
 	typ.elt = P.ParseVarType();
 
@@ -499,61 +479,51 @@
 }
 
 
-func (P *Parser) TryResult() bool {
-	P.Trace("Result (try)");
+func (P *Parser) ParseResult() {
+	P.Trace("Result");
 
-	res := false;
 	if P.tok == Scanner.LPAREN {
+		// one or more named results
 		// TODO: here we allow empty returns - should proably fix this
 		P.ParseParameters();
-		res = true;
-	} else {
-		res = P.TryType() != nil;
-	}
-	P.Ecart();
 
-	return res;
+	} else {
+		// anonymous result
+		pos := P.pos;
+		typ := P.TryType();
+		if typ != nil {
+			obj := Globals.NewObject(pos, Object.VAR, ".res");
+			obj.typ = typ;
+			P.Declare(obj);
+		}
+	}
+
+	P.Ecart();
 }
 
 
-// Anonymous signatures
+// Signatures
 //
-//          (params)
-//          (params) type
-//          (params) (results)
-// (recv) . (params)
-// (recv) . (params) type
-// (recv) . (params) (results)
+// (params)
+// (params) type
+// (params) (results)
 
-func (P *Parser) ParseAnonymousSignature() *Globals.Type {
-	P.Trace("AnonymousSignature");
+func (P *Parser) ParseSignature() *Globals.Type {
+	P.Trace("Signature");
 
 	P.OpenScope();
 	P.level--;
 	sig := P.top_scope;
-	p0 := 0;
 
-	recv_pos := P.pos;
 	P.ParseParameters();
+	r0 := sig.entries.len;
+	P.ParseResult();
 
-	if P.tok == Scanner.PERIOD {
-		p0 = sig.entries.len_;
-		if P.semantic_checks && p0 != 1 {
-			P.Error(recv_pos, "must have exactly one receiver");
-			panic("UNIMPLEMENTED (ParseAnonymousSignature)");
-			// TODO do something useful here
-		}
-		P.Next();
-		P.ParseParameters();
-	}
-
-	r0 := sig.entries.len_;
-	P.TryResult();
 	P.level++;
 	P.CloseScope();
 
 	P.Ecart();
-	return MakeFunctionType(sig, p0, r0, true);
+	return MakeFunctionType(sig, 0, r0);
 }
 
 
@@ -577,8 +547,8 @@
 	if P.tok == Scanner.LPAREN {
 		recv_pos := P.pos;
 		P.ParseParameters();
-		p0 = sig.entries.len_;
-		if P.semantic_checks && p0 != 1 {
+		p0 = sig.entries.len;
+		if p0 != 1 {
 			print("p0 = ", p0, "\n");
 			P.Error(recv_pos, "must have exactly one receiver");
 			panic("UNIMPLEMENTED (ParseNamedSignature)");
@@ -590,20 +560,20 @@
 
 	P.ParseParameters();
 
-	r0 := sig.entries.len_;
-	P.TryResult();
+	r0 := sig.entries.len;
+	P.ParseResult();
 	P.level++;
 	P.CloseScope();
 
 	P.Ecart();
-	return pos, ident, MakeFunctionType(sig, p0, r0, true);
+	return pos, ident, MakeFunctionType(sig, p0, r0);
 }
 
 
 func (P *Parser) ParseFunctionType() *Globals.Type {
 	P.Trace("FunctionType");
 
-	typ := P.ParseAnonymousSignature();
+	typ := P.ParseSignature();
 
 	P.Ecart();
 	return typ;
@@ -625,14 +595,14 @@
 
 	P.ParseParameters();
 
-	r0 := sig.entries.len_;
-	P.TryResult();
+	r0 := sig.entries.len;
+	P.ParseResult();
 	P.level++;
 	P.CloseScope();
 	P.Optional(Scanner.SEMICOLON);
 
 	obj := Globals.NewObject(pos, Object.FUNC, ident);
-	obj.typ = MakeFunctionType(sig, 1, r0, true);
+	obj.typ = MakeFunctionType(sig, 1, r0);
 	P.Declare(obj);
 
 	P.Ecart();
@@ -666,7 +636,7 @@
 	P.Expect(Scanner.MAP);
 	P.Expect(Scanner.LBRACK);
 	typ := Globals.NewType(Type.MAP);
-	typ.aux = P.ParseVarType();
+	typ.key = P.ParseVarType();
 	P.Expect(Scanner.RBRACK);
 	typ.elt = P.ParseVarType();
 	P.Ecart();
@@ -707,82 +677,80 @@
 	typ := Globals.NewType(Type.POINTER);
 
 	var elt *Globals.Type;
-	if P.semantic_checks {
-		if P.tok == Scanner.STRING && !P.comp.flags.sixg {
-			// implicit package.type forward declaration
-			// TODO eventually the scanner should strip the quotes
-			pkg_name := P.val[1 : len(P.val) - 1];  // strip quotes
-			pkg := P.comp.Lookup(pkg_name);
-			if pkg == nil {
-				// package doesn't exist yet - add it to the package list
-				obj := Globals.NewObject(P.pos, Object.PACKAGE, ".pkg");
-				pkg = Globals.NewPackage(pkg_name, obj, Globals.NewScope(nil));
-				pkg.key = "";  // mark as forward-declared package
-				P.comp.Insert(pkg);
-			} else {
-				// package exists already - must be forward declaration
-				if pkg.key != "" {
-					P.Error(P.pos, `cannot use implicit package forward declaration for imported package "` + P.val + `"`);
-					panic("wrong package forward decl");
-					// TODO introduce dummy package so we can continue safely
-				}
+	if P.tok == Scanner.STRING && !P.comp.flags.sixg {
+		// implicit package.type forward declaration
+		// TODO eventually the scanner should strip the quotes
+		pkg_name := P.val[1 : len(P.val) - 1];  // strip quotes
+		pkg := P.comp.Lookup(pkg_name);
+		if pkg == nil {
+			// package doesn't exist yet - add it to the package list
+			obj := Globals.NewObject(P.pos, Object.PACKAGE, ".pkg");
+			pkg = Globals.NewPackage(pkg_name, obj, Globals.NewScope(nil));
+			pkg.key = "";  // mark as forward-declared package
+			P.comp.Insert(pkg);
+		} else {
+			// package exists already - must be forward declaration
+			if pkg.key != "" {
+				P.Error(P.pos, `cannot use implicit package forward declaration for imported package "` + P.val + `"`);
+				panic("wrong package forward decl");
+				// TODO introduce dummy package so we can continue safely
 			}
-
-			P.Next();  // consume package name
-			P.Expect(Scanner.PERIOD);
+		}
+		
+		P.Next();  // consume package name
+		P.Expect(Scanner.PERIOD);
+		pos, ident := P.ParseIdent(false);
+		obj := pkg.scope.Lookup(ident);
+		if obj == nil {
+			elt = Globals.NewType(Type.FORWARD);
+			elt.scope = P.top_scope;  // not really needed here, but for consistency
+			obj = Globals.NewObject(pos, Object.TYPE, ident);
+			obj.exported = true;  // the type name must be visible
+			obj.typ = elt;
+			elt.obj = obj;  // primary type object;
+			pkg.scope.Insert(obj);
+			obj.pnolev = pkg.obj.pnolev;
+		} else {
+			if obj.kind != Object.TYPE || obj.typ.form != Type.FORWARD {
+				panic("inconsistency in package.type forward declaration");
+			}
+			elt = obj.typ;
+		}
+		
+	} else if P.tok == Scanner.IDENT {
+		if P.Lookup(P.val) == nil {
+			// implicit type forward declaration
+			// create a named forward type 
 			pos, ident := P.ParseIdent(false);
-			obj := pkg.scope.Lookup(ident);
-			if obj == nil {
-				elt = Globals.NewType(Type.FORWARD);
-				elt.scope = P.top_scope;  // not really needed here, but for consistency
-				obj = Globals.NewObject(pos, Object.TYPE, ident);
-				obj.exported = true;  // the type name must be visible
-				obj.typ = elt;
-				elt.obj = obj;  // primary type object;
-				pkg.scope.Insert(obj);
-				obj.pnolev = pkg.obj.pnolev;
-			} else {
-				if obj.kind != Object.TYPE || obj.typ.form != Type.FORWARD {
-					panic("inconsistency in package.type forward declaration");
-				}
-				elt = obj.typ;
-			}
+			obj := Globals.NewObject(pos, Object.TYPE, ident);
+			elt = Globals.NewType(Type.FORWARD);
+			obj.typ = elt;
+			elt.obj = obj;  // primary type object;
+			// remember the current scope - resolving the forward
+			// type must find a matching declaration in this or a less nested scope
+			elt.scope = P.top_scope;
 
-		} else if P.tok == Scanner.IDENT {
-			if P.Lookup(P.val) == nil {
-				// implicit type forward declaration
 				// create a named forward type
-				pos, ident := P.ParseIdent(false);
-				obj := Globals.NewObject(pos, Object.TYPE, ident);
-				elt = Globals.NewType(Type.FORWARD);
-				obj.typ = elt;
-				elt.obj = obj;  // primary type object;
-				// remember the current scope - resolving the forward
-				// type must find a matching declaration in this or a less nested scope
-				elt.scope = P.top_scope;
-
-			} else {
-				// type name
-				// (ParseType() (via TryType()) checks for forward types and complains,
-				// so call ParseTypeName() directly)
-				// we can only have a foward type here if we refer to the name of a
-				// yet incomplete type (i.e. if we are in the middle of a type's declaration)
-				elt = P.ParseTypeName();
-			}
-
-			// collect uses of pointer types referring to forward types
-			if elt.form == Type.FORWARD {
-				P.forward_types.AddTyp(typ);
-			}
 
 		} else {
-			elt = P.ParseType();
+			// type name
+			// (ParseType() (via TryType()) checks for forward types and complains,
+			// so call ParseTypeName() directly)
+			// we can only have a foward type here if we refer to the name of a
+			// yet incomplete type (i.e. if we are in the middle of a type's declaration)
+			elt = P.ParseTypeName();
+		}
+
+		// collect uses of pointer types referring to forward types
+		if elt.form == Type.FORWARD {
+			P.forward_types.AddTyp(typ);
 		}
 
 	} else {
 		elt = P.ParseType();
 	}
 
+
 	typ.elt = elt;
 
 	P.Ecart();
@@ -892,24 +860,6 @@
 }
 
 
-func (P *Parser) ParseNew() Globals.Expr {
-	P.Trace("New");
-
-	P.Expect(Scanner.NEW);
-	P.Expect(Scanner.LPAREN);
-	P.ParseType();
-	args := Globals.NewList();
-	if P.tok == Scanner.COMMA {
-		P.Next();
-		P.ParseExpressionList(args)
-	}
-	P.Expect(Scanner.RPAREN);
-
-	P.Ecart();
-	return nil;
-}
-
-
 func (P *Parser) ParseFunctionLit() Globals.Expr {
 	P.Trace("FunctionLit");
 
@@ -989,13 +939,12 @@
 	var res Globals.Expr = AST.Bad;
 
 	if pos >= 0 {
+		// we have an identifier
 		obj := P.ParseQualifiedIdent(pos, ident);
-		if P.semantic_checks {
-			if obj.kind == Object.TYPE {
-				res = P.ParseCompositeLit(obj.typ);
-			} else {
-				res = AST.NewObject(pos, obj);
-			}
+		if obj.kind == Object.TYPE && P.tok == Scanner.LBRACE {
+			res = P.ParseCompositeLit(obj.typ);
+		} else {
+			res = AST.NewObject(pos, obj);
 		}
 
 	} else {
@@ -1027,30 +976,8 @@
 			res = x;
 			P.Next();
 
-		case Scanner.NIL:
-			P.Next();
-			res = AST.Nil;
-
-		case Scanner.IOTA:
-			x := AST.NewLiteral(P.pos, Universe.int_t);
-			x.i = 42;  // TODO set the right value
-			res = x;
-			P.Next();
-
-		case Scanner.TRUE:
-			P.Next();
-			res = AST.True;
-
-		case Scanner.FALSE:
-			P.Next();
-			res = AST.False;
-
 		case Scanner.FUNC:
 			res = P.ParseFunctionLit();
-
-		case Scanner.NEW:
-			res = P.ParseNew();
-
 		default:
 			typ := P.TryType();
 			if typ != nil {
@@ -1071,40 +998,17 @@
 func (P *Parser) ParseSelectorOrTypeAssertion(x Globals.Expr) Globals.Expr {
 	P.Trace("SelectorOrTypeAssertion");
 
-	period_pos := P.pos;
 	P.Expect(Scanner.PERIOD);
-
+	pos := P.pos;
+	
 	if P.tok >= Scanner.IDENT {
-		ident_pos, ident := P.ParseIdent(true);
-
-		if P.semantic_checks {
-			switch typ := x.typ(); typ.form {
-			case Type.BAD:
-				// ignore
-				break;
-			case Type.STRUCT, Type.INTERFACE:
-				obj := typ.scope.Lookup(ident);
-				if obj != nil {
-					x = AST.NewSelector(x.pos(), obj.typ);
-
-				} else {
-					P.Error(ident_pos, `no field/method "` + ident + `"`);
-					x = AST.Bad;
-				}
-			default:
-				P.Error(period_pos, `"." not applicable`);
-				x = AST.Bad;
-			}
-		}
-
+		pos, selector := P.ParseIdent(true);
+		x = Expr.Select(P.comp, x, pos, selector);
 	} else {
 		P.Expect(Scanner.LPAREN);
-		P.ParseType();
+		typ := P.ParseType();
 		P.Expect(Scanner.RPAREN);
-
-		if P.semantic_checks {
-			panic("UNIMPLEMENTED");
-		}
+		x = Expr.AssertType(P.comp, x, pos, typ);
 	}
 
 	P.Ecart();
@@ -1115,41 +1019,17 @@
 func (P *Parser) ParseIndexOrSlice(x Globals.Expr) Globals.Expr {
 	P.Trace("IndexOrSlice");
 
-	pos := P.pos;
 	P.Expect(Scanner.LBRACK);
-	i1 := P.ParseExpression();
-	var i2 Globals.Expr;
+	i := P.ParseExpression();
 	if P.tok == Scanner.COLON {
 		P.Next();
-		i2 := P.ParseExpression();
+		j := P.ParseExpression();
+		x = Expr.Slice(P.comp, x, i, j);
+	} else {
+		x = Expr.Index(P.comp, x, i);
 	}
 	P.Expect(Scanner.RBRACK);
 
-	if P.semantic_checks {
-		switch typ := x.typ(); typ.form {
-		case Type.BAD:
-			// ignore
-			break;
-		case Type.STRING, Type.ARRAY:
-			panic("UNIMPLEMENTED");
-
-		case Type.MAP:
-			if Type.Equal(typ.aux, i1.typ()) {
-				// x = AST.NewSubscript(x, i1);
-				panic("UNIMPLEMENTED");
-
-			} else {
-				P.Error(x.pos(), "map key type mismatch");
-				x = AST.Bad;
-			}
-
-		default:
-			P.Error(pos, `"[]" not applicable`);
-			x = AST.Bad;
-		}
-
-	}
-
 	P.Ecart();
 	return x;
 }
@@ -1164,10 +1044,7 @@
 		P.ParseExpressionList(args);
 	}
 	P.Expect(Scanner.RPAREN);
-
-	if P.semantic_checks {
-		panic("UNIMPLEMENTED");
-	}
+	x = Expr.Call(P.comp, x, args);
 
 	P.Ecart();
 	return x;
@@ -1221,14 +1098,15 @@
 	case Scanner.ARROW: fallthrough;
 	case Scanner.AND:
 		P.Next();
-		P.ParseUnaryExpr();
+		x := P.ParseUnaryExpr();
 		P.Ecart();
-		return nil;  // TODO fix this
+		return x;  // TODO fix this
 	}
-	P.ParsePrimaryExpr(-1, "");
+	
+	x := P.ParsePrimaryExpr(-1, "");
 
 	P.Ecart();
-	return nil;  // TODO fix this
+	return x;  // TODO fix this
 }
 
 
@@ -1261,15 +1139,12 @@
 	} else {
 		x = P.ParseUnaryExpr();
 	}
+
 	for prec := Precedence(P.tok); prec >= prec1; prec-- {
 		for Precedence(P.tok) == prec {
-			e := new(*AST.BinaryExpr);
-			e.typ_ = Universe.bad_t;  // TODO fix this
-			e.op = P.tok;  // TODO should we use tokens or separate operator constants?
-			e.x = x;
 			P.Next();
-			e.y = P.ParseBinaryExpr(-1, "", prec + 1);
-			x = e;
+			y := P.ParseBinaryExpr(-1, "", prec + 1);
+			x = Expr.BinaryExpr(P.comp, x, y);
 		}
 	}
 
@@ -1309,17 +1184,19 @@
 // Statements
 
 func (P *Parser) ConvertToExprList(pos_list, ident_list, expr_list *Globals.List) {
+	if pos_list.len != ident_list.len {
+		panic("inconsistent lists");
+	}
 	for p, q := pos_list.first, ident_list.first; q != nil; p, q = p.next, q.next {
 		pos, ident := p.val, q.str;
-		if P.semantic_checks {
-			obj := P.Lookup(ident);
-			if obj == nil {
-				P.Error(pos, `"` + ident + `" is not declared`);
-				obj = Globals.NewObject(pos, Object.BAD, ident);
-			}
+		obj := P.Lookup(ident);
+		if obj == nil {
+			P.Error(pos, `"` + ident + `" is not declared`);
+			obj = Globals.NewObject(pos, Object.BAD, ident);
 		}
-		expr_list.AddInt(0);  // TODO fix this - add correct expression
+		expr_list.AddExpr(AST.NewObject(pos, obj));
 	}
+	pos_list.Clear();
 	ident_list.Clear();
 }
 
@@ -1327,10 +1204,9 @@
 func (P *Parser) ParseIdentOrExpr(pos_list, ident_list, expr_list *Globals.List) {
 	P.Trace("IdentOrExpr");
 
-	pos_list.AddInt(P.pos);
 	pos, ident := -1, "";
 	just_ident := false;
-	if expr_list.len_ == 0 /* only idents so far */ && P.tok == Scanner.IDENT {
+	if expr_list.len == 0 /* only idents so far */ && P.tok == Scanner.IDENT {
 		pos, ident = P.pos, P.val;
 		P.Next();
 		switch P.tok {
@@ -1348,17 +1224,17 @@
 			Scanner.XOR_ASSIGN,
 			Scanner.SHL_ASSIGN,
 			Scanner.SHR_ASSIGN:
-			// identifier is not part of a more complicated expression
+			// identifier is *not* part of a more complicated expression
 			just_ident = true;
 		}
 	}
 
 	if just_ident {
+		pos_list.AddInt(pos);
 		ident_list.AddStr(ident);
 	} else {
 		P.ConvertToExprList(pos_list, ident_list, expr_list);
-		P.ParseIdentExpression(pos, ident);
-		expr_list.AddInt(0);  // TODO fix this - add correct expression
+		expr_list.AddExpr(P.ParseIdentExpression(pos, ident));
 	}
 
 	P.Ecart();
@@ -1368,7 +1244,9 @@
 func (P *Parser) ParseIdentOrExprList() (pos_list, ident_list, expr_list *Globals.List) {
 	P.Trace("IdentOrExprList");
 
-	pos_list, ident_list, expr_list = Globals.NewList(), Globals.NewList(), Globals.NewList();
+	pos_list, ident_list = Globals.NewList(), Globals.NewList();  // "pairs" of (pos, ident)
+	expr_list = Globals.NewList();
+	
 	P.ParseIdentOrExpr(pos_list, ident_list, expr_list);
 	for P.tok == Scanner.COMMA {
 		P.Next();
@@ -1380,6 +1258,26 @@
 }
 
 
+// Compute the number of individual values provided by the expression list.
+func (P *Parser) ListArity(list *Globals.List) int {
+	if list.len == 1 {
+		x := list.ExprAt(0);
+		if x.op() == AST.CALL {
+			panic("UNIMPLEMENTED");
+		}
+		return 1;
+	} else {
+		for p := list.first; p != nil; p = p.next {
+			x := p.expr;
+			if x.op() == AST.CALL {
+				panic("UNIMPLEMENTED");
+			}
+		}
+	}
+	panic("UNREACHABLE");
+}
+
+
 func (P *Parser) ParseSimpleStat() {
 	P.Trace("SimpleStat");
 
@@ -1389,37 +1287,38 @@
 	// Strategy: We parse an expression list, but simultaneously, as
 	// long as possible, maintain a list of identifiers which is converted
 	// into an expression list only if neccessary. The result of
-	// ParseIdentOrExprList is a list of ident/expr positions and either
-	// a non-empty list of identifiers or a non-empty list of expressions
+	// ParseIdentOrExprList is a pair of non-empty lists of identfiers and
+	// their respective source positions, or a non-empty list of expressions
 	// (but not both).
 	pos_list, ident_list, expr_list := P.ParseIdentOrExprList();
 
 	switch P.tok {
 	case Scanner.COLON:
 		// label declaration
-		if P.semantic_checks && ident_list.len_ != 1 {
+		if ident_list.len == 1 {
+			obj := Globals.NewObject(pos_list.first.val, Object.LABEL, ident_list.first.str);
+			P.Declare(obj);
+		} else {
 			P.Error(P.pos, "illegal label declaration");
 		}
-		P.Next();
+		P.Next();  // consume ":"
 
 	case Scanner.DEFINE:
 		// variable declaration
-		if P.semantic_checks && ident_list.len_ == 0 {
+		if ident_list.len == 0 {
 			P.Error(P.pos, "illegal left-hand side for declaration");
 		}
-		P.Next();
-		pos := P.pos;
+		P.Next();  // consume ":="
 		val_list := P.ParseNewExpressionList();
-		if P.semantic_checks && val_list.len_ != ident_list.len_ {
-			P.Error(pos, "number of expressions does not match number of variables");
+		if val_list.len != ident_list.len {
+			P.Error(val_list.first.expr.pos(), "number of expressions does not match number of variables");
 		}
 		// declare variables
-		if P.semantic_checks {
-			for p, q := pos_list.first, ident_list.first; q != nil; p, q = p.next, q.next {
-				obj := Globals.NewObject(p.val, Object.VAR, q.str);
-				P.Declare(obj);
-				// TODO set correct types
-			}
+		for p, q := pos_list.first, ident_list.first; q != nil; p, q = p.next, q.next {
+			obj := Globals.NewObject(p.val, Object.VAR, q.str);
+			P.Declare(obj);
+			// TODO set correct types
+			obj.typ = Universe.bad_t;  // for now
 		}
 
 	case Scanner.ASSIGN: fallthrough;
@@ -1437,13 +1336,23 @@
 		P.Next();
 		pos := P.pos;
 		val_list := P.ParseNewExpressionList();
-		if P.semantic_checks && val_list.len_ != expr_list.len_ {
-			P.Error(pos, "number of expressions does not match number of variables");
+		
+		// assign variables
+		if val_list.len == 1 && val_list.first.expr.typ().form == Type.TUPLE {
+			panic("UNIMPLEMENTED");
+		} else {
+			var p, q *Globals.Elem;
+			for p, q = expr_list.first, val_list.first; p != nil && q != nil; p, q = p.next, q.next {
+				
+			}
+			if p != nil || q != nil {
+				P.Error(pos, "number of expressions does not match number of variables");
+			}
 		}
 
 	default:
 		P.ConvertToExprList(pos_list, ident_list, expr_list);
-		if P.semantic_checks && expr_list.len_ != 1 {
+		if expr_list.len != 1 {
 			P.Error(P.pos, "no expression list allowed");
 		}
 		if P.tok == Scanner.INC || P.tok == Scanner.DEC {
@@ -1739,11 +1648,9 @@
 		obj = P.ParseIdentDecl(Object.PACKAGE);
 	}
 
-	if P.semantic_checks && P.tok == Scanner.STRING {
+	if P.tok == Scanner.STRING {
 		// TODO eventually the scanner should strip the quotes
 		pkg_name := P.val[1 : len(P.val) - 1];  // strip quotes
-		// TODO switch to indirect import once the compiler problems are fixed
-		//pkg := Import.Import(P.comp, pkg_name);
 		pkg := P.comp.env.Import(P.comp, pkg_name);
 		if pkg != nil {
 			pno := pkg.obj.pnolev;  // preserve pno
@@ -1752,7 +1659,7 @@
 				obj = pkg.obj;
 				P.Declare(obj);  // this changes (pkg.)obj.pnolev!
 			}
-			obj.pnolev = pno;  // correct pno
+			obj.pnolev = pno;  // reset pno
 		} else {
 			P.Error(P.pos, `import of "` + pkg_name + `" failed`);
 		}
@@ -1831,9 +1738,9 @@
 		elt := P.ParseType();  // we want a complete type - don't shortcut to ParseTypeName()
 		typ.elt = elt;
 		if elt.form == Type.ALIAS {
-			typ.aux = elt.aux;  // the base type
+			typ.key = elt.key;  // the base type
 		} else {
-			typ.aux = elt;
+			typ.key = elt;
 		}
 	} else {
 		typ = P.ParseType();
@@ -2012,10 +1919,6 @@
 // Program
 
 func (P *Parser) ResolveForwardTypes() {
-	if !P.semantic_checks {
-		return;
-	}
-
 	for p := P.forward_types.first; p != nil; p = p.next {
 		typ := p.typ;
 		if typ.form != Type.POINTER {
@@ -2060,10 +1963,6 @@
 
 
 func (P *Parser) MarkExports() {
-	if !P.semantic_checks {
-		return;
-	}
-
 	scope := P.top_scope;
 	for p := P.exports.first; p != nil; p = p.next {
 		obj := scope.Lookup(p.str);
@@ -2101,11 +2000,23 @@
 			panic("incorrect scope level");
 		}
 
-		P.comp.Insert(Globals.NewPackage(P.S.filename, obj, P.top_scope));
+		P.comp.Insert(Globals.NewPackage(P.scanner.filename, obj, P.top_scope));
 		if P.comp.pkg_ref != 1 {
 			panic("should have exactly one package now");
 		}
 
+		if P.comp.flags.sixg {
+			// automatically import package sys
+			pkg := P.comp.env.Import(P.comp, "sys");
+			if pkg != nil {
+				pno := pkg.obj.pnolev;  // preserve pno
+				P.Declare(pkg.obj);  // this changes pkg.obj.pnolev!
+				pkg.obj.pnolev = pno;  // reset pno
+			} else {
+				P.Error(P.pos, `pre-import of package "sys" failed`);
+			}
+		}
+		
 		for P.tok == Scanner.IMPORT {
 			P.ParseDecl(false, Scanner.IMPORT);
 			P.Optional(Scanner.SEMICOLON);
diff --git a/usr/gri/gosrc/printer.go b/usr/gri/gosrc/printer.go
index d0c5a08..c75152b 100755
--- a/usr/gri/gosrc/printer.go
+++ b/usr/gri/gosrc/printer.go
@@ -40,7 +40,7 @@
 func (P *Printer) PrintSigRange(typ *Globals.Type, a, b int) {
 	scope := typ.scope;
 	if a + 1 == b && IsAnonymous(scope.entries.ObjAt(a).ident) {
-		P.PrintType(scope.entries.TypAt(a));  // result type only
+		P.PrintType(scope.entries.ObjAt(a).typ);  // result type only
 	} else {
 		print("(");
 		for i := a; i < b; i++ {
@@ -57,16 +57,16 @@
 
 
 func (P *Printer) PrintSignature(typ *Globals.Type, fun *Globals.Object) {
-	if typ.form != Type.FUNCTION {
-		panic("typ.form != Type.FUNCTION");
-	}
-	
 	p0 := 0;
-	if typ.flags & Type.RECV != 0 {
+	if typ.form == Type.METHOD {
 		p0 = 1;
+	} else {
+		if typ.form != Type.FUNCTION {
+			panic("not a function or method");
+		}
 	}
-	r0 := p0 + typ.len_;
-	l0 := typ.scope.entries.len_;
+	r0 := p0 + typ.len;
+	l0 := typ.scope.entries.len;
 	
 	if P.level == 0 {
 		print("func ");
@@ -105,7 +105,7 @@
 	// determine the number of scope entries to print
 	var n int;
 	if P.print_all {
-		n = scope.entries.len_;
+		n = scope.entries.len;
 	} else {
 		n = 0;
 		for p := scope.entries.first; p != nil; p = p.next {
@@ -130,12 +130,12 @@
 	}
 }
 
-	
+
 func (P *Printer) PrintObjectStruct(obj *Globals.Object) {
 	switch obj.kind {
 	case Object.BAD:
-		print("bad ");
 		P.PrintObject(obj);
+		print(" /* bad */");
 
 	case Object.CONST:
 		print("const ");
@@ -149,10 +149,11 @@
 		print(" ");
 		P.PrintTypeStruct(obj.typ);
 
-	case Object.VAR, Object.FIELD:
-		if P.level == 0 {
-			print("var ");
-		}
+	case Object.VAR:
+		print("var ");
+		fallthrough;
+
+	case Object.FIELD:
 		P.PrintObject(obj);
 		print(" ");
 		P.PrintType(obj.typ);
@@ -160,6 +161,10 @@
 	case Object.FUNC:
 		P.PrintSignature(obj.typ, obj);
 
+	case Object.BUILTIN:
+		P.PrintObject(obj);
+		print(" /* builtin */");
+		
 	case Object.PACKAGE:
 		print("package ");
 		P.PrintObject(obj);
@@ -197,11 +202,14 @@
 	case Type.VOID:
 		print("void");
 		
+	case Type.BAD:
+		print("<bad type>");
+
 	case Type.FORWARD:
 		print("<forward type>");
 
-	case Type.BAD:
-		print("<bad type>");
+	case Type.TUPLE:
+		print("<tuple type>");
 
 	case Type.NIL, Type.BOOL, Type.UINT, Type.INT, Type.FLOAT, Type.STRING, Type.ANY:
 		if typ.obj == nil {
@@ -211,9 +219,9 @@
 
 	case Type.ALIAS:
 		P.PrintType(typ.elt);
-		if typ.aux != typ.elt {
+		if typ.key != typ.elt {
 			print(" /* ");
-			P.PrintType(typ.aux);
+			P.PrintType(typ.key);
 			print(" */");
 		}
 		
@@ -233,12 +241,12 @@
 
 	case Type.MAP:
 		print("map [");
-		P.PrintType(typ.aux);
+		P.PrintType(typ.key);
 		print("] ");
 		P.PrintType(typ.elt);
 
 	case Type.CHANNEL:
-		switch typ.flags {
+		switch typ.aux {
 		case Type.SEND: print("chan <- ");
 		case Type.RECV: print("<- chan ");
 		case Type.SEND + Type.RECV: print("chan ");
@@ -253,10 +261,6 @@
 		print("*");
 		P.PrintType(typ.elt);
 
-	case Type.REFERENCE:
-		print("&");
-		P.PrintType(typ.elt);
-
 	default:
 		panic("UNREACHABLE");
 		
diff --git a/usr/gri/gosrc/scanner.go b/usr/gri/gosrc/scanner.go
index a1e18ba..ac5b9b6 100644
--- a/usr/gri/gosrc/scanner.go
+++ b/usr/gri/gosrc/scanner.go
@@ -86,7 +86,6 @@
 	ELSE;
 	EXPORT;
 	FALLTHROUGH;
-	FALSE;
 	FOR;
 	FUNC;
 	GO;
@@ -94,17 +93,13 @@
 	IF;
 	IMPORT;
 	INTERFACE;
-	IOTA;
 	MAP;
-	NEW;
-	NIL;
 	PACKAGE;
 	RANGE;
 	RETURN;
 	SELECT;
 	STRUCT;
 	SWITCH;
-	TRUE;
 	TYPE;
 	VAR;
 	KEYWORDS_END;
@@ -191,7 +186,6 @@
 	case ELSE: return "else";
 	case EXPORT: return "export";
 	case FALLTHROUGH: return "fallthrough";
-	case FALSE: return "false";
 	case FOR: return "for";
 	case FUNC: return "func";
 	case GO: return "go";
@@ -199,17 +193,13 @@
 	case IF: return "if";
 	case IMPORT: return "import";
 	case INTERFACE: return "interface";
-	case IOTA: return "iota";
 	case MAP: return "map";
-	case NEW: return "new";
-	case NIL: return "nil";
 	case PACKAGE: return "package";
 	case RANGE: return "range";
 	case RETURN: return "return";
 	case SELECT: return "select";
 	case STRUCT: return "struct";
 	case SWITCH: return "switch";
-	case TRUE: return "true";
 	case TYPE: return "type";
 	case VAR: return "var";
 	}
@@ -219,7 +209,7 @@
 
 
 func init() {
-	Keywords = new(map [string] int);
+	Keywords = make(map [string] int);
 
 	for i := KEYWORDS_BEG; i <= KEYWORDS_END; i++ {
 	  Keywords[TokenName(i)] = i;
@@ -578,14 +568,14 @@
 }
 
 
-func (S *Scanner) ScanEscape() string {
+func (S *Scanner) ScanEscape(quote int) string {
 	// TODO: fix this routine
 
 	ch := S.ch;
 	pos := S.chpos;
 	S.Next();
 	switch (ch) {
-	case 'a', 'b', 'f', 'n', 'r', 't', 'v', '\\', '\'', '"':
+	case 'a', 'b', 'f', 'n', 'r', 't', 'v', '\\':
 		return string(ch);
 
 	case '0', '1', '2', '3', '4', '5', '6', '7':
@@ -605,9 +595,13 @@
 		return "";  // TODO fix this
 
 	default:
+		// check for quote outside the switch for better generated code (eventually)
+		if ch == quote {
+			return string(quote);
+		}
 		S.Error(pos, "illegal char escape");
 	}
-
+	
 	return "";  // TODO fix this
 }
 
@@ -619,7 +613,7 @@
 	ch := S.ch;
 	S.Next();
 	if ch == '\\' {
-		S.ScanEscape();
+		S.ScanEscape('\'');
 	}
 
 	S.Expect('\'');
@@ -639,7 +633,7 @@
 			break;
 		}
 		if ch == '\\' {
-			S.ScanEscape();
+			S.ScanEscape('"');
 		}
 	}
 
@@ -781,7 +775,7 @@
 
 func (S *Scanner) Server(c chan *Token) {
 	for {
-		t := new(*Token);
+		t := new(Token);
 		t.tok, t.pos, t.val = S.Scan();
 		c <- t;
 		if t.tok == EOF {
diff --git a/usr/gri/gosrc/test_scanner.go b/usr/gri/gosrc/test_scanner.go
index b43810a..928a807 100644
--- a/usr/gri/gosrc/test_scanner.go
+++ b/usr/gri/gosrc/test_scanner.go
@@ -8,7 +8,7 @@
 
 
 func Scan1(filename, src string) {
-	S := new(*Scanner.Scanner);
+	S := new(Scanner.Scanner);
 	S.Open(filename, src);
 	for {
 		tok, pos, val := S.Scan();
@@ -25,9 +25,9 @@
 
 
 func Scan2(filename, src string) {
-	S := new(*Scanner.Scanner);
+	S := new(Scanner.Scanner);
 	S.Open(filename, src);
-	c := new(chan *Scanner.Token, 32);
+	c := make(chan *Scanner.Token, 32);
 	go S.Server(c);
 	for {
 		var t *Scanner.Token;
diff --git a/usr/gri/gosrc/type.go b/usr/gri/gosrc/type.go
index bd554d4..5c80ad1 100644
--- a/usr/gri/gosrc/type.go
+++ b/usr/gri/gosrc/type.go
@@ -10,8 +10,12 @@
 
 export const /* form */ (
 	// internal types
-	// VOID types are used when we don't have a type.
-	VOID = iota;
+	// 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;
 	
 	// BAD 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
@@ -22,6 +26,10 @@
 	// 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;
@@ -33,13 +41,13 @@
 	ANY;
 	
 	// composite types
-	ALIAS; ARRAY; STRUCT; INTERFACE; MAP; CHANNEL; FUNCTION; POINTER; REFERENCE;
+	ALIAS; ARRAY; STRUCT; INTERFACE; MAP; CHANNEL; FUNCTION; METHOD; POINTER;
 )
 
 
-export const /* flag */ (
-	SEND = 1 << iota;  // chan>
-	RECV;  // chan< or method
+export const /* Type.aux */ (
+	SEND = 1;  // chan>
+	RECV = 2;  // chan<
 )
 
 
@@ -53,6 +61,7 @@
 	case VOID: return "VOID";
 	case BAD: return "BAD";
 	case FORWARD: return "FORWARD";
+	case TUPLE: return "TUPLE";
 	case NIL: return "NIL";
 	case BOOL: return "BOOL";
 	case UINT: return "UINT";
@@ -67,8 +76,8 @@
 	case MAP: return "MAP";
 	case CHANNEL: return "CHANNEL";
 	case FUNCTION: return "FUNCTION";
+	case METHOD: return "METHOD";
 	case POINTER: return "POINTER";
-	case REFERENCE: return "REFERENCE";
 	}
 	return "<unknown Type form>";
 }
@@ -102,25 +111,24 @@
 
 	case ARRAY:
 		return
-			x.len_ == y.len_ &&
+			x.len == y.len &&
 			Equal(x.elt, y.elt);
 
 	case MAP:
 		return
-			Equal(x.aux, y.aux) &&
+			Equal(x.key, y.key) &&
 			Equal(x.elt, y.elt);
 
 	case CHANNEL:
 		return
-			x.flags == y.flags &&
+			x.aux == y.aux &&
 			Equal(x.elt, y.elt);
 
-	case FUNCTION:
+	case FUNCTION, METHOD:
 		{	xp := x.scope.entries;
 			yp := x.scope.entries;
-			if	x.flags != y.flags &&  // function or method
-				x.len_ != y.len_ &&  // number of parameters
-				xp.len_ != yp.len_  // recv + parameters + results
+			if	x.len != y.len &&  // number of parameters
+				xp.len != yp.len  // recv + parameters + results
 			{
 				return false;
 			}
@@ -163,8 +171,12 @@
 		panic("UNIMPLEMENTED");
 		return false;
 
-	case POINTER, REFERENCE:
+	case POINTER:
 		return Equal(x.elt, y.elt);
+		
+	case TUPLE:
+		panic("UNIMPLEMENTED");
+		return false;
 	}
 
 	panic("UNREACHABLE");
diff --git a/usr/gri/gosrc/universe.go b/usr/gri/gosrc/universe.go
index cb65682..a5d11f9 100755
--- a/usr/gri/gosrc/universe.go
+++ b/usr/gri/gosrc/universe.go
@@ -48,7 +48,9 @@
 	ptrint_t *Globals.Type;
 	
 	true_,
-	false_ *Globals.Object;
+	false_,
+	iota_,
+	nil_ *Globals.Object;
 )
 
 
@@ -72,17 +74,17 @@
 
 func DeclAlias(ident string, typ *Globals.Type) *Globals.Type {
 	alias := Globals.NewType(Type.ALIAS);
-	alias.aux = typ;
+	alias.key = typ;
 	alias.elt = typ;
 	return DeclObj(Object.TYPE, ident, alias).typ;
 }
 
 
 func Register(typ *Globals.Type) *Globals.Type {
-	if types.len_ < 0 {
-		panic("types.len_ < 0");
+	if types.len < 0 {
+		panic("types.len < 0");
 	}
-	typ.ref = types.len_;
+	typ.ref = types.len;
 	types.AddTyp(typ);
 	return typ;
 }
@@ -96,7 +98,7 @@
 	void_t = Globals.NewType(Type.VOID);
 	Globals.Universe_void_t = void_t;
 	bad_t = Globals.NewType(Type.BAD);
-	nil_t = DeclType(Type.NIL, "nil", 8);
+	nil_t = Globals.NewType(Type.NIL);
 	
 	// Basic types
 	bool_t = Register(DeclType(Type.BOOL, "bool", 1));
@@ -130,9 +132,14 @@
 	// Predeclared constants
 	true_ = DeclObj(Object.CONST, "true", bool_t);
 	false_ = DeclObj(Object.CONST, "false", bool_t);
+	iota_ = DeclObj(Object.CONST, "iota", int_t);
+	nil_ = DeclObj(Object.CONST, "nil", nil_t);
 
 	// Builtin functions
-	DeclObj(Object.FUNC, "len", Globals.NewType(Type.FUNCTION));  // incomplete
+	DeclObj(Object.BUILTIN, "len", void_t);
+	DeclObj(Object.BUILTIN, "new", void_t);
+	DeclObj(Object.BUILTIN, "panic", void_t);
+	DeclObj(Object.BUILTIN, "print", void_t);
 	
 	// scope.Print();
 }
diff --git a/usr/gri/gosrc/verifier.go b/usr/gri/gosrc/verifier.go
index 9c1405e..640a8ff 100644
--- a/usr/gri/gosrc/verifier.go
+++ b/usr/gri/gosrc/verifier.go
@@ -46,11 +46,15 @@
 
 	switch typ.form {
 	case Type.VOID:
+	case Type.BAD:
 		break;  // TODO for now - remove eventually
+		
 	case Type.FORWARD:
 		if typ.scope == nil {
 			Error("forward types must have a scope");
 		}
+
+	case Type.TUPLE:
 		break;
 	case Type.NIL:
 		break;
@@ -82,8 +86,6 @@
 		break;
 	case Type.POINTER:
 		break;
-	case Type.REFERENCE:
-		break;
 	default:
 		Error("illegal type form " + Type.FormStr(typ.form));
 	}
@@ -139,12 +141,12 @@
 func (V *Verifier) Verify(comp *Globals.Compilation) {
 	// initialize Verifier
 	V.comp = comp;
-	V.objs = new(map[*Globals.Object] bool);
-	V.typs = new(map[*Globals.Type] bool);
-	V.pkgs = new(map[*Globals.Package] bool);
+	V.objs = make(map[*Globals.Object] bool);
+	V.typs = make(map[*Globals.Type] bool);
+	V.pkgs = make(map[*Globals.Package] bool);
 
 	// verify all packages
-	filenames := new(map[string] bool);
+	filenames := make(map[string] bool);
 	for i := 0; i < comp.pkg_ref; i++ {
 		pkg := comp.pkg_list[i];
 		// each pkg filename must appear only once
@@ -158,6 +160,6 @@
 
 
 export func Verify(comp *Globals.Compilation) {
-	V := new(*Verifier);
+	V := new(Verifier);
 	V.Verify(comp);
 }