- import and export code, bug fixes
- almost back to where I was in C++, but now all in Go

R=r
OCL=13627
CL=13627
diff --git a/usr/gri/gosrc/parser.go b/usr/gri/gosrc/parser.go
index 7d47427..67caa6a 100644
--- a/usr/gri/gosrc/parser.go
+++ b/usr/gri/gosrc/parser.go
@@ -4,11 +4,13 @@
 
 package Parser
 
+import Utils "utils"
 import Scanner "scanner"
 import Globals "globals"
 import Object "object"
 import Type "type"
 import Universe "universe"
+import Import "import"
 import AST "ast"
 
 
@@ -28,6 +30,7 @@
 	val string;  // token value (for IDENT, NUMBER, STRING only)
 
 	// Semantic analysis
+	level int;  // 0 = global scope, -1 = function scope of global functions, etc.
 	top_scope *Globals.Scope;
 	undef_types *Globals.List;
 	exports *Globals.List;
@@ -77,6 +80,7 @@
 	P.indent = 0;
 	P.S = S;
 	P.Next();
+	P.level = 0;
 	P.top_scope = Universe.scope;
 	P.undef_types = Globals.NewList();
 	P.exports = Globals.NewList();
@@ -128,7 +132,11 @@
 
 
 func (P *Parser) DeclareInScope(scope *Globals.Scope, obj *Globals.Object) {
-	if EnableSemanticTests && scope.Lookup(obj.ident) != nil {
+	if !EnableSemanticTests {
+		return;
+	}
+	obj.pnolev = P.level;
+	if scope.Lookup(obj.ident) != nil {
 		P.Error(obj.pos, `"` + obj.ident + `" is declared already`);
 		return;  // don't insert it into the scope
 	}
@@ -141,6 +149,77 @@
 }
 
 
+func MakeFunctionType(sig *Globals.Scope, p0, r0 int, check_recv bool) *Globals.Type {
+  // Determine if we have a receiver or not.
+  if p0 > 0 && check_recv {
+    // method
+	if p0 != 1 {
+		panic "p0 != 1";
+	}
+  }
+  typ := Globals.NewType(Type.FUNCTION);
+  if p0 == 0 {
+	typ.flags = 0;
+  } else {
+	typ.flags = Type.RECV;
+  }
+  typ.len_ = r0 - p0;
+  typ.scope = sig;
+  return typ;
+}
+
+
+func (P *Parser) DeclareFunc(exported bool, 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 {
+		panic "no recv in signature?";
+	}
+    trecv := typ.scope.entries.first.typ;
+    if trecv.form == Type.POINTER {
+      trecv = trecv.elt;
+    }
+    scope = trecv.scope;
+  }
+  
+  // Declare the function.
+  fun := scope.Lookup(ident);
+  if fun == nil {
+    fun = Globals.NewObject(-1, Object.FUNC, ident);
+	fun.typ = typ;
+	// TODO do we need to set the prymary type? probably...
+    P.DeclareInScope(scope, fun);
+    return fun;
+  }
+  
+  // fun != NULL: possibly a forward declaration.
+  if (fun.kind != Object.FUNC) {
+    P.Error(-1, `"` + ident + `" is declared already`);
+    // Continue but do not insert this function into the scope.
+    fun = Globals.NewObject(-1, Object.FUNC, ident);
+	fun.typ = typ;
+	// TODO do we need to set the prymary type? probably...
+    return fun;
+  }
+  
+  // We have a function with the same name.
+  /*
+  if (!EqualTypes(type, fun->type())) {
+    this->Error("type of \"%s\" does not match its forward declaration", name.cstr());
+    // Continue but do not insert this function into the scope.
+    NewObject(Object::FUNC, name);
+    fun->set_type(type);
+    return fun;    
+  }
+  */
+  
+  // We have a matching forward declaration. Use it.
+  return fun;
+}
+
+
 // ----------------------------------------------------------------------------
 // Common productions
 
@@ -225,10 +304,23 @@
 		}
 
 		if obj.kind == Object.PACKAGE && P.tok == Scanner.PERIOD {
-			panic "Qualified ident not complete yet";
-			P.Next();
-			P.ParseIdent();
+			if obj.pnolev < 0 {
+				panic "obj.pnolev < 0";
+			}
+			pkg := P.comp.pkgs[obj.pnolev];
+			//if pkg.obj.ident != ident {
+			//	panic "pkg.obj.ident != ident";
+			//}
+			P.Next();  // consume "."
+			pos = P.pos;
+			ident = P.ParseIdent();
+			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;
 		
@@ -383,26 +475,6 @@
 }
 
 
-func MakeFunctionType(sig *Globals.Scope, p0, r0 int, check_recv bool) *Globals.Type {
-  // Determine if we have a receiver or not.
-  if p0 > 0 && check_recv {
-    // method
-	if p0 != 1 {
-		panic "p0 != 1";
-	}
-  }
-  typ := Globals.NewType(Type.FUNCTION);
-  if p0 == 0 {
-	typ.flags = 0;
-  } else {
-	typ.flags = Type.RECV;
-  }
-  typ.len_ = r0 - p0;
-  typ.scope = sig;
-  return typ;
-}
-
-
 // Anonymous signatures
 //
 //          (params)
@@ -424,9 +496,9 @@
 	
 	if P.tok == Scanner.PERIOD {
 		p0 = sig.entries.len_;
-		if (p0 != 1) {
+		if (EnableSemanticTests && p0 != 1) {
 			P.Error(recv_pos, "must have exactly one receiver")
-			panic "UNIMPLEMENTED";
+			panic "UNIMPLEMENTED (ParseAnonymousSignature)";
 			// TODO do something useful here
 		}
 		P.Next();
@@ -462,10 +534,10 @@
 		recv_pos := P.pos;
 		P.ParseParameters();
 		p0 = sig.entries.len_;
-		if (p0 != 1) {
+		if (EnableSemanticTests && p0 != 1) {
 			print "p0 = ", p0, "\n";
 			P.Error(recv_pos, "must have exactly one receiver")
-			panic "UNIMPLEMENTED";
+			panic "UNIMPLEMENTED (ParseNamedSignature)";
 			// TODO do something useful here
 		}
 	}
@@ -498,8 +570,13 @@
 	P.Trace("MethodDecl");
 	
 	P.ParseIdent();
+	P.OpenScope();
+	sig := P.top_scope;
+	p0 := 0;
 	P.ParseParameters();
+	r0 := sig.entries.len_;
 	P.TryResult();
+	P.CloseScope();
 	P.Optional(Scanner.SEMICOLON);
 	
 	P.Ecart();
@@ -662,15 +739,26 @@
 }
 
 
-func (P *Parser) ParseBlock() {
+func (P *Parser) ParseBlock(sig *Globals.Scope) {
 	P.Trace("Block");
 	
 	P.Expect(Scanner.LBRACE);
 	P.OpenScope();
+	if sig != nil {
+		P.level--;
+		// add function parameters to scope
+		scope := P.top_scope;
+		for p := sig.entries.first; p != nil; p = p.next {
+			scope.Insert(p.obj)
+		}
+	}
 	if P.tok != Scanner.RBRACE && P.tok != Scanner.SEMICOLON {
 		P.ParseStatementList();
 	}
 	P.Optional(Scanner.SEMICOLON);
+	if sig != nil {
+		P.level++;
+	}
 	P.CloseScope();
 	P.Expect(Scanner.RBRACE);
 	
@@ -717,8 +805,8 @@
 func (P *Parser) ParseFunctionLit() {
 	P.Trace("FunctionLit");
 	
-	P.ParseFunctionType();
-	P.ParseBlock();
+	typ := P.ParseFunctionType();
+	P.ParseBlock(typ.scope);
 	
 	P.Ecart();
 }
@@ -1226,7 +1314,7 @@
 			}
 		}
 	}
-	P.ParseBlock();
+	P.ParseBlock(nil);
 	if P.tok == Scanner.ELSE {
 		P.Next();
 		if P.tok == Scanner.IF {
@@ -1262,7 +1350,7 @@
 			}
 		}
 	}
-	P.ParseBlock();
+	P.ParseBlock(nil);
 	P.CloseScope();
 	
 	P.Ecart();
@@ -1389,7 +1477,7 @@
 	P.ParseIdentList();
 	P.Expect(Scanner.DEFINE);
 	P.ParseExpression();
-	P.ParseBlock();
+	P.ParseBlock(nil);
 	
 	P.Ecart();
 }
@@ -1431,7 +1519,7 @@
 	case Scanner.BREAK, Scanner.CONTINUE, Scanner.GOTO:
 		P.ParseControlFlowStat(P.tok);
 	case Scanner.LBRACE:
-		P.ParseBlock();
+		P.ParseBlock(nil);
 	case Scanner.IF:
 		P.ParseIfStat();
 	case Scanner.FOR:
@@ -1461,30 +1549,32 @@
 func (P *Parser) ParseImportSpec() {
 	P.Trace("ImportSpec");
 	
+	var obj *Globals.Object = nil;
 	if P.tok == Scanner.PERIOD {
+		P.Error(P.pos, `"import ." not yet handled properly`);
 		P.Next();
 	} else if P.tok == Scanner.IDENT {
-		P.Next();
+		obj = P.ParseIdentDecl(Object.PACKAGE);
 	}
-	P.Expect(Scanner.STRING);
 	
-	P.Ecart();
-}
-
-
-func (P *Parser) ParseImportDecl() {
-	P.Trace("ImportDecl");
-	
-	P.Expect(Scanner.IMPORT);
-	if P.tok == Scanner.LPAREN {
-		P.Next();
-		for P.tok != Scanner.RPAREN && P.tok != Scanner.EOF {
-			P.ParseImportSpec();
-			P.Optional(Scanner.SEMICOLON);  // TODO this seems wrong
+	if (EnableSemanticTests && P.tok == Scanner.STRING) {
+		// TODO eventually the scanner should strip the quotes
+		pkg_name := P.val[1 : len(P.val) - 1];  // strip quotes
+		imp := new(Import.Importer);
+		pkg := imp.Import(P.comp, Utils.FixExt(Utils.BaseName(pkg_name)));
+		if pkg != nil {
+			if obj == nil {
+				// use original package name
+				obj = pkg.obj;
+				P.Declare(obj);
+			}
+			obj.pnolev = pkg.obj.pnolev;
+		} else {
+			P.Error(P.pos, `import of "` + pkg_name + `" failed`);
 		}
 		P.Next();
 	} else {
-		P.ParseImportSpec();
+		P.Expect(Scanner.STRING);  // use Expect() error handling
 	}
 	
 	P.Ecart();
@@ -1569,6 +1659,7 @@
 // TODO With method variables, we wouldn't need this dispatch function.
 func (P *Parser) ParseSpec(exported bool, keyword int) {
 	switch keyword {
+	case Scanner.IMPORT: P.ParseImportSpec();
 	case Scanner.CONST: P.ParseConstSpec(exported);
 	case Scanner.TYPE: P.ParseTypeSpec(exported);
 	case Scanner.VAR: P.ParseVarSpec(exported);
@@ -1586,7 +1677,8 @@
 		for P.tok == Scanner.IDENT {
 			P.ParseSpec(exported, keyword);
 			if P.tok != Scanner.RPAREN {
-				P.Expect(Scanner.SEMICOLON);
+				// P.Expect(Scanner.SEMICOLON);
+				P.Optional(Scanner.SEMICOLON);  // TODO this seems wrong! (needed for math.go)
 			}
 		}
 		P.Next();
@@ -1602,12 +1694,13 @@
 	P.Trace("FuncDecl");
 	
 	P.Expect(Scanner.FUNC);
-	P.ParseNamedSignature();
+	ident, typ := P.ParseNamedSignature();
+	obj := P.DeclareFunc(exported, ident, typ);  // need obj later for statements
 	if P.tok == Scanner.SEMICOLON {
 		// forward declaration
 		P.Next();
 	} else {
-		P.ParseBlock();
+		P.ParseBlock(typ.scope);
 	}
 	
 	P.Ecart();
@@ -1643,9 +1736,14 @@
 	
 	exported := false;
 	if P.tok == Scanner.EXPORT {
+		if P.level == 0 {
+			exported = true;
+		} else {
+			P.Error(P.pos, "local declarations cannot be exported");
+		}
 		P.Next();
-		exported = true;
 	}
+	
 	switch P.tok {
 	case Scanner.CONST, Scanner.TYPE, Scanner.VAR:
 		P.ParseDecl(exported, P.tok);
@@ -1732,14 +1830,18 @@
 	
 	P.OpenScope();
 	P.Expect(Scanner.PACKAGE);
-	pkg := P.comp.pkgs[0];
+	pkg := Globals.NewPackage(P.S.filename);
 	pkg.obj = P.ParseIdentDecl(Object.PACKAGE);
+	P.comp.Insert(pkg);
+	if P.comp.npkgs != 1 {
+		panic "should have exactly one package now";
+	}
 	P.Optional(Scanner.SEMICOLON);
 	
 	{	P.OpenScope();
 		pkg.scope = P.top_scope;
 		for P.tok == Scanner.IMPORT {
-			P.ParseImportDecl();
+			P.ParseDecl(false, Scanner.IMPORT);
 			P.Optional(Scanner.SEMICOLON);
 		}