mirror of
https://github.com/golang/go.git
synced 2025-05-16 21:04:38 +00:00
- converted more of AST and parser to use interfaces and explicit structs for individual Go constructs (can be replaced now with interface calls such that the parser becomes AST structure independent, as suggested by rsc) - added more tests (find all .go files under GOROOT) - (temporarily) lost html links for identifiers when generating html output - TODO: lots of cleanups R=r OCL=25518 CL=25518
1698 lines
34 KiB
Go
1698 lines
34 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 (
|
|
"flag";
|
|
"fmt";
|
|
"vector";
|
|
Scanner "scanner";
|
|
AST "ast";
|
|
SymbolTable "symboltable";
|
|
)
|
|
|
|
|
|
type Parser struct {
|
|
// Tracing/debugging
|
|
trace, sixg, deps bool;
|
|
indent uint;
|
|
|
|
// Scanner
|
|
scanner *Scanner.Scanner;
|
|
comments *vector.Vector;
|
|
|
|
// Scanner.Token
|
|
pos int; // token source position
|
|
tok int; // one token look-ahead
|
|
val string; // token value (for IDENT, NUMBER, STRING only)
|
|
|
|
// Non-syntactic parser control
|
|
opt_semi bool; // true if semicolon separator is optional in statement list
|
|
|
|
// Nesting levels
|
|
scope_lev int; // 0 = global scope, 1 = function scope of global functions, etc.
|
|
|
|
// Scopes
|
|
top_scope *SymbolTable.Scope;
|
|
};
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// Elementary support
|
|
|
|
func unimplemented() {
|
|
panic("unimplemented");
|
|
}
|
|
|
|
|
|
func unreachable() {
|
|
panic("unreachable");
|
|
}
|
|
|
|
|
|
func assert(pred bool) {
|
|
if !pred {
|
|
panic("assertion failed");
|
|
}
|
|
}
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// Parsing support
|
|
|
|
func (P *Parser) printIndent() {
|
|
i := P.indent;
|
|
// reduce printing time by a factor of 2 or more
|
|
for ; i > 10; i -= 10 {
|
|
fmt.Printf(". . . . . . . . . . ");
|
|
}
|
|
for ; i > 0; i-- {
|
|
fmt.Printf(". ");
|
|
}
|
|
}
|
|
|
|
|
|
func trace(P *Parser, msg string) *Parser {
|
|
P.printIndent();
|
|
fmt.Printf("%s (\n", msg);
|
|
P.indent++;
|
|
return P;
|
|
}
|
|
|
|
|
|
func un/*trace*/(P *Parser) {
|
|
P.indent--;
|
|
P.printIndent();
|
|
fmt.Printf(")\n");
|
|
}
|
|
|
|
|
|
func (P *Parser) next0() {
|
|
P.pos, P.tok, P.val = P.scanner.Scan();
|
|
P.opt_semi = false;
|
|
|
|
if P.trace {
|
|
P.printIndent();
|
|
switch P.tok {
|
|
case Scanner.IDENT, Scanner.INT, Scanner.FLOAT, Scanner.STRING:
|
|
fmt.Printf("[%d] %s = %s\n", P.pos, Scanner.TokenString(P.tok), P.val);
|
|
case Scanner.LPAREN:
|
|
// don't print '(' - screws up selection in terminal window
|
|
fmt.Printf("[%d] LPAREN\n", P.pos);
|
|
case Scanner.RPAREN:
|
|
// don't print ')' - screws up selection in terminal window
|
|
fmt.Printf("[%d] RPAREN\n", P.pos);
|
|
default:
|
|
fmt.Printf("[%d] %s\n", P.pos, Scanner.TokenString(P.tok));
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
func (P *Parser) next() {
|
|
for P.next0(); P.tok == Scanner.COMMENT; P.next0() {
|
|
P.comments.Push(AST.NewComment(P.pos, P.val));
|
|
}
|
|
}
|
|
|
|
|
|
func (P *Parser) Open(trace, sixg, deps bool, scanner *Scanner.Scanner) {
|
|
P.trace = trace;
|
|
P.sixg = sixg;
|
|
P.deps = deps;
|
|
P.indent = 0;
|
|
|
|
P.scanner = scanner;
|
|
P.comments = vector.New(0);
|
|
|
|
P.next();
|
|
P.scope_lev = 0;
|
|
}
|
|
|
|
|
|
func (P *Parser) error(pos int, msg string) {
|
|
P.scanner.Error(pos, msg);
|
|
}
|
|
|
|
|
|
func (P *Parser) expect(tok int) {
|
|
if P.tok != tok {
|
|
msg := "expected '" + Scanner.TokenString(tok) + "', found '" + Scanner.TokenString(P.tok) + "'";
|
|
switch P.tok {
|
|
case Scanner.IDENT, Scanner.INT, Scanner.FLOAT, Scanner.STRING:
|
|
msg += " " + P.val;
|
|
}
|
|
P.error(P.pos, msg);
|
|
}
|
|
P.next(); // make progress in any case
|
|
}
|
|
|
|
|
|
func (P *Parser) OptSemicolon() {
|
|
if P.tok == Scanner.SEMICOLON {
|
|
P.next();
|
|
}
|
|
}
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// Scopes
|
|
|
|
func (P *Parser) openScope() {
|
|
P.top_scope = SymbolTable.NewScope(P.top_scope);
|
|
}
|
|
|
|
|
|
func (P *Parser) closeScope() {
|
|
P.top_scope = P.top_scope.Parent;
|
|
}
|
|
|
|
|
|
/*
|
|
func (P *Parser) declareInScope(scope *SymbolTable.Scope, x AST.Expr, kind int, typ *AST.Type) {
|
|
if P.scope_lev < 0 {
|
|
panic("cannot declare objects in other packages");
|
|
}
|
|
if ident, ok := x.(*AST.Ident); ok { // ignore bad exprs
|
|
obj := ident.Obj;
|
|
obj.Kind = kind;
|
|
//TODO fix typ setup!
|
|
//obj.Typ = typ;
|
|
obj.Pnolev = P.scope_lev;
|
|
switch {
|
|
case scope.LookupLocal(obj.Ident) == nil:
|
|
scope.Insert(obj);
|
|
case kind == SymbolTable.TYPE:
|
|
// possibly a forward declaration
|
|
case kind == SymbolTable.FUNC:
|
|
// possibly a forward declaration
|
|
default:
|
|
P.error(obj.Pos, `"` + obj.Ident + `" is declared already`);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// Declare a comma-separated list of idents or a single ident.
|
|
func (P *Parser) declare(x AST.Expr, kind int, typ *AST.Type) {
|
|
for {
|
|
p, ok := x.(*AST.BinaryExpr);
|
|
if ok && p.Tok == Scanner.COMMA {
|
|
P.declareInScope(P.top_scope, p.X, kind, typ);
|
|
x = p.Y;
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
P.declareInScope(P.top_scope, x, kind, typ);
|
|
}
|
|
*/
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// Common productions
|
|
|
|
func (P *Parser) tryType() AST.Expr;
|
|
func (P *Parser) parseExpression(prec int) AST.Expr;
|
|
func (P *Parser) parseStatement() AST.Stat;
|
|
func (P *Parser) parseDeclaration() AST.Decl;
|
|
|
|
|
|
// If scope != nil, lookup identifier in scope. Otherwise create one.
|
|
func (P *Parser) parseIdent(scope *SymbolTable.Scope) *AST.Ident {
|
|
if P.trace {
|
|
defer un(trace(P, "Ident"));
|
|
}
|
|
|
|
if P.tok == Scanner.IDENT {
|
|
var obj *SymbolTable.Object;
|
|
if scope != nil {
|
|
obj = scope.Lookup(P.val);
|
|
}
|
|
if obj == nil {
|
|
obj = SymbolTable.NewObject(P.pos, SymbolTable.NONE, P.val);
|
|
} else {
|
|
assert(obj.Kind != SymbolTable.NONE);
|
|
}
|
|
x := &AST.Ident(P.pos, obj);
|
|
P.next();
|
|
return x;
|
|
}
|
|
|
|
P.expect(Scanner.IDENT); // use expect() error handling
|
|
return &AST.Ident(P.pos, nil);
|
|
}
|
|
|
|
|
|
func (P *Parser) parseIdentList(x AST.Expr) AST.Expr {
|
|
if P.trace {
|
|
defer un(trace(P, "IdentList"));
|
|
}
|
|
|
|
var last *AST.BinaryExpr;
|
|
if x == nil {
|
|
x = P.parseIdent(nil);
|
|
}
|
|
for P.tok == Scanner.COMMA {
|
|
pos := P.pos;
|
|
P.next();
|
|
y := P.parseIdent(nil);
|
|
if last == nil {
|
|
last = &AST.BinaryExpr(pos, Scanner.COMMA, x, y);
|
|
x = last;
|
|
} else {
|
|
last.Y = &AST.BinaryExpr(pos, Scanner.COMMA, last.Y, y);
|
|
last = last.Y.(*AST.BinaryExpr);
|
|
}
|
|
}
|
|
|
|
return x;
|
|
}
|
|
|
|
|
|
func (P *Parser) parseIdentList2(x AST.Expr) []*AST.Ident {
|
|
if P.trace {
|
|
defer un(trace(P, "IdentList"));
|
|
}
|
|
|
|
list := vector.New(0);
|
|
if x == nil {
|
|
x = P.parseIdent(nil);
|
|
}
|
|
list.Push(x);
|
|
for P.tok == Scanner.COMMA {
|
|
P.next();
|
|
list.Push(P.parseIdent(nil));
|
|
}
|
|
|
|
// convert vector
|
|
idents := make([]*AST.Ident, list.Len());
|
|
for i := 0; i < list.Len(); i++ {
|
|
idents[i] = list.At(i).(*AST.Ident);
|
|
}
|
|
return idents;
|
|
}
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// Types
|
|
|
|
func (P *Parser) parseType() AST.Expr {
|
|
if P.trace {
|
|
defer un(trace(P, "Type"));
|
|
}
|
|
|
|
t := P.tryType();
|
|
if t == nil {
|
|
P.error(P.pos, "type expected");
|
|
t = &AST.BadExpr(P.pos);
|
|
}
|
|
|
|
return t;
|
|
}
|
|
|
|
|
|
func (P *Parser) parseVarType() AST.Expr {
|
|
if P.trace {
|
|
defer un(trace(P, "VarType"));
|
|
}
|
|
|
|
return P.parseType();
|
|
}
|
|
|
|
|
|
func (P *Parser) parseQualifiedIdent() AST.Expr {
|
|
if P.trace {
|
|
defer un(trace(P, "QualifiedIdent"));
|
|
}
|
|
|
|
var x AST.Expr = P.parseIdent(P.top_scope);
|
|
for P.tok == Scanner.PERIOD {
|
|
pos := P.pos;
|
|
P.next();
|
|
y := P.parseIdent(nil);
|
|
x = &AST.Selector(pos, x, y);
|
|
}
|
|
|
|
return x;
|
|
}
|
|
|
|
|
|
func (P *Parser) parseTypeName() AST.Expr {
|
|
if P.trace {
|
|
defer un(trace(P, "TypeName"));
|
|
}
|
|
|
|
return P.parseQualifiedIdent();
|
|
}
|
|
|
|
|
|
func (P *Parser) parseArrayType() *AST.ArrayType {
|
|
if P.trace {
|
|
defer un(trace(P, "ArrayType"));
|
|
}
|
|
|
|
pos := P.pos;
|
|
P.expect(Scanner.LBRACK);
|
|
var len AST.Expr;
|
|
if P.tok == Scanner.ELLIPSIS {
|
|
len = &AST.Ellipsis(P.pos);
|
|
P.next();
|
|
} else if P.tok != Scanner.RBRACK {
|
|
len = P.parseExpression(1);
|
|
}
|
|
P.expect(Scanner.RBRACK);
|
|
elt := P.parseType();
|
|
|
|
return &AST.ArrayType(pos, len, elt);
|
|
}
|
|
|
|
|
|
func (P *Parser) parseChannelType() *AST.ChannelType {
|
|
if P.trace {
|
|
defer un(trace(P, "ChannelType"));
|
|
}
|
|
|
|
pos := P.pos;
|
|
mode := AST.FULL;
|
|
if P.tok == Scanner.CHAN {
|
|
P.next();
|
|
if P.tok == Scanner.ARROW {
|
|
P.next();
|
|
mode = AST.SEND;
|
|
}
|
|
} else {
|
|
P.expect(Scanner.ARROW);
|
|
P.expect(Scanner.CHAN);
|
|
mode = AST.RECV;
|
|
}
|
|
val := P.parseVarType();
|
|
|
|
return &AST.ChannelType(pos, mode, val);
|
|
}
|
|
|
|
|
|
func (P *Parser) tryParameterType() AST.Expr {
|
|
if P.tok == Scanner.ELLIPSIS {
|
|
pos := P.tok;
|
|
P.next();
|
|
return &AST.Ellipsis(pos);
|
|
}
|
|
return P.tryType();
|
|
}
|
|
|
|
|
|
func (P *Parser) parseParameterType() AST.Expr {
|
|
typ := P.tryParameterType();
|
|
if typ == nil {
|
|
P.error(P.tok, "type expected");
|
|
typ = &AST.BadExpr(P.pos);
|
|
}
|
|
return typ;
|
|
}
|
|
|
|
|
|
func (P *Parser) parseParameterDecl(ellipsis_ok bool) (*vector.Vector, AST.Expr) {
|
|
if P.trace {
|
|
defer un(trace(P, "ParameterDecl"));
|
|
}
|
|
|
|
// a list of identifiers looks like a list of type names
|
|
list := vector.New(0);
|
|
for {
|
|
// TODO do not allow ()'s here
|
|
list.Push(P.parseParameterType());
|
|
if P.tok == Scanner.COMMA {
|
|
P.next();
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
|
|
// if we had a list of identifiers, it must be followed by a type
|
|
typ := P.tryParameterType();
|
|
|
|
return list, typ;
|
|
}
|
|
|
|
|
|
func (P *Parser) parseParameterList(ellipsis_ok bool) []*AST.Field {
|
|
if P.trace {
|
|
defer un(trace(P, "ParameterList"));
|
|
}
|
|
|
|
list, typ := P.parseParameterDecl(false);
|
|
if typ != nil {
|
|
// IdentifierList Type
|
|
// convert list of identifiers into []*Ident
|
|
idents := make([]*AST.Ident, list.Len());
|
|
for i := 0; i < list.Len(); i++ {
|
|
idents[i] = list.At(i).(*AST.Ident);
|
|
}
|
|
list.Init(0);
|
|
list.Push(&AST.Field(idents, typ, nil));
|
|
|
|
for P.tok == Scanner.COMMA {
|
|
P.next();
|
|
idents := P.parseIdentList2(nil);
|
|
typ := P.parseParameterType();
|
|
list.Push(&AST.Field(idents, typ, nil));
|
|
}
|
|
|
|
} else {
|
|
// Type { "," Type }
|
|
// convert list of types into list of *Param
|
|
for i := 0; i < list.Len(); i++ {
|
|
list.Set(i, &AST.Field(nil, list.At(i).(AST.Expr), nil));
|
|
}
|
|
}
|
|
|
|
// convert list
|
|
params := make([]*AST.Field, list.Len());
|
|
for i := 0; i < list.Len(); i++ {
|
|
params[i] = list.At(i).(*AST.Field);
|
|
}
|
|
|
|
return params;
|
|
}
|
|
|
|
|
|
// TODO make sure Go spec is updated
|
|
func (P *Parser) parseParameters(ellipsis_ok bool) []*AST.Field {
|
|
if P.trace {
|
|
defer un(trace(P, "Parameters"));
|
|
}
|
|
|
|
var params []*AST.Field;
|
|
P.expect(Scanner.LPAREN);
|
|
if P.tok != Scanner.RPAREN {
|
|
params = P.parseParameterList(ellipsis_ok);
|
|
}
|
|
P.expect(Scanner.RPAREN);
|
|
|
|
return params;
|
|
}
|
|
|
|
|
|
func (P *Parser) parseResult() []*AST.Field {
|
|
if P.trace {
|
|
defer un(trace(P, "Result"));
|
|
}
|
|
|
|
var result []*AST.Field;
|
|
if P.tok == Scanner.LPAREN {
|
|
result = P.parseParameters(false);
|
|
} else if P.tok != Scanner.FUNC {
|
|
typ := P.tryType();
|
|
if typ != nil {
|
|
result = make([]*AST.Field, 1);
|
|
result[0] = &AST.Field(nil, typ, nil);
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
// Function types
|
|
//
|
|
// (params)
|
|
// (params) type
|
|
// (params) (results)
|
|
|
|
func (P *Parser) parseSignature() *AST.Signature {
|
|
if P.trace {
|
|
defer un(trace(P, "Signature"));
|
|
}
|
|
|
|
//P.openScope();
|
|
//P.scope_lev++;
|
|
|
|
//t.Scope = P.top_scope;
|
|
params := P.parseParameters(true); // TODO find better solution
|
|
//t.End = P.pos;
|
|
result := P.parseResult();
|
|
|
|
//P.scope_lev--;
|
|
//P.closeScope();
|
|
|
|
return &AST.Signature(params, result);
|
|
}
|
|
|
|
|
|
func (P *Parser) parseFunctionType() *AST.FunctionType {
|
|
if P.trace {
|
|
defer un(trace(P, "FunctionType"));
|
|
}
|
|
|
|
pos := P.pos;
|
|
P.expect(Scanner.FUNC);
|
|
sig := P.parseSignature();
|
|
|
|
return &AST.FunctionType(pos, sig);
|
|
}
|
|
|
|
|
|
func (P *Parser) parseMethodSpec() *AST.Field {
|
|
if P.trace {
|
|
defer un(trace(P, "MethodSpec"));
|
|
}
|
|
|
|
var idents []*AST.Ident;
|
|
var typ AST.Expr;
|
|
x := P.parseQualifiedIdent();
|
|
if tmp, is_ident := x.(*AST.Ident); is_ident && (P.tok == Scanner.COMMA || P.tok == Scanner.LPAREN) {
|
|
// method(s)
|
|
idents = P.parseIdentList2(x);
|
|
typ = &AST.FunctionType(0, P.parseSignature());
|
|
} else {
|
|
// embedded interface
|
|
typ = x;
|
|
}
|
|
|
|
return &AST.Field(idents, typ, nil);
|
|
}
|
|
|
|
|
|
func (P *Parser) parseInterfaceType() *AST.InterfaceType {
|
|
if P.trace {
|
|
defer un(trace(P, "InterfaceType"));
|
|
}
|
|
|
|
pos := P.pos;
|
|
end := 0;
|
|
var methods []*AST.Field;
|
|
|
|
P.expect(Scanner.INTERFACE);
|
|
if P.tok == Scanner.LBRACE {
|
|
P.next();
|
|
//P.openScope();
|
|
//P.scope_lev++;
|
|
|
|
list := vector.New(0);
|
|
for P.tok == Scanner.IDENT {
|
|
list.Push(P.parseMethodSpec());
|
|
if P.tok != Scanner.RBRACE {
|
|
P.expect(Scanner.SEMICOLON);
|
|
}
|
|
}
|
|
//t.End = P.pos;
|
|
|
|
//P.scope_lev--;
|
|
//P.closeScope();
|
|
end = P.pos;
|
|
P.expect(Scanner.RBRACE);
|
|
P.opt_semi = true;
|
|
|
|
// convert vector
|
|
methods = make([]*AST.Field, list.Len());
|
|
for i := list.Len() - 1; i >= 0; i-- {
|
|
methods[i] = list.At(i).(*AST.Field);
|
|
}
|
|
}
|
|
|
|
return &AST.InterfaceType(pos, methods, end);
|
|
}
|
|
|
|
|
|
func (P *Parser) parseMapType() *AST.MapType {
|
|
if P.trace {
|
|
defer un(trace(P, "MapType"));
|
|
}
|
|
|
|
pos := P.pos;
|
|
P.expect(Scanner.MAP);
|
|
P.expect(Scanner.LBRACK);
|
|
key := P.parseVarType();
|
|
P.expect(Scanner.RBRACK);
|
|
val := P.parseVarType();
|
|
|
|
return &AST.MapType(pos, key, val);
|
|
}
|
|
|
|
|
|
func (P *Parser) parseOperand() AST.Expr
|
|
|
|
|
|
func (P *Parser) parseFieldDecl() *AST.Field {
|
|
if P.trace {
|
|
defer un(trace(P, "FieldDecl"));
|
|
}
|
|
|
|
// a list of identifiers looks like a list of type names
|
|
list := vector.New(0);
|
|
for {
|
|
// TODO do not allow ()'s here
|
|
list.Push(P.parseType());
|
|
if P.tok == Scanner.COMMA {
|
|
P.next();
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
|
|
// if we had a list of identifiers, it must be followed by a type
|
|
typ := P.tryType();
|
|
|
|
// optional tag
|
|
var tag AST.Expr;
|
|
if P.tok == Scanner.STRING {
|
|
// ParseOperand takes care of string concatenation
|
|
tag = P.parseOperand();
|
|
}
|
|
|
|
// analyze case
|
|
var idents []*AST.Ident;
|
|
if typ != nil {
|
|
// non-empty identifier list followed by a type
|
|
idents = make([]*AST.Ident, list.Len());
|
|
for i := 0; i < list.Len(); i++ {
|
|
if ident, is_ident := list.At(i).(*AST.Ident); is_ident {
|
|
idents[i] = ident;
|
|
} else {
|
|
P.error(list.At(i).(AST.Expr).Pos(), "identifier expected");
|
|
}
|
|
}
|
|
} else {
|
|
// anonymous field
|
|
if list.Len() == 1 {
|
|
// TODO should do more checks here
|
|
typ = list.At(0).(AST.Expr);
|
|
} else {
|
|
P.error(P.pos, "anonymous field expected");
|
|
}
|
|
}
|
|
|
|
return &AST.Field(idents, typ, tag);
|
|
}
|
|
|
|
|
|
func (P *Parser) parseStructType() AST.Expr {
|
|
if P.trace {
|
|
defer un(trace(P, "StructType"));
|
|
}
|
|
|
|
pos := P.pos;
|
|
end := 0;
|
|
var fields []*AST.Field;
|
|
|
|
P.expect(Scanner.STRUCT);
|
|
if P.tok == Scanner.LBRACE {
|
|
P.next();
|
|
|
|
list := vector.New(0);
|
|
for P.tok != Scanner.RBRACE && P.tok != Scanner.EOF {
|
|
list.Push(P.parseFieldDecl());
|
|
if P.tok == Scanner.SEMICOLON {
|
|
P.next();
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
P.OptSemicolon();
|
|
|
|
end = P.pos;
|
|
P.expect(Scanner.RBRACE);
|
|
P.opt_semi = true;
|
|
|
|
// convert vector
|
|
fields = make([]*AST.Field, list.Len());
|
|
for i := list.Len() - 1; i >= 0; i-- {
|
|
fields[i] = list.At(i).(*AST.Field);
|
|
}
|
|
}
|
|
|
|
return AST.StructType(pos, fields, end);
|
|
}
|
|
|
|
|
|
func (P *Parser) parsePointerType() AST.Expr {
|
|
if P.trace {
|
|
defer un(trace(P, "PointerType"));
|
|
}
|
|
|
|
pos := P.pos;
|
|
P.expect(Scanner.MUL);
|
|
base := P.parseType();
|
|
|
|
return &AST.PointerType(pos, base);
|
|
}
|
|
|
|
|
|
func (P *Parser) tryType() AST.Expr {
|
|
if P.trace {
|
|
defer un(trace(P, "Type (try)"));
|
|
}
|
|
|
|
switch P.tok {
|
|
case Scanner.IDENT: return P.parseTypeName();
|
|
case Scanner.LBRACK: return P.parseArrayType();
|
|
case Scanner.CHAN, Scanner.ARROW: return P.parseChannelType();
|
|
case Scanner.INTERFACE: return P.parseInterfaceType();
|
|
case Scanner.FUNC: return P.parseFunctionType();
|
|
case Scanner.MAP: return P.parseMapType();
|
|
case Scanner.STRUCT: return P.parseStructType();
|
|
case Scanner.MUL: return P.parsePointerType();
|
|
case Scanner.LPAREN:
|
|
pos := P.pos;
|
|
P.next();
|
|
t := P.parseType();
|
|
P.expect(Scanner.RPAREN);
|
|
return &AST.Group(pos, t);
|
|
}
|
|
|
|
// no type found
|
|
return nil;
|
|
}
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// Blocks
|
|
|
|
|
|
func (P *Parser) parseStatementList(list *vector.Vector) {
|
|
if P.trace {
|
|
defer un(trace(P, "StatementList"));
|
|
}
|
|
|
|
expect_semi := false;
|
|
for P.tok != Scanner.CASE && P.tok != Scanner.DEFAULT && P.tok != Scanner.RBRACE && P.tok != Scanner.EOF {
|
|
if expect_semi {
|
|
P.expect(Scanner.SEMICOLON);
|
|
expect_semi = false;
|
|
}
|
|
list.Push(P.parseStatement());
|
|
if P.tok == Scanner.SEMICOLON {
|
|
P.next();
|
|
} else if P.opt_semi {
|
|
P.opt_semi = false; // "consume" optional semicolon
|
|
} else {
|
|
expect_semi = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
func (P *Parser) parseBlock(tok int) *AST.Block {
|
|
if P.trace {
|
|
defer un(trace(P, "Block"));
|
|
}
|
|
|
|
b := AST.NewBlock(P.pos, tok);
|
|
P.expect(tok);
|
|
|
|
/*
|
|
P.openScope();
|
|
// enter recv and parameters into function scope
|
|
if ftyp != nil {
|
|
assert(ftyp.Form == AST.FUNCTION);
|
|
if ftyp.Key != nil {
|
|
}
|
|
if ftyp.List != nil {
|
|
for i, n := 0, ftyp.List.Len(); i < n; i++ {
|
|
if x, ok := ftyp.List.At(i).(*AST.Ident); ok {
|
|
P.declareInScope(P.top_scope, x, SymbolTable.VAR, nil);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
*/
|
|
|
|
P.parseStatementList(b.List);
|
|
|
|
/*
|
|
P.closeScope();
|
|
*/
|
|
|
|
if tok == Scanner.LBRACE {
|
|
b.End = P.pos;
|
|
P.expect(Scanner.RBRACE);
|
|
P.opt_semi = true;
|
|
}
|
|
|
|
return b;
|
|
}
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// Expressions
|
|
|
|
func (P *Parser) parseExpressionList() AST.Expr {
|
|
if P.trace {
|
|
defer un(trace(P, "ExpressionList"));
|
|
}
|
|
|
|
x := P.parseExpression(1);
|
|
for first := true; P.tok == Scanner.COMMA; {
|
|
pos := P.pos;
|
|
P.next();
|
|
y := P.parseExpression(1);
|
|
if first {
|
|
x = &AST.BinaryExpr(pos, Scanner.COMMA, x, y);
|
|
first = false;
|
|
} else {
|
|
x.(*AST.BinaryExpr).Y = &AST.BinaryExpr(pos, Scanner.COMMA, x.(*AST.BinaryExpr).Y, y);
|
|
}
|
|
}
|
|
|
|
return x;
|
|
}
|
|
|
|
|
|
func (P *Parser) parseFunctionLit() AST.Expr {
|
|
if P.trace {
|
|
defer un(trace(P, "FunctionLit"));
|
|
}
|
|
|
|
pos := P.pos;
|
|
P.expect(Scanner.FUNC);
|
|
typ := P.parseSignature();
|
|
P.scope_lev++;
|
|
body := P.parseBlock(Scanner.LBRACE);
|
|
P.scope_lev--;
|
|
|
|
return &AST.FunctionLit(pos, typ, body);
|
|
}
|
|
|
|
|
|
func (P *Parser) parseOperand() AST.Expr {
|
|
if P.trace {
|
|
defer un(trace(P, "Operand"));
|
|
}
|
|
|
|
switch P.tok {
|
|
case Scanner.IDENT:
|
|
return P.parseIdent(P.top_scope);
|
|
|
|
case Scanner.LPAREN:
|
|
pos := P.pos;
|
|
P.next();
|
|
x := P.parseExpression(1);
|
|
P.expect(Scanner.RPAREN);
|
|
return &AST.Group(pos, x);
|
|
|
|
case Scanner.INT, Scanner.FLOAT, Scanner.STRING:
|
|
x := &AST.BasicLit(P.pos, P.tok, P.val);
|
|
P.next();
|
|
if x.Tok == Scanner.STRING {
|
|
// TODO should remember the list instead of
|
|
// concatenate the strings here
|
|
for ; P.tok == Scanner.STRING; P.next() {
|
|
x.Val += P.val;
|
|
}
|
|
}
|
|
return x;
|
|
|
|
case Scanner.FUNC:
|
|
return P.parseFunctionLit();
|
|
|
|
default:
|
|
t := P.tryType();
|
|
if t != nil {
|
|
return t;
|
|
} else {
|
|
P.error(P.pos, "operand expected");
|
|
P.next(); // make progress
|
|
}
|
|
}
|
|
|
|
return &AST.BadExpr(P.pos);
|
|
}
|
|
|
|
|
|
func (P *Parser) parseSelectorOrTypeGuard(x AST.Expr) AST.Expr {
|
|
if P.trace {
|
|
defer un(trace(P, "SelectorOrTypeGuard"));
|
|
}
|
|
|
|
pos := P.pos;
|
|
P.expect(Scanner.PERIOD);
|
|
|
|
if P.tok == Scanner.IDENT {
|
|
x = &AST.Selector(pos, x, P.parseIdent(nil));
|
|
|
|
} else {
|
|
P.expect(Scanner.LPAREN);
|
|
x = &AST.TypeGuard(pos, x, P.parseType());
|
|
P.expect(Scanner.RPAREN);
|
|
}
|
|
|
|
return x;
|
|
}
|
|
|
|
|
|
func (P *Parser) parseIndex(x AST.Expr) AST.Expr {
|
|
if P.trace {
|
|
defer un(trace(P, "IndexOrSlice"));
|
|
}
|
|
|
|
pos := P.pos;
|
|
P.expect(Scanner.LBRACK);
|
|
i := P.parseExpression(0);
|
|
P.expect(Scanner.RBRACK);
|
|
|
|
return &AST.Index(pos, x, i);
|
|
}
|
|
|
|
|
|
func (P *Parser) parseBinaryExpr(prec1 int) AST.Expr
|
|
|
|
func (P *Parser) parseCompositeElements() AST.Expr {
|
|
x := P.parseExpression(0);
|
|
if P.tok == Scanner.COMMA {
|
|
pos := P.pos;
|
|
P.next();
|
|
|
|
// first element determines mode
|
|
singles := true;
|
|
if t, is_binary := x.(*AST.BinaryExpr); is_binary && t.Tok == Scanner.COLON {
|
|
singles = false;
|
|
}
|
|
|
|
var last *AST.BinaryExpr;
|
|
for P.tok != Scanner.RPAREN && P.tok != Scanner.EOF {
|
|
y := P.parseExpression(0);
|
|
|
|
if singles {
|
|
if t, is_binary := y.(*AST.BinaryExpr); is_binary && t.Tok == Scanner.COLON {
|
|
P.error(t.X.Pos(), "single value expected; found pair");
|
|
}
|
|
} else {
|
|
if t, is_binary := y.(*AST.BinaryExpr); !is_binary || t.Tok != Scanner.COLON {
|
|
P.error(y.Pos(), "key:value pair expected; found single value");
|
|
}
|
|
}
|
|
|
|
if last == nil {
|
|
last = &AST.BinaryExpr(pos, Scanner.COMMA, x, y);
|
|
x = last;
|
|
} else {
|
|
last.Y = &AST.BinaryExpr(pos, Scanner.COMMA, last.Y, y);
|
|
last = last.Y.(*AST.BinaryExpr);
|
|
}
|
|
|
|
if P.tok == Scanner.COMMA {
|
|
pos = P.pos;
|
|
P.next();
|
|
} else {
|
|
break;
|
|
}
|
|
|
|
}
|
|
}
|
|
return x;
|
|
}
|
|
|
|
|
|
func (P *Parser) parseCallOrCompositeLit(f AST.Expr) AST.Expr {
|
|
if P.trace {
|
|
defer un(trace(P, "CallOrCompositeLit"));
|
|
}
|
|
|
|
pos := P.pos;
|
|
P.expect(Scanner.LPAREN);
|
|
var args AST.Expr;
|
|
if P.tok != Scanner.RPAREN {
|
|
args = P.parseCompositeElements();
|
|
}
|
|
P.expect(Scanner.RPAREN);
|
|
|
|
return &AST.Call(pos, f, args);
|
|
}
|
|
|
|
|
|
func (P *Parser) parsePrimaryExpr() AST.Expr {
|
|
if P.trace {
|
|
defer un(trace(P, "PrimaryExpr"));
|
|
}
|
|
|
|
x := P.parseOperand();
|
|
for {
|
|
switch P.tok {
|
|
case Scanner.PERIOD: x = P.parseSelectorOrTypeGuard(x);
|
|
case Scanner.LBRACK: x = P.parseIndex(x);
|
|
case Scanner.LPAREN: x = P.parseCallOrCompositeLit(x);
|
|
default:
|
|
return x;
|
|
}
|
|
}
|
|
|
|
unreachable();
|
|
return nil;
|
|
}
|
|
|
|
|
|
func (P *Parser) parseUnaryExpr() AST.Expr {
|
|
if P.trace {
|
|
defer un(trace(P, "UnaryExpr"));
|
|
}
|
|
|
|
switch P.tok {
|
|
case Scanner.ADD, Scanner.SUB, Scanner.MUL, Scanner.NOT, Scanner.XOR, Scanner.ARROW, Scanner.AND:
|
|
pos, tok := P.pos, P.tok;
|
|
P.next();
|
|
y := P.parseUnaryExpr();
|
|
return &AST.UnaryExpr(pos, tok, y);
|
|
/*
|
|
if lit, ok := y.(*AST.TypeLit); ok && tok == Scanner.MUL {
|
|
// pointer type
|
|
t := AST.NewType(pos, AST.POINTER);
|
|
t.Elt = lit.Typ;
|
|
return &AST.TypeLit(t);
|
|
} else {
|
|
return &AST.UnaryExpr(pos, tok, y);
|
|
}
|
|
*/
|
|
}
|
|
|
|
return P.parsePrimaryExpr();
|
|
}
|
|
|
|
|
|
func (P *Parser) parseBinaryExpr(prec1 int) AST.Expr {
|
|
if P.trace {
|
|
defer un(trace(P, "BinaryExpr"));
|
|
}
|
|
|
|
x := P.parseUnaryExpr();
|
|
for prec := Scanner.Precedence(P.tok); prec >= prec1; prec-- {
|
|
for Scanner.Precedence(P.tok) == prec {
|
|
pos, tok := P.pos, P.tok;
|
|
P.next();
|
|
y := P.parseBinaryExpr(prec + 1);
|
|
x = &AST.BinaryExpr(pos, tok, x, y);
|
|
}
|
|
}
|
|
|
|
return x;
|
|
}
|
|
|
|
|
|
func (P *Parser) parseExpression(prec int) AST.Expr {
|
|
if P.trace {
|
|
defer un(trace(P, "Expression"));
|
|
}
|
|
|
|
if prec < 0 {
|
|
panic("precedence must be >= 0");
|
|
}
|
|
|
|
return P.parseBinaryExpr(prec);
|
|
}
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// Statements
|
|
|
|
func (P *Parser) parseSimpleStat(range_ok bool) AST.Stat {
|
|
if P.trace {
|
|
defer un(trace(P, "SimpleStat"));
|
|
}
|
|
|
|
x := P.parseExpressionList();
|
|
|
|
switch P.tok {
|
|
case Scanner.COLON:
|
|
// label declaration
|
|
pos := P.pos;
|
|
P.next(); // consume ":"
|
|
P.opt_semi = true;
|
|
if AST.ExprLen(x) == 1 {
|
|
if label, is_ident := x.(*AST.Ident); is_ident {
|
|
return &AST.LabelDecl(pos, label);
|
|
}
|
|
}
|
|
P.error(x.Pos(), "illegal label declaration");
|
|
return nil;
|
|
|
|
case
|
|
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:
|
|
// declaration/assignment
|
|
pos, tok := P.pos, P.tok;
|
|
P.next();
|
|
var y AST.Expr;
|
|
if range_ok && P.tok == Scanner.RANGE {
|
|
range_pos := P.pos;
|
|
P.next();
|
|
y = &AST.UnaryExpr(range_pos, Scanner.RANGE, P.parseExpression(1));
|
|
if tok != Scanner.DEFINE && tok != Scanner.ASSIGN {
|
|
P.error(pos, "expected '=' or ':=', found '" + Scanner.TokenString(tok) + "'");
|
|
}
|
|
} else {
|
|
y = P.parseExpressionList();
|
|
if xl, yl := AST.ExprLen(x), AST.ExprLen(y); xl > 1 && yl > 1 && xl != yl {
|
|
P.error(x.Pos(), "arity of lhs doesn't match rhs");
|
|
}
|
|
}
|
|
// TODO changed ILLEGAL -> NONE
|
|
return &AST.ExpressionStat(x.Pos(), Scanner.ILLEGAL, &AST.BinaryExpr(pos, tok, x, y));
|
|
|
|
default:
|
|
if AST.ExprLen(x) != 1 {
|
|
P.error(x.Pos(), "only one expression allowed");
|
|
}
|
|
|
|
if P.tok == Scanner.INC || P.tok == Scanner.DEC {
|
|
s := &AST.ExpressionStat(P.pos, P.tok, x);
|
|
P.next(); // consume "++" or "--"
|
|
return s;
|
|
}
|
|
|
|
// TODO changed ILLEGAL -> NONE
|
|
return &AST.ExpressionStat(x.Pos(), Scanner.ILLEGAL, x);
|
|
}
|
|
|
|
unreachable();
|
|
return nil;
|
|
}
|
|
|
|
|
|
func (P *Parser) parseInvocationStat(keyword int) *AST.ExpressionStat {
|
|
if P.trace {
|
|
defer un(trace(P, "InvocationStat"));
|
|
}
|
|
|
|
pos := P.pos;
|
|
P.expect(keyword);
|
|
return &AST.ExpressionStat(pos, keyword, P.parseExpression(1));
|
|
}
|
|
|
|
|
|
func (P *Parser) parseReturnStat() *AST.ExpressionStat {
|
|
if P.trace {
|
|
defer un(trace(P, "ReturnStat"));
|
|
}
|
|
|
|
pos := P.pos;
|
|
P.expect(Scanner.RETURN);
|
|
var x AST.Expr;
|
|
if P.tok != Scanner.SEMICOLON && P.tok != Scanner.RBRACE {
|
|
x = P.parseExpressionList();
|
|
}
|
|
|
|
return &AST.ExpressionStat(pos, Scanner.RETURN, x);
|
|
}
|
|
|
|
|
|
func (P *Parser) parseControlFlowStat(tok int) *AST.ControlFlowStat {
|
|
if P.trace {
|
|
defer un(trace(P, "ControlFlowStat"));
|
|
}
|
|
|
|
s := &AST.ControlFlowStat(P.pos, tok, nil);
|
|
P.expect(tok);
|
|
if tok != Scanner.FALLTHROUGH && P.tok == Scanner.IDENT {
|
|
s.Label = P.parseIdent(P.top_scope);
|
|
}
|
|
|
|
return s;
|
|
}
|
|
|
|
|
|
func (P *Parser) parseControlClause(isForStat bool) (init AST.Stat, expr AST.Expr, post AST.Stat) {
|
|
if P.trace {
|
|
defer un(trace(P, "ControlClause"));
|
|
}
|
|
|
|
if P.tok != Scanner.LBRACE {
|
|
if P.tok != Scanner.SEMICOLON {
|
|
init = P.parseSimpleStat(isForStat);
|
|
// TODO check for range clause and exit if found
|
|
}
|
|
if P.tok == Scanner.SEMICOLON {
|
|
P.next();
|
|
if P.tok != Scanner.SEMICOLON && P.tok != Scanner.LBRACE {
|
|
expr = P.parseExpression(1);
|
|
}
|
|
if isForStat {
|
|
P.expect(Scanner.SEMICOLON);
|
|
if P.tok != Scanner.LBRACE {
|
|
post = P.parseSimpleStat(false);
|
|
}
|
|
}
|
|
} else {
|
|
if init != nil { // guard in case of errors
|
|
if s, is_expr_stat := init.(*AST.ExpressionStat); is_expr_stat {
|
|
expr, init = s.Expr, nil;
|
|
} else {
|
|
P.error(0, "illegal control clause");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return init, expr, post;
|
|
}
|
|
|
|
|
|
func (P *Parser) parseIfStat() *AST.IfStat {
|
|
if P.trace {
|
|
defer un(trace(P, "IfStat"));
|
|
}
|
|
|
|
P.openScope();
|
|
pos := P.pos;
|
|
P.expect(Scanner.IF);
|
|
init, cond, dummy := P.parseControlClause(false);
|
|
body := P.parseBlock(Scanner.LBRACE);
|
|
var else_ AST.Stat;
|
|
if P.tok == Scanner.ELSE {
|
|
P.next();
|
|
if ok := P.tok == Scanner.IF || P.tok == Scanner.LBRACE; ok || P.sixg {
|
|
else_ = P.parseStatement();
|
|
if !ok {
|
|
// wrap in a block since we don't have one
|
|
body := AST.NewBlock(0, Scanner.LBRACE);
|
|
body.List.Push(else_);
|
|
else_ = &AST.CompositeStat(body);
|
|
}
|
|
} else {
|
|
P.error(P.pos, "'if' or '{' expected - illegal 'else' branch");
|
|
}
|
|
}
|
|
P.closeScope();
|
|
|
|
return &AST.IfStat(pos, init, cond, body, else_);
|
|
}
|
|
|
|
|
|
func (P *Parser) parseForStat() *AST.ForStat {
|
|
if P.trace {
|
|
defer un(trace(P, "ForStat"));
|
|
}
|
|
|
|
P.openScope();
|
|
pos := P.pos;
|
|
P.expect(Scanner.FOR);
|
|
init, cond, post := P.parseControlClause(true);
|
|
body := P.parseBlock(Scanner.LBRACE);
|
|
P.closeScope();
|
|
|
|
return &AST.ForStat(pos, init, cond, post, body);
|
|
}
|
|
|
|
|
|
func (P *Parser) parseCaseClause() *AST.CaseClause {
|
|
if P.trace {
|
|
defer un(trace(P, "CaseClause"));
|
|
}
|
|
|
|
// SwitchCase
|
|
pos := P.pos;
|
|
var expr AST.Expr;
|
|
if P.tok == Scanner.CASE {
|
|
P.next();
|
|
expr = P.parseExpressionList();
|
|
} else {
|
|
P.expect(Scanner.DEFAULT);
|
|
}
|
|
|
|
return &AST.CaseClause(pos, expr, P.parseBlock(Scanner.COLON));
|
|
}
|
|
|
|
|
|
func (P *Parser) parseSwitchStat() *AST.SwitchStat {
|
|
if P.trace {
|
|
defer un(trace(P, "SwitchStat"));
|
|
}
|
|
|
|
P.openScope();
|
|
pos := P.pos;
|
|
P.expect(Scanner.SWITCH);
|
|
init, tag, post := P.parseControlClause(false);
|
|
body := AST.NewBlock(P.pos, Scanner.LBRACE);
|
|
P.expect(Scanner.LBRACE);
|
|
for P.tok != Scanner.RBRACE && P.tok != Scanner.EOF {
|
|
body.List.Push(P.parseCaseClause());
|
|
}
|
|
body.End = P.pos;
|
|
P.expect(Scanner.RBRACE);
|
|
P.opt_semi = true;
|
|
P.closeScope();
|
|
|
|
return &AST.SwitchStat(pos, init, tag, body);
|
|
}
|
|
|
|
|
|
func (P *Parser) parseCommClause() *AST.CaseClause {
|
|
if P.trace {
|
|
defer un(trace(P, "CommClause"));
|
|
}
|
|
|
|
// CommCase
|
|
pos := P.pos;
|
|
var expr AST.Expr;
|
|
if P.tok == Scanner.CASE {
|
|
P.next();
|
|
x := P.parseExpression(1);
|
|
if P.tok == Scanner.ASSIGN || P.tok == Scanner.DEFINE {
|
|
pos, tok := P.pos, P.tok;
|
|
P.next();
|
|
if P.tok == Scanner.ARROW {
|
|
y := P.parseExpression(1);
|
|
x = &AST.BinaryExpr(pos, tok, x, y);
|
|
} else {
|
|
P.expect(Scanner.ARROW); // use expect() error handling
|
|
}
|
|
}
|
|
expr = x;
|
|
} else {
|
|
P.expect(Scanner.DEFAULT);
|
|
}
|
|
|
|
return &AST.CaseClause(pos, expr, P.parseBlock(Scanner.COLON));
|
|
}
|
|
|
|
|
|
func (P *Parser) parseSelectStat() *AST.SelectStat {
|
|
if P.trace {
|
|
defer un(trace(P, "SelectStat"));
|
|
}
|
|
|
|
P.openScope();
|
|
pos := P.pos;
|
|
P.expect(Scanner.SELECT);
|
|
body := AST.NewBlock(P.pos, Scanner.LBRACE);
|
|
P.expect(Scanner.LBRACE);
|
|
for P.tok != Scanner.RBRACE && P.tok != Scanner.EOF {
|
|
body.List.Push(P.parseCommClause());
|
|
}
|
|
body.End = P.pos;
|
|
P.expect(Scanner.RBRACE);
|
|
P.opt_semi = true;
|
|
P.closeScope();
|
|
|
|
return &AST.SelectStat(pos, body);
|
|
}
|
|
|
|
|
|
func (P *Parser) parseStatement() AST.Stat {
|
|
if P.trace {
|
|
defer un(trace(P, "Statement"));
|
|
}
|
|
|
|
switch P.tok {
|
|
case Scanner.CONST, Scanner.TYPE, Scanner.VAR:
|
|
return &AST.DeclarationStat(P.parseDeclaration());
|
|
case Scanner.FUNC:
|
|
// for now we do not allow local function declarations,
|
|
// instead we assume this starts a function literal
|
|
fallthrough;
|
|
case
|
|
// only the tokens that are legal top-level expression starts
|
|
Scanner.IDENT, Scanner.INT, Scanner.FLOAT, Scanner.STRING, Scanner.LPAREN, // operand
|
|
Scanner.LBRACK, Scanner.STRUCT, // composite type
|
|
Scanner.MUL, Scanner.AND, Scanner.ARROW: // unary
|
|
return P.parseSimpleStat(false);
|
|
case Scanner.GO, Scanner.DEFER:
|
|
return P.parseInvocationStat(P.tok);
|
|
case Scanner.RETURN:
|
|
return P.parseReturnStat();
|
|
case Scanner.BREAK, Scanner.CONTINUE, Scanner.GOTO, Scanner.FALLTHROUGH:
|
|
return P.parseControlFlowStat(P.tok);
|
|
case Scanner.LBRACE:
|
|
return &AST.CompositeStat(P.parseBlock(Scanner.LBRACE));
|
|
case Scanner.IF:
|
|
return P.parseIfStat();
|
|
case Scanner.FOR:
|
|
return P.parseForStat();
|
|
case Scanner.SWITCH:
|
|
return P.parseSwitchStat();
|
|
case Scanner.SELECT:
|
|
return P.parseSelectStat();
|
|
case Scanner.SEMICOLON:
|
|
// don't consume the ";", it is the separator following the empty statement
|
|
return &AST.EmptyStat(P.pos);
|
|
}
|
|
|
|
// no statement found
|
|
P.error(P.pos, "statement expected");
|
|
return &AST.BadStat(P.pos);
|
|
}
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// Declarations
|
|
|
|
func (P *Parser) parseImportSpec(pos int) *AST.ImportDecl {
|
|
if P.trace {
|
|
defer un(trace(P, "ImportSpec"));
|
|
}
|
|
|
|
var ident *AST.Ident;
|
|
if P.tok == Scanner.PERIOD {
|
|
P.error(P.pos, `"import ." not yet handled properly`);
|
|
P.next();
|
|
} else if P.tok == Scanner.IDENT {
|
|
ident = P.parseIdent(nil);
|
|
}
|
|
|
|
var path AST.Expr;
|
|
if P.tok == Scanner.STRING {
|
|
// TODO eventually the scanner should strip the quotes
|
|
path = &AST.BasicLit(P.pos, Scanner.STRING, P.val);
|
|
P.next();
|
|
} else {
|
|
P.expect(Scanner.STRING); // use expect() error handling
|
|
}
|
|
|
|
return &AST.ImportDecl(pos, ident, path);
|
|
}
|
|
|
|
|
|
func (P *Parser) parseConstSpec(pos int) *AST.ConstDecl {
|
|
if P.trace {
|
|
defer un(trace(P, "ConstSpec"));
|
|
}
|
|
|
|
idents := P.parseIdentList2(nil);
|
|
typ := P.tryType();
|
|
var vals AST.Expr;
|
|
if P.tok == Scanner.ASSIGN {
|
|
P.next();
|
|
vals = P.parseExpressionList();
|
|
}
|
|
|
|
return &AST.ConstDecl(pos, idents, typ, vals);
|
|
}
|
|
|
|
|
|
func (P *Parser) parseTypeSpec(pos int) *AST.TypeDecl {
|
|
if P.trace {
|
|
defer un(trace(P, "TypeSpec"));
|
|
}
|
|
|
|
ident := P.parseIdent(nil);
|
|
typ := P.parseType();
|
|
|
|
return &AST.TypeDecl(pos, ident, typ);
|
|
}
|
|
|
|
|
|
func (P *Parser) parseVarSpec(pos int) *AST.VarDecl {
|
|
if P.trace {
|
|
defer un(trace(P, "VarSpec"));
|
|
}
|
|
|
|
idents := P.parseIdentList2(nil);
|
|
var typ AST.Expr;
|
|
var vals AST.Expr;
|
|
if P.tok == Scanner.ASSIGN {
|
|
P.next();
|
|
vals = P.parseExpressionList();
|
|
} else {
|
|
typ = P.parseVarType();
|
|
if P.tok == Scanner.ASSIGN {
|
|
P.next();
|
|
vals = P.parseExpressionList();
|
|
}
|
|
}
|
|
|
|
return &AST.VarDecl(pos, idents, typ, vals);
|
|
}
|
|
|
|
|
|
func (P *Parser) parseSpec(pos, keyword int) AST.Decl {
|
|
kind := SymbolTable.NONE;
|
|
|
|
switch keyword {
|
|
case Scanner.IMPORT: return P.parseImportSpec(pos);
|
|
case Scanner.CONST: return P.parseConstSpec(pos);
|
|
case Scanner.TYPE: return P.parseTypeSpec(pos);
|
|
case Scanner.VAR: return P.parseVarSpec(pos);
|
|
}
|
|
|
|
unreachable();
|
|
return nil;
|
|
|
|
/*
|
|
// semantic checks
|
|
if d.Tok == Scanner.IMPORT {
|
|
if d.Ident != nil {
|
|
//P.declare(d.Ident, kind, nil);
|
|
}
|
|
} else {
|
|
//P.declare(d.Ident, kind, d.Typ);
|
|
if d.Val != nil {
|
|
// initialization/assignment
|
|
llen := AST.ExprLen(d.Ident);
|
|
rlen := AST.ExprLen(d.Val);
|
|
if llen == rlen {
|
|
// TODO
|
|
} else if rlen == 1 {
|
|
// TODO
|
|
} else {
|
|
if llen < rlen {
|
|
P.error(AST.ExprAt(d.Val, llen).Pos(), "more expressions than variables");
|
|
} else {
|
|
P.error(AST.ExprAt(d.Ident, rlen).Pos(), "more variables than expressions");
|
|
}
|
|
}
|
|
} else {
|
|
// TODO
|
|
}
|
|
}
|
|
*/
|
|
}
|
|
|
|
|
|
func (P *Parser) parseDecl(keyword int) AST.Decl {
|
|
if P.trace {
|
|
defer un(trace(P, "Decl"));
|
|
}
|
|
|
|
pos := P.pos;
|
|
P.expect(keyword);
|
|
if P.tok == Scanner.LPAREN {
|
|
P.next();
|
|
list := vector.New(0);
|
|
for P.tok != Scanner.RPAREN && P.tok != Scanner.EOF {
|
|
list.Push(P.parseSpec(0, keyword));
|
|
if P.tok == Scanner.SEMICOLON {
|
|
P.next();
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
end := P.pos;
|
|
P.expect(Scanner.RPAREN);
|
|
P.opt_semi = true;
|
|
|
|
// convert vector
|
|
decls := make([]AST.Decl, list.Len());
|
|
for i := 0; i < list.Len(); i++ {
|
|
decls[i] = list.At(i).(AST.Decl);
|
|
}
|
|
|
|
return &AST.DeclList(pos, keyword, decls, end);
|
|
}
|
|
|
|
return P.parseSpec(pos, keyword);
|
|
}
|
|
|
|
|
|
// Function declarations
|
|
//
|
|
// func ident (params)
|
|
// func ident (params) type
|
|
// func ident (params) (results)
|
|
// func (recv) ident (params)
|
|
// func (recv) ident (params) type
|
|
// func (recv) ident (params) (results)
|
|
|
|
func (P *Parser) parseFunctionDecl() *AST.FuncDecl {
|
|
if P.trace {
|
|
defer un(trace(P, "FunctionDecl"));
|
|
}
|
|
|
|
pos := P.pos;
|
|
P.expect(Scanner.FUNC);
|
|
|
|
var recv *AST.Field;
|
|
if P.tok == Scanner.LPAREN {
|
|
pos := P.pos;
|
|
tmp := P.parseParameters(true);
|
|
if len(tmp) == 1 {
|
|
recv = tmp[0];
|
|
} else {
|
|
P.error(pos, "must have exactly one receiver");
|
|
}
|
|
}
|
|
|
|
ident := P.parseIdent(nil);
|
|
sig := P.parseSignature();
|
|
|
|
var body *AST.Block;
|
|
if P.tok == Scanner.LBRACE {
|
|
body = P.parseBlock(Scanner.LBRACE);
|
|
}
|
|
|
|
return &AST.FuncDecl(pos, recv, ident, sig, body);
|
|
}
|
|
|
|
|
|
func (P *Parser) parseDeclaration() AST.Decl {
|
|
if P.trace {
|
|
defer un(trace(P, "Declaration"));
|
|
}
|
|
|
|
switch P.tok {
|
|
case Scanner.CONST, Scanner.TYPE, Scanner.VAR:
|
|
return P.parseDecl(P.tok);
|
|
case Scanner.FUNC:
|
|
return P.parseFunctionDecl();
|
|
}
|
|
|
|
pos := P.pos;
|
|
P.error(pos, "declaration expected");
|
|
P.next(); // make progress
|
|
return &AST.BadDecl(pos);
|
|
}
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// Program
|
|
|
|
func (P *Parser) ParseProgram() *AST.Program {
|
|
if P.trace {
|
|
defer un(trace(P, "Program"));
|
|
}
|
|
|
|
P.openScope();
|
|
p := AST.NewProgram(P.pos);
|
|
P.expect(Scanner.PACKAGE);
|
|
p.Ident = P.parseIdent(nil);
|
|
|
|
// package body
|
|
{ P.openScope();
|
|
list := vector.New(0);
|
|
for P.tok == Scanner.IMPORT {
|
|
list.Push(P.parseDecl(Scanner.IMPORT));
|
|
P.OptSemicolon();
|
|
}
|
|
if !P.deps {
|
|
for P.tok != Scanner.EOF {
|
|
list.Push(P.parseDeclaration());
|
|
P.OptSemicolon();
|
|
}
|
|
}
|
|
P.closeScope();
|
|
|
|
// convert list
|
|
p.Decls = make([]AST.Decl, list.Len());
|
|
for i := 0; i < list.Len(); i++ {
|
|
p.Decls[i] = list.At(i).(AST.Decl);
|
|
}
|
|
}
|
|
|
|
p.Comments = P.comments;
|
|
P.closeScope();
|
|
|
|
return p;
|
|
}
|