1
0
mirror of https://github.com/golang/go synced 2024-11-23 00:40:08 -07:00
go/usr/gri/gosrc/parser.go
Robert Griesemer 9761a6d069 - backward link from objs to containing scope
(first step towards cleaner package handling)
- check that map, function, and channel vars are pointers

R=r
OCL=13690
CL=13690
2008-07-31 13:35:30 -07:00

1936 lines
39 KiB
Go

// 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 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"
export Parser
type Parser struct {
comp *Globals.Compilation;
semantic_checks bool;
verbose, indent int;
S *Scanner.Scanner;
// Token
tok int; // one token look-ahead
pos int; // token source position
val string; // token value (for IDENT, NUMBER, STRING only)
// Semantic analysis
level int; // 0 = global scope, -1 = function/struct scope of global functions/structs, etc.
top_scope *Globals.Scope;
undef_types *Globals.List;
exports *Globals.List;
}
// ----------------------------------------------------------------------------
// Support functions
func (P *Parser) PrintIndent() {
for i := P.indent; i > 0; i-- {
print ". ";
}
}
func (P *Parser) Trace(msg string) {
if P.verbose > 0 {
P.PrintIndent();
print msg, " {\n";
P.indent++;
}
}
func (P *Parser) Ecart() {
if P.verbose > 0 {
P.indent--;
P.PrintIndent();
print "}\n";
}
}
func (P *Parser) Next() {
P.tok, P.pos, P.val = P.S.Scan();
if P.verbose > 1 {
P.PrintIndent();
print "[", P.pos, "] ", Scanner.TokenName(P.tok), "\n";
}
}
func (P *Parser) Open(comp *Globals.Compilation, S *Scanner.Scanner) {
P.comp = comp;
P.semantic_checks = comp.flags.semantic_checks;
P.verbose = comp.flags.verbose;
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();
}
func (P *Parser) Error(pos int, msg string) {
P.S.Error(pos, msg);
}
func (P *Parser) Expect(tok int) {
if P.tok != tok {
P.Error(P.pos, "expected '" + Scanner.TokenName(tok) + "', found '" + Scanner.TokenName(P.tok) + "'");
}
P.Next(); // make progress in any case
}
func (P *Parser) Optional(tok int) {
if P.tok == tok {
P.Next();
}
}
// ----------------------------------------------------------------------------
// Scopes
func (P *Parser) OpenScope() {
P.top_scope = Globals.NewScope(P.top_scope);
}
func (P *Parser) CloseScope() {
P.top_scope = P.top_scope.parent;
}
func (P *Parser) Lookup(ident string) *Globals.Object {
for scope := P.top_scope; scope != nil; scope = scope.parent {
obj := scope.Lookup(ident);
if obj != nil {
return obj;
}
}
return nil;
}
func (P *Parser) DeclareInScope(scope *Globals.Scope, obj *Globals.Object) {
if !P.semantic_checks {
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
}
scope.Insert(obj);
}
func (P *Parser) Declare(obj *Globals.Object) {
P.DeclareInScope(P.top_scope, obj);
}
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";
}
}
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(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?";
}
recv_typ := typ.scope.entries.first.obj.typ;
if recv_typ.form == Type.POINTER {
recv_typ = recv_typ.elt;
}
scope = recv_typ.scope;
}
// declare the function
obj := scope.Lookup(ident);
if obj == nil {
obj = Globals.NewObject(-1, Object.FUNC, ident);
obj.typ = typ;
// TODO do we need to set the primary type? probably...
P.DeclareInScope(scope, obj);
return obj;
}
// obj != NULL: possibly a forward declaration.
if (obj.kind != Object.FUNC) {
P.Error(-1, `"` + ident + `" is declared already`);
// Continue but do not insert this function into the scope.
obj = Globals.NewObject(-1, Object.FUNC, ident);
obj.typ = typ;
// TODO do we need to set the prymary type? probably...
return obj;
}
// We have a function with the same name.
/*
if (!EqualTypes(type, obj->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);
obj->set_type(type);
return obj;
}
*/
// We have a matching forward declaration. Use it.
return obj;
}
// ----------------------------------------------------------------------------
// Common productions
func (P *Parser) TryType() *Globals.Type;
func (P *Parser) ParseExpression() Globals.Expr;
func (P *Parser) TryStatement() bool;
func (P *Parser) ParseDeclaration();
func (P *Parser) ParseIdent() string {
P.Trace("Ident");
ident := "";
if P.tok == Scanner.IDENT {
ident = P.val;
if P.verbose > 0 {
P.PrintIndent();
print "Ident = \"", ident, "\"\n";
}
P.Next();
} else {
P.Expect(Scanner.IDENT); // use Expect() error handling
}
P.Ecart();
return ident;
}
func (P *Parser) ParseIdentDecl(kind int) *Globals.Object {
P.Trace("IdentDecl");
pos := P.pos;
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) ParseIdentList() {
P.Trace("IdentList");
P.ParseIdent();
for P.tok == Scanner.COMMA {
P.Next();
P.ParseIdent();
}
P.Ecart();
}
func (P *Parser) ParseQualifiedIdent(pos int, ident string) *Globals.Object {
P.Trace("QualifiedIdent");
if pos < 0 {
pos = P.pos;
ident = P.ParseIdent();
}
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.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;
} else {
if P.tok == Scanner.PERIOD {
P.Next();
P.ParseIdent();
}
P.Ecart();
return nil;
}
}
// ----------------------------------------------------------------------------
// Types
func (P *Parser) ParseType() *Globals.Type {
P.Trace("Type");
typ := P.TryType();
if typ == nil {
P.Error(P.pos, "type expected");
typ = Universe.bad_t;
}
P.Ecart();
return typ;
}
func (P *Parser) ParseVarType() *Globals.Type {
P.Trace("VarType");
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;
}
}
P.Ecart();
return typ;
}
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;
}
}
func (P *Parser) ParseArrayType() *Globals.Type {
P.Trace("ArrayType");
P.Expect(Scanner.LBRACK);
typ := Globals.NewType(Type.ARRAY);
if P.tok != Scanner.RBRACK {
// TODO set typ.len_
P.ParseExpression();
}
P.Expect(Scanner.RBRACK);
typ.elt = P.ParseVarType();
P.Ecart();
return typ;
}
func (P *Parser) ParseChannelType() *Globals.Type {
P.Trace("ChannelType");
P.Expect(Scanner.CHAN);
typ := Globals.NewType(Type.CHANNEL);
switch P.tok {
case Scanner.SEND:
typ.flags = Type.SEND;
P.Next();
case Scanner.RECV:
typ.flags = Type.RECV;
P.Next();
default:
typ.flags = Type.SEND + Type.RECV;
}
typ.elt = P.ParseVarType();
P.Ecart();
return typ;
}
func (P *Parser) ParseVarDeclList() {
P.Trace("VarDeclList");
list := P.ParseIdentDeclList(Object.VAR);
typ := P.ParseVarType();
for p := list.first; p != nil; p = p.next {
p.obj.typ = typ; // TODO should use/have set_type()
}
P.Ecart();
}
func (P *Parser) ParseParameterSection() {
P.Trace("ParameterSection");
P.ParseVarDeclList();
P.Ecart();
}
func (P *Parser) ParseParameterList() {
P.Trace("ParameterList");
P.ParseParameterSection();
for P.tok == Scanner.COMMA {
P.Next();
P.ParseParameterSection();
}
P.Ecart();
}
func (P *Parser) ParseParameters() {
P.Trace("Parameters");
P.Expect(Scanner.LPAREN);
if P.tok != Scanner.RPAREN {
P.ParseParameterList();
}
P.Expect(Scanner.RPAREN);
P.Ecart();
}
func (P *Parser) TryResult() bool {
P.Trace("Result (try)");
res := false;
if P.tok == Scanner.LPAREN {
// TODO: here we allow empty returns - should proably fix this
P.ParseParameters();
res = true;
} else {
res = P.TryType() != nil;
}
P.Ecart();
return res;
}
// Anonymous signatures
//
// (params)
// (params) type
// (params) (results)
// (recv) . (params)
// (recv) . (params) type
// (recv) . (params) (results)
func (P *Parser) ParseAnonymousSignature() *Globals.Type {
P.Trace("AnonymousSignature");
P.OpenScope();
P.level--;
sig := P.top_scope;
p0 := 0;
recv_pos := P.pos;
P.ParseParameters();
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);
}
// Named signatures
//
// name (params)
// name (params) type
// name (params) (results)
// (recv) name (params)
// (recv) name (params) type
// (recv) name (params) (results)
func (P *Parser) ParseNamedSignature() (name string, typ *Globals.Type) {
P.Trace("NamedSignature");
P.OpenScope();
P.level--;
sig := P.top_scope;
p0 := 0;
if P.tok == Scanner.LPAREN {
recv_pos := P.pos;
P.ParseParameters();
p0 = sig.entries.len_;
if (P.semantic_checks && p0 != 1) {
print "p0 = ", p0, "\n";
P.Error(recv_pos, "must have exactly one receiver")
panic "UNIMPLEMENTED (ParseNamedSignature)";
// TODO do something useful here
}
}
name = P.ParseIdent();
P.ParseParameters();
r0 := sig.entries.len_;
P.TryResult();
P.level++;
P.CloseScope();
P.Ecart();
return name, MakeFunctionType(sig, p0, r0, true);
}
func (P *Parser) ParseFunctionType() *Globals.Type {
P.Trace("FunctionType");
P.Expect(Scanner.FUNC);
typ := P.ParseAnonymousSignature();
P.Ecart();
return typ;
}
func (P *Parser) ParseMethodDecl() {
P.Trace("MethodDecl");
pos := P.pos;
ident := P.ParseIdent();
P.OpenScope();
P.level--;
sig := P.top_scope;
// dummy receiver (give it a name so it won't conflict with unnamed result)
sig.Insert(Globals.NewObject(pos, Object.VAR, ".recv"));
P.ParseParameters();
r0 := sig.entries.len_;
P.TryResult();
P.level++;
P.CloseScope();
P.Optional(Scanner.SEMICOLON);
obj := Globals.NewObject(pos, Object.FUNC, ident);
obj.typ = MakeFunctionType(sig, 1, r0, true);
P.Declare(obj);
P.Ecart();
}
func (P *Parser) ParseInterfaceType() *Globals.Type {
P.Trace("InterfaceType");
P.Expect(Scanner.INTERFACE);
P.Expect(Scanner.LBRACE);
P.OpenScope();
P.level--;
typ := Globals.NewType(Type.INTERFACE);
typ.scope = P.top_scope;
for P.tok == Scanner.IDENT {
P.ParseMethodDecl();
}
P.level++;
P.CloseScope();
P.Expect(Scanner.RBRACE);
P.Ecart();
return typ;
}
func (P *Parser) ParseMapType() *Globals.Type {
P.Trace("MapType");
P.Expect(Scanner.MAP);
P.Expect(Scanner.LBRACK);
typ := Globals.NewType(Type.MAP);
typ.key = P.ParseVarType();
P.Expect(Scanner.RBRACK);
typ.elt = P.ParseVarType();
P.Ecart();
return typ;
}
func (P *Parser) ParseFieldDecl() {
P.Trace("FieldDecl");
P.ParseVarDeclList();
P.Ecart();
}
func (P *Parser) ParseStructType() *Globals.Type {
P.Trace("StructType");
P.Expect(Scanner.STRUCT);
P.Expect(Scanner.LBRACE);
P.OpenScope();
P.level--;
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.level++;
P.CloseScope();
P.Expect(Scanner.RBRACE);
P.Ecart();
return typ;
}
func (P *Parser) ParsePointerType() *Globals.Type {
P.Trace("PointerType");
P.Expect(Scanner.MUL);
typ := Globals.NewType(Type.POINTER);
if P.semantic_checks {
if P.tok == Scanner.IDENT {
if P.Lookup(P.val) == nil {
// implicit forward declaration
// TODO very problematic: in which scope should the
// type object be declared? It's different if this
// is inside a struct or say in a var declaration.
// This code is only here for "compatibility" with 6g.
pos := P.pos;
obj := Globals.NewObject(pos, Object.TYPE, P.ParseIdent());
obj.typ = Globals.NewType(Type.UNDEF);
obj.typ.obj = obj; // primary type object
typ.elt = obj.typ;
// TODO obj should be declared, but scope is not clear
} else {
// type name
// (ParseType() doesn't permit incomplete types,
// so call ParseTypeName() here)
typ.elt = P.ParseTypeName();
}
} else {
typ.elt = P.ParseType();
}
// collect undefined pointer types
if typ.elt.form == Type.UNDEF {
P.undef_types.AddTyp(typ);
}
} else {
typ.elt = P.ParseType();
}
P.Ecart();
return typ;
}
// Returns nil if no type was found.
func (P *Parser) TryType() *Globals.Type {
P.Trace("Type (try)");
pos := P.pos;
var typ *Globals.Type = nil;
switch P.tok {
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();
}
if typ != nil && typ.form == Type.UNDEF {
P.Error(pos, "incomplete type");
}
P.Ecart();
return typ;
}
// ----------------------------------------------------------------------------
// Blocks
func (P *Parser) ParseStatement() {
P.Trace("Statement");
if !P.TryStatement() {
P.Error(P.pos, "statement expected");
P.Next(); // make progress
}
P.Ecart();
}
func (P *Parser) ParseStatementList() {
P.Trace("StatementList");
for P.TryStatement() {
P.Optional(Scanner.SEMICOLON);
}
P.Ecart();
}
func (P *Parser) ParseBlock(sig *Globals.Scope) {
P.Trace("Block");
P.Expect(Scanner.LBRACE);
P.OpenScope();
if sig != nil {
P.level--;
// add copies of the formal parameters to the function scope
scope := P.top_scope;
for p := sig.entries.first; p != nil; p = p.next {
scope.Insert(p.obj.Copy())
}
}
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);
P.Ecart();
}
// ----------------------------------------------------------------------------
// Expressions
func (P *Parser) ParseExpressionList() *Globals.List {
P.Trace("ExpressionList");
list := Globals.NewList();
P.ParseExpression();
list.AddInt(0); // TODO fix this - add correct list element
for P.tok == Scanner.COMMA {
P.Next();
P.ParseExpression();
list.AddInt(0); // TODO fix this - add correct list element
}
P.Ecart();
return list;
}
func (P *Parser) ParseNew() Globals.Expr {
P.Trace("New");
P.Expect(Scanner.NEW);
P.Expect(Scanner.LPAREN);
P.ParseType();
if P.tok == Scanner.COMMA {
P.Next();
P.ParseExpressionList()
}
P.Expect(Scanner.RPAREN);
P.Ecart();
return nil;
}
func (P *Parser) ParseFunctionLit() Globals.Expr {
P.Trace("FunctionLit");
typ := P.ParseFunctionType();
P.ParseBlock(typ.scope);
P.Ecart();
return nil;
}
func (P *Parser) ParseExpressionPair() {
P.Trace("ExpressionPair");
P.ParseExpression();
P.Expect(Scanner.COLON);
P.ParseExpression();
P.Ecart();
}
func (P *Parser) ParseExpressionPairList() {
P.Trace("ExpressionPairList");
P.ParseExpressionPair();
for (P.tok == Scanner.COMMA) {
P.ParseExpressionPair();
}
P.Ecart();
}
func (P *Parser) ParseBuiltinCall() Globals.Expr {
P.Trace("BuiltinCall");
P.ParseExpressionList(); // TODO should be optional
P.Ecart();
return nil;
}
func (P *Parser) ParseCompositeLit(typ *Globals.Type) Globals.Expr {
P.Trace("CompositeLit");
// TODO I think we should use {} instead of () for
// composite literals to syntactically distinguish
// them from conversions. For now: allow both.
var paren int;
if P.tok == Scanner.LPAREN {
P.Next();
paren = Scanner.RPAREN;
} else {
P.Expect(Scanner.LBRACE);
paren = Scanner.RBRACE;
}
// TODO: should allow trailing ','
if P.tok != paren {
P.ParseExpression();
if P.tok == Scanner.COMMA {
P.Next();
if P.tok != paren {
P.ParseExpressionList();
}
} else if P.tok == Scanner.COLON {
P.Next();
P.ParseExpression();
if P.tok == Scanner.COMMA {
P.Next();
if P.tok != paren {
P.ParseExpressionPairList();
}
}
}
}
P.Expect(paren);
P.Ecart();
return nil;
}
func (P *Parser) ParseOperand(pos int, ident string) Globals.Expr {
P.Trace("Operand");
if pos < 0 && P.tok == Scanner.IDENT {
// no look-ahead yet
pos = P.pos;
ident = P.val;
P.Next();
}
if pos >= 0 {
// TODO set these up properly in the Universe
if ident == "panic" || ident == "print" {
P.ParseBuiltinCall();
goto exit;
}
P.ParseQualifiedIdent(pos, ident);
// TODO enable code below
/*
if obj.kind == Object.TYPE {
P.ParseCompositeLit(obj.typ);
}
*/
goto exit;
}
switch P.tok {
case Scanner.IDENT:
panic "UNREACHABLE";
case Scanner.LPAREN:
P.Next();
P.ParseExpression();
P.Expect(Scanner.RPAREN);
case Scanner.STRING: fallthrough;
case Scanner.NUMBER: fallthrough;
case Scanner.NIL: fallthrough;
case Scanner.IOTA: fallthrough;
case Scanner.TRUE: fallthrough;
case Scanner.FALSE:
P.Next();
case Scanner.FUNC:
P.ParseFunctionLit();
case Scanner.NEW:
P.ParseNew();
default:
typ := P.TryType();
if typ != nil {
P.ParseCompositeLit(typ);
} else {
P.Error(P.pos, "operand expected");
P.Next(); // make progress
}
}
exit:
P.Ecart();
return nil;
}
func (P *Parser) ParseSelectorOrTypeAssertion() Globals.Expr {
P.Trace("SelectorOrTypeAssertion");
P.Expect(Scanner.PERIOD);
if P.tok == Scanner.IDENT {
P.ParseIdent();
} else {
P.Expect(Scanner.LPAREN);
P.ParseType();
P.Expect(Scanner.RPAREN);
}
P.Ecart();
return nil;
}
func (P *Parser) ParseIndexOrSlice() Globals.Expr {
P.Trace("IndexOrSlice");
P.Expect(Scanner.LBRACK);
P.ParseExpression();
if P.tok == Scanner.COLON {
P.Next();
P.ParseExpression();
}
P.Expect(Scanner.RBRACK);
P.Ecart();
return nil;
}
func (P *Parser) ParseCall() Globals.Expr {
P.Trace("Call");
P.Expect(Scanner.LPAREN);
if P.tok != Scanner.RPAREN {
P.ParseExpressionList();
}
P.Expect(Scanner.RPAREN);
P.Ecart();
return nil;
}
func (P *Parser) ParsePrimaryExpr(pos int, ident string) Globals.Expr {
P.Trace("PrimaryExpr");
P.ParseOperand(pos, ident);
for {
switch P.tok {
case Scanner.PERIOD:
P.ParseSelectorOrTypeAssertion();
case Scanner.LBRACK:
P.ParseIndexOrSlice();
case Scanner.LPAREN:
P.ParseCall();
default:
P.Ecart();
return nil;
}
}
P.Ecart();
return nil;
}
func (P *Parser) ParsePrimaryExprList() {
P.Trace("PrimaryExprList");
P.ParsePrimaryExpr(-1, "");
for P.tok == Scanner.COMMA {
P.Next();
P.ParsePrimaryExpr(-1, "");
}
P.Ecart();
}
func (P *Parser) ParseUnaryExpr() Globals.Expr {
P.Trace("UnaryExpr");
switch P.tok {
case Scanner.ADD: fallthrough;
case Scanner.SUB: fallthrough;
case Scanner.NOT: fallthrough;
case Scanner.XOR: fallthrough;
case Scanner.MUL: fallthrough;
case Scanner.RECV: fallthrough;
case Scanner.AND:
P.Next();
P.ParseUnaryExpr();
P.Ecart();
return nil; // TODO fix this
}
P.ParsePrimaryExpr(-1, "");
P.Ecart();
return nil; // TODO fix this
}
func Precedence(tok int) int {
// TODO should use a map or array here for lookup
switch tok {
case Scanner.LOR:
return 1;
case Scanner.LAND:
return 2;
case Scanner.SEND, Scanner.RECV:
return 3;
case Scanner.EQL, Scanner.NEQ, Scanner.LSS, Scanner.LEQ, Scanner.GTR, Scanner.GEQ:
return 4;
case Scanner.ADD, Scanner.SUB, Scanner.OR, Scanner.XOR:
return 5;
case Scanner.MUL, Scanner.QUO, Scanner.REM, Scanner.SHL, Scanner.SHR, Scanner.AND:
return 6;
}
return 0;
}
func (P *Parser) ParseBinaryExpr(pos int, ident string, prec1 int) Globals.Expr {
P.Trace("BinaryExpr");
var x Globals.Expr;
if pos >= 0 {
x = P.ParsePrimaryExpr(pos, ident);
} else {
x = P.ParseUnaryExpr();
}
for prec := Precedence(P.tok); prec >= prec1; prec-- {
for Precedence(P.tok) == prec {
e := new(AST.BinaryExpr);
e.typ_ = Universe.undef_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;
}
}
P.Ecart();
return x;
}
// Expressions where the first token may be an identifier which has already
// been consumed. If the identifier is present, pos is the identifier position,
// otherwise pos must be < 0 (and ident is ignored).
func (P *Parser) ParseIdentExpression(pos int, ident string) Globals.Expr {
P.Trace("IdentExpression");
indent := P.indent;
x := P.ParseBinaryExpr(pos, ident, 1);
if indent != P.indent {
panic "imbalanced tracing code (Expression)";
}
P.Ecart();
return x;
}
func (P *Parser) ParseExpression() Globals.Expr {
P.Trace("Expression");
x := P.ParseIdentExpression(-1, "");
P.Ecart();
return x;
}
// ----------------------------------------------------------------------------
// Statements
func (P *Parser) ConvertToExprList(pos_list, ident_list, expr_list *Globals.List) {
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);
}
}
expr_list.AddInt(0); // TODO fix this - add correct expression
}
ident_list.Clear();
}
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 {
pos, ident = P.pos, P.val;
P.Next();
switch P.tok {
case Scanner.COMMA,
Scanner.COLON,
Scanner.DEFINE,
Scanner.ASSIGN,
Scanner.ADD_ASSIGN,
Scanner.SUB_ASSIGN,
Scanner.MUL_ASSIGN,
Scanner.QUO_ASSIGN,
Scanner.REM_ASSIGN,
Scanner.AND_ASSIGN,
Scanner.OR_ASSIGN,
Scanner.XOR_ASSIGN,
Scanner.SHL_ASSIGN,
Scanner.SHR_ASSIGN:
// identifier is not part of a more complicated expression
just_ident = true;
}
}
if just_ident {
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
}
P.Ecart();
}
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();
P.ParseIdentOrExpr(pos_list, ident_list, expr_list);
for P.tok == Scanner.COMMA {
P.Next();
P.ParseIdentOrExpr(pos_list, ident_list, expr_list);
}
P.Ecart();
return pos_list, ident_list, expr_list;
}
func (P *Parser) ParseSimpleStat() {
P.Trace("SimpleStat");
// If we see an identifier, we don't know if it's part of a
// label declaration, (multiple) variable declaration, assignment,
// or simply an expression, without looking ahead.
// 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
// (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 {
P.Error(P.pos, "illegal label declaration");
}
P.Next();
case Scanner.DEFINE:
// variable declaration
if P.semantic_checks && ident_list.len_ == 0 {
P.Error(P.pos, "illegal left-hand side for declaration");
}
P.Next();
pos := P.pos;
val_list := P.ParseExpressionList();
if P.semantic_checks && val_list.len_ != ident_list.len_ {
P.Error(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
}
}
case Scanner.ASSIGN: fallthrough;
case Scanner.ADD_ASSIGN: fallthrough;
case Scanner.SUB_ASSIGN: fallthrough;
case Scanner.MUL_ASSIGN: fallthrough;
case Scanner.QUO_ASSIGN: fallthrough;
case Scanner.REM_ASSIGN: fallthrough;
case Scanner.AND_ASSIGN: fallthrough;
case Scanner.OR_ASSIGN: fallthrough;
case Scanner.XOR_ASSIGN: fallthrough;
case Scanner.SHL_ASSIGN: fallthrough;
case Scanner.SHR_ASSIGN:
P.ConvertToExprList(pos_list, ident_list, expr_list);
P.Next();
pos := P.pos;
val_list := P.ParseExpressionList();
if P.semantic_checks && val_list.len_ != expr_list.len_ {
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 {
P.Error(P.pos, "no expression list allowed");
}
if P.tok == Scanner.INC || P.tok == Scanner.DEC {
P.Next();
}
}
P.Ecart();
}
func (P *Parser) ParseGoStat() {
P.Trace("GoStat");
P.Expect(Scanner.GO);
P.ParseExpression();
P.Ecart();
}
func (P *Parser) ParseReturnStat() {
P.Trace("ReturnStat");
P.Expect(Scanner.RETURN);
if P.tok != Scanner.SEMICOLON && P.tok != Scanner.RBRACE {
P.ParseExpressionList();
}
P.Ecart();
}
func (P *Parser) ParseControlFlowStat(tok int) {
P.Trace("ControlFlowStat");
P.Expect(tok);
if P.tok == Scanner.IDENT {
P.ParseIdent();
}
P.Ecart();
}
func (P *Parser) ParseIfStat() *AST.IfStat {
P.Trace("IfStat");
P.Expect(Scanner.IF);
P.OpenScope();
if P.tok != Scanner.LBRACE {
if P.tok != Scanner.SEMICOLON {
P.ParseSimpleStat();
}
if P.tok == Scanner.SEMICOLON {
P.Next();
if P.tok != Scanner.LBRACE {
P.ParseExpression();
}
}
}
P.ParseBlock(nil);
if P.tok == Scanner.ELSE {
P.Next();
if P.tok == Scanner.IF {
P.ParseIfStat();
} else {
// TODO should be P.ParseBlock()
P.ParseStatement();
}
}
P.CloseScope();
P.Ecart();
}
func (P *Parser) ParseForStat() {
P.Trace("ForStat");
P.Expect(Scanner.FOR);
P.OpenScope();
if P.tok != Scanner.LBRACE {
if P.tok != Scanner.SEMICOLON {
P.ParseSimpleStat();
}
if P.tok == Scanner.SEMICOLON {
P.Next();
if P.tok != Scanner.SEMICOLON {
P.ParseExpression();
}
P.Expect(Scanner.SEMICOLON);
if P.tok != Scanner.LBRACE {
P.ParseSimpleStat();
}
}
}
P.ParseBlock(nil);
P.CloseScope();
P.Ecart();
}
func (P *Parser) ParseCase() {
P.Trace("Case");
if P.tok == Scanner.CASE {
P.Next();
P.ParseExpressionList();
} else {
P.Expect(Scanner.DEFAULT);
}
P.Expect(Scanner.COLON);
P.Ecart();
}
func (P *Parser) ParseCaseList() {
P.Trace("CaseList");
P.ParseCase();
for P.tok == Scanner.CASE || P.tok == Scanner.DEFAULT {
P.ParseCase();
}
P.Ecart();
}
func (P *Parser) ParseCaseClause() {
P.Trace("CaseClause");
P.ParseCaseList();
if P.tok != Scanner.FALLTHROUGH && P.tok != Scanner.RBRACE {
P.ParseStatementList();
P.Optional(Scanner.SEMICOLON);
}
if P.tok == Scanner.FALLTHROUGH {
P.Next();
P.Optional(Scanner.SEMICOLON);
}
P.Ecart();
}
func (P *Parser) ParseSwitchStat() {
P.Trace("SwitchStat");
P.Expect(Scanner.SWITCH);
P.OpenScope();
if P.tok != Scanner.LBRACE {
if P.tok != Scanner.SEMICOLON {
P.ParseSimpleStat();
}
if P.tok == Scanner.SEMICOLON {
P.Next();
if P.tok != Scanner.LBRACE {
P.ParseExpression();
}
}
}
P.Expect(Scanner.LBRACE);
for P.tok == Scanner.CASE || P.tok == Scanner.DEFAULT {
P.ParseCaseClause();
}
P.Expect(Scanner.RBRACE);
P.CloseScope();
P.Ecart();
}
func (P *Parser) ParseCommCase() {
P.Trace("CommCase");
if P.tok == Scanner.CASE {
P.Next();
if P.tok == Scanner.GTR {
// send
P.Next();
P.ParseExpression();
P.Expect(Scanner.EQL);
P.ParseExpression();
} else {
// receive
if P.tok != Scanner.LSS {
P.ParseIdent();
P.Expect(Scanner.ASSIGN);
}
P.Expect(Scanner.LSS);
P.ParseExpression();
}
} else {
P.Expect(Scanner.DEFAULT);
}
P.Expect(Scanner.COLON);
P.Ecart();
}
func (P *Parser) ParseCommClause() {
P.Trace("CommClause");
P.ParseCommCase();
if P.tok != Scanner.CASE && P.tok != Scanner.DEFAULT && P.tok != Scanner.RBRACE {
P.ParseStatementList();
P.Optional(Scanner.SEMICOLON);
}
P.Ecart();
}
func (P *Parser) ParseRangeStat() bool {
P.Trace("RangeStat");
P.Expect(Scanner.RANGE);
P.ParseIdentList();
P.Expect(Scanner.DEFINE);
P.ParseExpression();
P.ParseBlock(nil);
P.Ecart();
}
func (P *Parser) ParseSelectStat() bool {
P.Trace("SelectStat");
P.Expect(Scanner.SELECT);
P.Expect(Scanner.LBRACE);
for P.tok != Scanner.RBRACE && P.tok != Scanner.EOF {
P.ParseCommClause();
}
P.Next();
P.Ecart();
}
func (P *Parser) TryStatement() bool {
P.Trace("Statement (try)");
indent := P.indent;
res := true;
switch P.tok {
case Scanner.CONST: fallthrough;
case Scanner.TYPE: fallthrough;
case Scanner.VAR:
P.ParseDeclaration();
case Scanner.FUNC:
// for now we do not allow local function declarations
fallthrough;
case Scanner.MUL, Scanner.SEND, Scanner.RECV, Scanner.IDENT, Scanner.LPAREN:
P.ParseSimpleStat();
case Scanner.GO:
P.ParseGoStat();
case Scanner.RETURN:
P.ParseReturnStat();
case Scanner.BREAK, Scanner.CONTINUE, Scanner.GOTO:
P.ParseControlFlowStat(P.tok);
case Scanner.LBRACE:
P.ParseBlock(nil);
case Scanner.IF:
P.ParseIfStat();
case Scanner.FOR:
P.ParseForStat();
case Scanner.SWITCH:
P.ParseSwitchStat();
case Scanner.RANGE:
P.ParseRangeStat();
case Scanner.SELECT:
P.ParseSelectStat();
default:
// no statement found
res = false;
}
if indent != P.indent {
panic "imbalanced tracing code (Statement)"
}
P.Ecart();
return res;
}
// ----------------------------------------------------------------------------
// Declarations
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 {
obj = P.ParseIdentDecl(Object.PACKAGE);
}
if (P.semantic_checks && P.tok == Scanner.STRING) {
// TODO eventually the scanner should strip the quotes
pkg_name := P.val[1 : len(P.val) - 1]; // strip quotes
pkg := Import.Import(P.comp, pkg_name);
if pkg != nil {
pno := pkg.obj.pnolev; // preserve pno
if obj == nil {
// use original package name
obj = pkg.obj;
P.Declare(obj); // this changes (pkg.)obj.pnolev!
}
obj.pnolev = pno; // correct pno
} else {
P.Error(P.pos, `import of "` + pkg_name + `" failed`);
}
P.Next();
} else {
P.Expect(Scanner.STRING); // use Expect() error handling
}
P.Ecart();
}
func (P *Parser) ParseConstSpec(exported bool) {
P.Trace("ConstSpec");
list := P.ParseIdentDeclList(Object.CONST);
typ := P.TryType();
if typ != nil {
for p := list.first; p != nil; p = p.next {
p.obj.exported = exported;
p.obj.typ = typ; // TODO should use/have set_type()!
}
}
if P.tok == Scanner.ASSIGN {
P.Next();
P.ParseExpressionList();
}
P.Ecart();
}
func (P *Parser) ParseTypeSpec(exported bool) {
P.Trace("TypeSpec");
pos := P.pos;
ident := P.ParseIdent();
obj := P.top_scope.Lookup(ident); // only lookup in top scope!
if obj != nil {
// name already declared - 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.exported = exported;
obj.typ = Globals.NewType(Type.UNDEF);
obj.typ.obj = obj; // primary type object
P.Declare(obj);
}
// If the next token is an identifier and we have a legal program,
// it must be a typename. In that case this declaration introduces
// an alias type.
make_alias := P.tok == Scanner.IDENT;
// If we have an explicit forward declaration, TryType will not
// find a type and return nil.
typ := P.TryType();
if typ != nil {
if make_alias {
alias := Globals.NewType(Type.ALIAS);
alias.elt = typ;
typ = alias;
}
obj.typ = typ;
if typ.obj == nil {
typ.obj = obj; // primary type object
}
}
P.Ecart();
}
func (P *Parser) ParseVarSpec(exported bool) {
P.Trace("VarSpec");
list := P.ParseIdentDeclList(Object.VAR);
if P.tok == Scanner.ASSIGN {
P.Next();
P.ParseExpressionList();
} else {
typ := P.ParseVarType();
for p := list.first; p != nil; p = p.next {
p.obj.typ = typ;
}
if P.tok == Scanner.ASSIGN {
P.Next();
P.ParseExpressionList();
}
}
P.Ecart();
}
// 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);
default: panic "UNREACHABLE";
}
}
func (P *Parser) ParseDecl(exported bool, keyword int) {
P.Trace("Decl");
P.Expect(keyword);
if P.tok == Scanner.LPAREN {
P.Next();
for P.tok == Scanner.IDENT {
P.ParseSpec(exported, keyword);
if P.tok != Scanner.RPAREN {
// P.Expect(Scanner.SEMICOLON);
P.Optional(Scanner.SEMICOLON); // TODO this seems wrong! (needed for math.go)
}
}
P.Next();
} else {
P.ParseSpec(exported, keyword);
}
P.Ecart();
}
func (P *Parser) ParseFuncDecl(exported bool) {
P.Trace("FuncDecl");
P.Expect(Scanner.FUNC);
ident, typ := P.ParseNamedSignature();
obj := P.DeclareFunc(ident, typ); // need obj later for statements
obj.exported = exported;
if P.tok == Scanner.SEMICOLON {
// forward declaration
P.Next();
} else {
P.ParseBlock(typ.scope);
}
P.Ecart();
}
func (P *Parser) ParseExportDecl() {
P.Trace("ExportDecl");
// TODO this needs to be clarified - the current syntax is
// "everything goes" - sigh...
//P.Expect(Scanner.EXPORT);
has_paren := false;
if P.tok == Scanner.LPAREN {
P.Next();
has_paren = true;
}
for P.tok == Scanner.IDENT {
P.exports.AddStr(P.ParseIdent());
P.Optional(Scanner.COMMA); // TODO this seems wrong
}
if has_paren {
P.Expect(Scanner.RPAREN)
}
P.Ecart();
}
func (P *Parser) ParseDeclaration() {
P.Trace("Declaration");
indent := P.indent;
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();
}
switch P.tok {
case Scanner.CONST, Scanner.TYPE, Scanner.VAR:
P.ParseDecl(exported, P.tok);
case Scanner.FUNC:
P.ParseFuncDecl(exported);
case Scanner.EXPORT:
if exported {
P.Error(P.pos, "cannot mark export declaration for export");
}
P.Next();
P.ParseExportDecl();
default:
if exported && (P.tok == Scanner.IDENT || P.tok == Scanner.LPAREN) {
P.ParseExportDecl();
} else {
P.Error(P.pos, "declaration expected");
P.Next(); // make progress
}
}
if indent != P.indent {
panic "imbalanced tracing code (Declaration)"
}
P.Ecart();
}
// ----------------------------------------------------------------------------
// Program
func (P *Parser) ResolveUndefTypes() {
if !P.semantic_checks {
return;
}
for p := P.undef_types.first; p != nil; p = p.next {
typ := p.typ;
if typ.form != Type.POINTER {
panic "unresolved types should be pointers only";
}
if typ.elt.form != Type.UNDEF {
panic "unresolved pointer should point to undefined type";
}
obj := typ.elt.obj;
typ.elt = obj.typ;
if typ.elt.form == Type.UNDEF {
P.Error(obj.pos, `"` + obj.ident + `" is not declared`);
}
}
}
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);
if obj != nil {
obj.exported = true;
// For now we export deep
// TODO this should change eventually - we need selective export
if obj.kind == Object.TYPE {
typ := obj.typ;
if typ.form == Type.STRUCT || typ.form == Type.INTERFACE {
scope := typ.scope;
for p := scope.entries.first; p != nil; p = p.next {
p.obj.exported = true;
}
}
}
} else {
// TODO need to report proper src position
P.Error(-1, `"` + p.str + `" is not declared - cannot be exported`);
}
}
}
func (P *Parser) ParseProgram() {
P.Trace("Program");
P.OpenScope();
P.Expect(Scanner.PACKAGE);
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);
{ if P.level != 0 {
panic "incorrect scope level";
}
P.OpenScope();
pkg.scope = P.top_scope;
for P.tok == Scanner.IMPORT {
P.ParseDecl(false, Scanner.IMPORT);
P.Optional(Scanner.SEMICOLON);
}
for P.tok != Scanner.EOF {
P.ParseDeclaration();
P.Optional(Scanner.SEMICOLON);
}
P.ResolveUndefTypes();
P.MarkExports();
P.CloseScope();
if P.level != 0 {
panic "incorrect scope level";
}
}
P.CloseScope();
P.Ecart();
}