--- /dev/null
+// 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 Exporter
+
+import Globals "globals"
+import Object "object"
+import Type "type"
+import Package "package"
+
+
+type Exporter struct {
+ /*
+ Compilation* comp;
+ */
+ debug bool;
+ buf [4*1024] byte;
+ pos int;
+ pkg_ref int;
+ type_ref int;
+};
+
+
+func (E *Exporter) WriteType(typ *Globals.Type);
+func (E *Exporter) WriteObject(obj *Globals.Object);
+func (E *Exporter) WritePackage(pkg *Package.Package) ;
+
+
+func (E *Exporter) WriteByte(x byte) {
+ E.buf[E.pos] = x;
+ E.pos++;
+ if E.debug {
+ print " ", x;
+ }
+}
+
+
+func (E *Exporter) WriteInt(x int) {
+ if E.debug {
+ print " #", x;
+ }
+ for x < -64 || x >= 64 {
+ E.WriteByte(byte(x & 127));
+ x = int(uint(x >> 7)); // arithmetic shift
+ }
+ // -64 <= x && x < 64
+ E.WriteByte(byte(x + 192));
+}
+
+
+func (E *Exporter) WriteString(s string) {
+ if E.debug {
+ print `"`, s, `"`;
+ }
+ n := len(s);
+ E.WriteInt(n);
+ for i := 0; i < n; i++ {
+ E.WriteByte(s[i]);
+ }
+}
+
+
+func (E *Exporter) WriteObjTag(tag int) {
+ if tag < 0 {
+ panic "tag < 0";
+ }
+ if E.debug {
+ print "\nO: ", tag; // obj kind
+ }
+ E.WriteInt(tag);
+}
+
+
+func (E *Exporter) WriteTypeTag(tag int) {
+ if E.debug {
+ if tag > 0 {
+ print "\nT", E.type_ref, ": ", tag; // type form
+ } else {
+ print " [T", -tag, "]"; // type ref
+ }
+ }
+ E.WriteInt(tag);
+}
+
+
+func (E *Exporter) WritePackageTag(tag int) {
+ if E.debug {
+ if tag > 0 {
+ print "\nP", E.pkg_ref, ": ", tag; // package no
+ } else {
+ print " [P", -tag, "]"; // package ref
+ }
+ }
+ E.WriteInt(tag);
+}
+
+
+func (E *Exporter) WriteTypeField(fld *Globals.Object) {
+ if fld.kind != Object.VAR {
+ panic "fld.kind != Object.VAR";
+ }
+ E.WriteType(fld.typ);
+}
+
+
+func (E *Exporter) WriteScope(scope *Globals.Scope) {
+ if E.debug {
+ print " {";
+ }
+
+ // determine number of objects to export
+ n := 0;
+ for p := scope.entries.first; p != nil; p = p.next {
+ if p.obj.mark {
+ n++;
+ }
+ }
+
+ // export the objects, if any
+ if n > 0 {
+ for p := scope.entries.first; p != nil; p = p.next {
+ if p.obj.mark {
+ E.WriteObject(p.obj);
+ }
+ }
+ }
+
+ if E.debug {
+ print " }";
+ }
+}
+
+
+func (E *Exporter) WriteObject(obj *Globals.Object) {
+ if obj == nil || !obj.mark {
+ panic "obj == nil || !obj.mark";
+ }
+
+ if obj.kind == Object.TYPE && obj.typ.obj == obj {
+ // primary type object - handled entirely by WriteType()
+ E.WriteObjTag(Object.PTYPE);
+ E.WriteType(obj.typ);
+
+ } else {
+ E.WriteObjTag(obj.kind);
+ E.WriteString(obj.ident);
+ E.WriteType(obj.typ);
+ panic "UNIMPLEMENTED";
+ //E.WritePackage(E.comp.packages[obj.pnolev]);
+
+ switch obj.kind {
+ case Object.BAD: fallthrough;
+ case Object.PACKAGE: fallthrough;
+ case Object.PTYPE:
+ panic "UNREACHABLE";
+ case Object.CONST:
+ E.WriteInt(0); // should be the correct value
+ break;
+ case Object.TYPE:
+ // nothing to do
+ case Object.VAR:
+ E.WriteInt(0); // should be the correct address/offset
+ case Object.FUNC:
+ E.WriteInt(0); // should be the correct address/offset
+ default:
+ panic "UNREACHABLE";
+ }
+ }
+}
+
+
+func (E *Exporter) WriteType(typ *Globals.Type) {
+ if typ == nil {
+ panic "typ == nil";
+ }
+
+ if typ.ref >= 0 {
+ E.WriteTypeTag(-typ.ref); // type already exported
+ return;
+ }
+
+ if typ.form <= 0 {
+ panic "typ.form <= 0";
+ }
+ E.WriteTypeTag(typ.form);
+ typ.ref = E.type_ref;
+ E.type_ref++;
+
+ if typ.obj != nil {
+ if typ.obj.typ != typ {
+ panic "typ.obj.type() != typ"; // primary type
+ }
+ E.WriteString(typ.obj.ident);
+ panic "UNIMPLEMENTED";
+ //WritePackage(E.comp.packages[typ.obj.pnolev]);
+ } else {
+ E.WriteString("");
+ }
+
+ switch typ.form {
+ case Type.UNDEF: fallthrough;
+ case Type.BAD: fallthrough;
+ case Type.NIL: fallthrough;
+ case Type.BOOL: fallthrough;
+ case Type.UINT: fallthrough;
+ case Type.INT: fallthrough;
+ case Type.FLOAT: fallthrough;
+ case Type.STRING: fallthrough;
+ case Type.ANY:
+ panic "UNREACHABLE";
+
+ case Type.ARRAY:
+ E.WriteInt(typ.len_);
+ E.WriteTypeField(typ.elt);
+
+ case Type.MAP:
+ E.WriteTypeField(typ.key);
+ E.WriteTypeField(typ.elt);
+
+ case Type.CHANNEL:
+ E.WriteInt(typ.flags);
+ E.WriteTypeField(typ.elt);
+
+ case Type.FUNCTION:
+ E.WriteInt(typ.flags);
+ fallthrough;
+ case Type.STRUCT: fallthrough;
+ case Type.INTERFACE:
+ E.WriteScope(typ.scope);
+
+ case Type.POINTER: fallthrough;
+ case Type.REFERENCE:
+ E.WriteTypeField(typ.elt);
+
+ default:
+ panic "UNREACHABLE";
+ }
+}
+
+
+func (E *Exporter) WritePackage(pkg *Package.Package) {
+ if pkg.ref >= 0 {
+ E.WritePackageTag(-pkg.ref); // package already exported
+ return;
+ }
+
+ if Object.PACKAGE <= 0 {
+ panic "Object.PACKAGE <= 0";
+ }
+ E.WritePackageTag(Object.PACKAGE);
+ pkg.ref = E.pkg_ref;
+ E.pkg_ref++;
+
+ E.WriteString(pkg.ident);
+ E.WriteString(pkg.path);
+ E.WriteString(pkg.key);
+}
+
+
+func (E *Exporter) Export(/*Compilation* comp, BBuffer* buf*/) {
+ panic "UNIMPLEMENTED";
+
+ /*
+ E.comp = comp;
+ E.buf = buf;
+ E.pak_ref = 0;
+ E.nbytes = 0;
+ */
+
+ // Predeclared types are "pre-exported".
+ /*
+ #ifdef DEBUG
+ for (int i = 0; i < Universe.types.len(); i++) {
+ ASSERT(Universe.types[i].ref == i);
+ }
+ #endif
+ E.type_ref = Universe.types.len();
+ */
+
+ var pkg *Package.Package = nil; // comp.packages[0];
+ E.WritePackage(pkg);
+ for p := pkg.scope.entries.first; p != nil; p = p.next {
+ if p.obj.mark {
+ E.WriteObject(p.obj);
+ }
+ }
+ E.WriteObjTag(0);
+
+ if E.debug {
+ print "\n(", E.pos, ")\n";
+ }
+}
+
+
+export Export
+func Export(/*Compilation* comp, BBuffer* buf*/) {
+ /*
+ Exporter exp;
+ exp.Export(comp, buf);
+ */
+}
import Scanner "scanner"
import Globals "globals"
+import Object "object"
+import Type "type"
import Universe "universe"
+// So I can submit and have a running parser for now...
+const EnableSemanticTests = false;
+
+
export Parser
type Parser struct {
verbose, indent int;
}
+// ----------------------------------------------------------------------------
+// Support functions
+
func (P *Parser) PrintIndent() {
for i := P.indent; i > 0; i-- {
print ". ";
}
if P.verbose > 1 {
P.PrintIndent();
- print Scanner.TokenName(P.tok), "\n";
+ print "[", P.beg, "] ", Scanner.TokenName(P.tok), "\n";
}
}
func (P *Parser) Error(pos int, msg string) {
P.S.Error(pos, msg);
- P.Next(); // make progress
}
func (P *Parser) Expect(tok int) {
- if P.tok == tok {
- P.Next()
- } else {
+ if P.tok != tok {
P.Error(P.beg, "expected '" + Scanner.TokenName(tok) + "', found '" + Scanner.TokenName(P.tok) + "'");
}
+ P.Next(); // make progress in any case
}
// ----------------------------------------------------------------------------
+// Scopes
func (P *Parser) OpenScope() {
P.top_scope = Globals.NewScope(P.top_scope);
func (P *Parser) DeclareInScope(scope *Globals.Scope, obj *Globals.Object) {
+ if !EnableSemanticTests {
+ return;
+ }
+
if scope.Lookup(obj.ident) != nil {
// TODO is this the correct error position?
- P.Error(P.beg, `"` + obj.ident + `" is declared already`);
+ P.Error(obj.pos, `"` + obj.ident + `" is declared already`);
return; // don't insert it into the scope
}
scope.Insert(obj);
// Common productions
-func (P *Parser) TryType() bool;
+func (P *Parser) TryType() *Globals.Type;
func (P *Parser) ParseExpression();
func (P *Parser) TryStatement() bool;
func (P *Parser) ParseDeclaration();
-func (P *Parser) ParseIdent() {
- if P.verbose > 0 {
- P.PrintIndent();
- print "Ident = \"", P.ident, "\"\n";
+func (P *Parser) ParseIdent() string {
+ P.Trace("Ident");
+
+ ident := "";
+ if P.tok == Scanner.IDENT {
+ ident = P.ident;
+ if P.verbose > 0 {
+ P.PrintIndent();
+ print "Ident = \"", ident, "\"\n";
+ }
+ P.Next();
+ } else {
+ P.Expect(Scanner.IDENT); // use Expect() error handling
}
- P.Expect(Scanner.IDENT);
+
+ P.Ecart();
+ return ident;
+}
+
+
+func (P *Parser) ParseIdentDecl(kind int) *Globals.Object {
+ P.Trace("IdentDecl");
+
+ pos := P.beg;
+ obj := Globals.NewObject(pos, kind, P.ParseIdent());
+ P.Declare(obj);
+
+ P.Ecart();
+ return obj;
+}
+
+
+func (P *Parser) ParseIdentDeclList(kind int) *Globals.List {
+ P.Trace("IdentDeclList");
+
+ list := Globals.NewList();
+ list.AddObj(P.ParseIdentDecl(kind));
+ for P.tok == Scanner.COMMA {
+ P.Next();
+ list.AddObj(P.ParseIdentDecl(kind));
+ }
+
+ P.Ecart();
+ return list;
}
}
-func (P *Parser) ParseQualifiedIdent() {
+func (P *Parser) ParseQualifiedIdent() *Globals.Object {
P.Trace("QualifiedIdent");
- P.ParseIdent();
- if P.tok == Scanner.PERIOD {
- P.Next();
+
+ if EnableSemanticTests {
+ pos := P.beg;
+ ident := P.ParseIdent();
+ 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 {
+ panic "Qualified ident not complete yet";
+ P.Next();
+ P.ParseIdent();
+ }
+ P.Ecart();
+ return obj;
+
+ } else {
P.ParseIdent();
+ if P.tok == Scanner.PERIOD {
+ P.Next();
+ P.ParseIdent();
+ }
+ P.Ecart();
+ return nil;
}
- P.Ecart();
}
// ----------------------------------------------------------------------------
// Types
-func (P *Parser) ParseType() {
+func (P *Parser) ParseType() *Globals.Type{
P.Trace("Type");
- if !P.TryType() {
+
+ typ := P.TryType();
+ if typ == nil {
P.Error(P.beg, "type expected");
+ typ = Universe.bad_t;
}
+
P.Ecart();
+ return typ;
}
-func (P *Parser) ParseTypeName() {
+func (P *Parser) ParseTypeName() *Globals.Type {
P.Trace("TypeName");
- P.ParseQualifiedIdent();
- P.Ecart();
+
+ if EnableSemanticTests {
+ obj := P.ParseQualifiedIdent();
+ typ := obj.typ;
+ if obj.kind != Object.TYPE {
+ P.Error(obj.pos, `"` + obj.ident + `" is not a type`);
+ typ = Universe.bad_t;
+ }
+ P.Ecart();
+ return typ;
+ } else {
+ P.ParseQualifiedIdent();
+ P.Ecart();
+ return Universe.bad_t;
+ }
}
-func (P *Parser) ParseArrayType() {
+func (P *Parser) ParseArrayType() *Globals.Type {
P.Trace("ArrayType");
P.Expect(Scanner.LBRACK);
if P.tok != Scanner.RBRACK {
P.Expect(Scanner.RBRACK);
P.ParseType();
P.Ecart();
+ return Universe.bad_t;
}
-func (P *Parser) ParseChannelType() {
+func (P *Parser) ParseChannelType() *Globals.Type {
P.Trace("ChannelType");
P.Expect(Scanner.CHAN);
switch P.tok {
}
P.ParseType();
P.Ecart();
+ return Universe.bad_t;
}
P.ParseParameters();
res = true;
} else {
- res = P.TryType();
+ res = P.TryType() != nil;
}
P.Ecart();
return res;
}
-func (P *Parser) ParseFunctionType() {
+func (P *Parser) ParseFunctionType() *Globals.Type {
P.Trace("FunctionType");
P.Expect(Scanner.FUNC);
P.ParseAnonymousSignature();
P.Ecart();
+ return Universe.bad_t;
}
}
-func (P *Parser) ParseInterfaceType() {
+func (P *Parser) ParseInterfaceType() *Globals.Type {
P.Trace("InterfaceType");
P.Expect(Scanner.INTERFACE);
P.Expect(Scanner.LBRACE);
P.CloseScope();
P.Next();
P.Ecart();
+ return Universe.bad_t;
}
-func (P *Parser) ParseMapType() {
+func (P *Parser) ParseMapType() *Globals.Type {
P.Trace("MapType");
P.Expect(Scanner.MAP);
P.Expect(Scanner.LBRACK);
P.Expect(Scanner.RBRACK);
P.ParseType();
P.Ecart();
+ return Universe.bad_t;
}
func (P *Parser) ParseFieldDecl() {
P.Trace("FieldDecl");
- P.ParseIdentList();
- P.ParseType();
+
+ list := P.ParseIdentDeclList(Object.VAR);
+ typ := P.ParseType(); // TODO should check completeness of types
+ for p := list.first; p != nil; p = p.next {
+ p.obj.typ = typ; // TODO should use/have set_type()
+ }
+
P.Ecart();
}
-func (P *Parser) ParseStructType() {
+func (P *Parser) ParseStructType() *Globals.Type {
P.Trace("StructType");
+
P.Expect(Scanner.STRUCT);
P.Expect(Scanner.LBRACE);
P.OpenScope();
- for P.tok != Scanner.RBRACE {
+ typ := Globals.NewType(Type.STRUCT);
+ typ.scope = P.top_scope;
+ for P.tok == Scanner.IDENT {
P.ParseFieldDecl();
if P.tok != Scanner.RBRACE {
P.Expect(Scanner.SEMICOLON);
P.Optional(Scanner.SEMICOLON);
P.CloseScope();
P.Expect(Scanner.RBRACE);
+
P.Ecart();
+ return typ;
}
-func (P *Parser) ParsePointerType() {
+func (P *Parser) ParsePointerType() *Globals.Type {
P.Trace("PointerType");
P.Expect(Scanner.MUL);
P.ParseType();
P.Ecart();
+ return Universe.bad_t;
}
-func (P *Parser) TryType() bool {
+// Returns nil if no type was found.
+func (P *Parser) TryType() *Globals.Type {
P.Trace("Type (try)");
+
+ var typ *Globals.Type = nil;
switch P.tok {
- case Scanner.IDENT:
- P.ParseTypeName();
- case Scanner.LBRACK:
- P.ParseArrayType();
- case Scanner.CHAN:
- P.ParseChannelType();
- case Scanner.INTERFACE:
- P.ParseInterfaceType();
- case Scanner.FUNC:
- P.ParseFunctionType();
- case Scanner.MAP:
- P.ParseMapType();
- case Scanner.STRUCT:
- P.ParseStructType();
- case Scanner.MUL:
- P.ParsePointerType();
- default:
- P.Ecart();
- return false;
+ case Scanner.IDENT: typ = P.ParseTypeName();
+ case Scanner.LBRACK: typ = P.ParseArrayType();
+ case Scanner.CHAN: typ = P.ParseChannelType();
+ case Scanner.INTERFACE: typ = P.ParseInterfaceType();
+ case Scanner.FUNC: typ = P.ParseFunctionType();
+ case Scanner.MAP: typ = P.ParseMapType();
+ case Scanner.STRUCT: typ = P.ParseStructType();
+ case Scanner.MUL: typ = P.ParsePointerType();
}
+
P.Ecart();
- return true;
+ return typ;
}
P.Trace("Statement");
if !P.TryStatement() {
P.Error(P.beg, "statement expected");
+ P.Next(); // make progress
}
P.Ecart();
}
P.ParseNew();
default:
P.Error(P.beg, "operand expected");
+ P.Next(); // make progress
}
P.Ecart();
}
case Scanner.FUNC:
// for now we do not allow local function declarations
fallthrough;
+ case Scanner.LSS: fallthrough;
case Scanner.GTR:
- P.ParseSimpleStat(); // send
+ P.ParseSimpleStat(); // send or receive
case Scanner.IDENT:
switch P.ident {
case "print", "panic":
func (P *Parser) ParseImportSpec() {
P.Trace("ImportSpec");
+
if P.tok == Scanner.PERIOD {
P.Next();
} else if P.tok == Scanner.IDENT {
P.Next();
}
P.Expect(Scanner.STRING);
+
P.Ecart();
}
func (P *Parser) ParseImportDecl() {
P.Trace("ImportDecl");
+
P.Expect(Scanner.IMPORT);
if P.tok == Scanner.LPAREN {
P.Next();
} else {
P.ParseImportSpec();
}
+
P.Ecart();
}
func (P *Parser) ParseConstSpec() {
P.Trace("ConstSpec");
- P.ParseIdent();
- P.TryType();
+
+ list := P.ParseIdentDeclList(Object.CONST);
+ typ := P.TryType();
+ if typ != nil {
+ for p := list.first; p != nil; p = p.next {
+ p.obj.typ = typ; // TODO should use/have set_type()!
+ }
+ }
if P.tok == Scanner.ASSIGN {
P.Next();
- P.ParseExpression();
+ P.ParseExpressionList();
}
+
P.Ecart();
}
func (P *Parser) ParseConstDecl() {
P.Trace("ConstDecl");
+
P.Expect(Scanner.CONST);
if P.tok == Scanner.LPAREN {
P.Next();
} else {
P.ParseConstSpec();
}
+
P.Ecart();
}
func (P *Parser) ParseTypeSpec() {
P.Trace("TypeSpec");
- P.ParseIdent();
- P.TryType();
+
+ pos := P.beg;
+ ident := P.ParseIdent();
+ obj := P.top_scope.Lookup(ident); // only lookup in top scope!
+ if obj != nil {
+ // ok if forward declared type
+ if obj.kind != Object.TYPE || obj.typ.form != Type.UNDEF {
+ // TODO use obj.pos to refer to decl pos in error msg!
+ P.Error(pos, `"` + ident + `" is declared already`);
+ }
+ } else {
+ obj = Globals.NewObject(pos, Object.TYPE, ident);
+ obj.typ = Universe.undef_t; // TODO fix this
+ P.top_scope.Insert(obj);
+ }
+
+ typ := P.TryType(); // no type if we have a forward decl
+ if typ != nil {
+ // TODO what about the name of incomplete types?
+ obj.typ = typ; // TODO should use/have set_typ()!
+ if typ.obj == nil {
+ typ.obj = obj; // primary type object
+ }
+ }
+
P.Ecart();
}
func (P *Parser) ParseTypeDecl() {
P.Trace("TypeDecl");
+
P.Expect(Scanner.TYPE);
if P.tok == Scanner.LPAREN {
P.Next();
} else {
P.ParseTypeSpec();
}
+
P.Ecart();
}
func (P *Parser) ParseVarSpec() {
P.Trace("VarSpec");
- P.ParseIdentList();
+
+ list := P.ParseIdentDeclList(Object.VAR);
if P.tok == Scanner.ASSIGN {
P.Next();
P.ParseExpressionList();
} else {
- P.ParseType();
+ typ := P.ParseType();
+ for p := list.first; p != nil; p = p.next {
+ p.obj.typ = typ; // TODO should use/have set_type()!
+ }
if P.tok == Scanner.ASSIGN {
P.Next();
P.ParseExpressionList();
}
}
+
P.Ecart();
}
func (P *Parser) ParseVarDecl() {
P.Trace("VarDecl");
+
P.Expect(Scanner.VAR);
if P.tok == Scanner.LPAREN {
P.Next();
} else {
P.ParseVarSpec();
}
+
P.Ecart();
}
func (P *Parser) ParseFuncDecl() {
P.Trace("FuncDecl");
+
P.Expect(Scanner.FUNC);
P.ParseNamedSignature();
if P.tok == Scanner.SEMICOLON {
} else {
P.ParseBlock();
}
+
P.Ecart();
}
func (P *Parser) ParseExportDecl() {
P.Trace("ExportDecl");
+
P.Expect(Scanner.EXPORT);
if P.tok == Scanner.LPAREN {
P.Next();
P.ParseIdent();
}
}
+
P.Ecart();
}
func (P *Parser) ParseDeclaration() {
P.Trace("Declaration");
+
indent := P.indent;
switch P.tok {
case Scanner.CONST:
P.ParseExportDecl();
default:
P.Error(P.beg, "declaration expected");
+ P.Next(); // make progress
}
if indent != P.indent {
panic "imbalanced tracing code"
}
+
P.Ecart();
}