- created new dir (gosrc) for go-based front-end
- adjusted makefiles
SVN=126763
diff --git a/usr/gri/gosrc/parser.go b/usr/gri/gosrc/parser.go
new file mode 100644
index 0000000..0e025f9
--- /dev/null
+++ b/usr/gri/gosrc/parser.go
@@ -0,0 +1,1061 @@
+// 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 Scanner "scanner"
+
+
+export Parser
+type Parser struct {
+ verbose, indent int;
+ S *Scanner.Scanner;
+ tok int; // one token look-ahead
+ beg, end int; // token position
+ ident string; // last ident seen
+}
+
+
+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.beg, P.end = P.S.Scan();
+ if P.tok == Scanner.IDENT {
+ P.ident = P.S.src[P.beg : P.end];
+ }
+ if P.verbose > 1 {
+ P.PrintIndent();
+ print Scanner.TokenName(P.tok), "\n";
+ }
+}
+
+
+func (P *Parser) Open(S *Scanner.Scanner, verbose int) {
+ P.verbose = verbose;
+ P.indent = 0;
+ P.S = S;
+ P.Next();
+}
+
+
+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 {
+ P.Error(P.beg, "expected '" + Scanner.TokenName(tok) + "', found '" + Scanner.TokenName(P.tok) + "'");
+ }
+}
+
+
+func (P *Parser) Optional(tok int) {
+ if P.tok == tok {
+ P.Next();
+ }
+}
+
+
+func (P *Parser) TryType() bool;
+func (P *Parser) ParseExpression();
+
+
+func (P *Parser) ParseIdent() {
+ if P.verbose > 0 {
+ P.PrintIndent();
+ print "Ident = \"", P.ident, "\"\n";
+ }
+ P.Expect(Scanner.IDENT);
+}
+
+
+func (P *Parser) ParseIdentList() {
+ P.Trace("IdentList");
+ P.ParseIdent();
+ for P.tok == Scanner.COMMA {
+ P.Next();
+ P.ParseIdent();
+ }
+ P.Ecart();
+}
+
+
+func (P *Parser) ParseQualifiedIdent() {
+ P.Trace("QualifiedIdent");
+ P.ParseIdent();
+ if P.tok == Scanner.PERIOD {
+ P.Next();
+ P.ParseIdent();
+ }
+ P.Ecart();
+}
+
+
+func (P *Parser) ParseTypeName() {
+ P.Trace("TypeName");
+ P.ParseQualifiedIdent();
+ P.Ecart();
+}
+
+
+func (P *Parser) ParseType() {
+ P.Trace("Type");
+ if !P.TryType() {
+ P.Error(P.beg, "type expected");
+ }
+ P.Ecart();
+}
+
+
+func (P *Parser) ParseArrayType() {
+ P.Trace("ArrayType");
+ P.Expect(Scanner.LBRACK);
+ if P.tok != Scanner.RBRACK {
+ P.ParseExpression();
+ }
+ P.Expect(Scanner.RBRACK);
+ P.ParseType();
+ P.Ecart();
+}
+
+
+func (P *Parser) ParseChannelType() {
+ P.Trace("ChannelType");
+ P.Expect(Scanner.CHAN);
+ switch P.tok {
+ case Scanner.LSS: fallthrough
+ case Scanner.GTR:
+ P.Next();
+ }
+ P.ParseType();
+ P.Ecart();
+}
+
+
+func (P *Parser) ParseParameters();
+func (P *Parser) TryResult() bool;
+
+
+func (P *Parser) ParseMethodDecl() {
+ P.Trace("MethodDecl");
+ P.ParseIdent();
+ P.ParseParameters();
+ P.TryResult();
+ P.Optional(Scanner.SEMICOLON);
+ P.Ecart();
+}
+
+
+func (P *Parser) ParseInterfaceType() {
+ P.Trace("InterfaceType");
+ P.Expect(Scanner.INTERFACE);
+ P.Expect(Scanner.LBRACE);
+ for P.tok != Scanner.RBRACE {
+ P.ParseMethodDecl();
+ }
+ P.Next();
+ P.Ecart();
+}
+
+
+func (P *Parser) ParseAnonymousSignature();
+
+
+func (P *Parser) ParseFunctionType() {
+ P.Trace("FunctionType");
+ P.Expect(Scanner.FUNC);
+ P.ParseAnonymousSignature();
+ P.Ecart();
+}
+
+
+func (P *Parser) ParseMapType() {
+ P.Trace("MapType");
+ P.Expect(Scanner.MAP);
+ P.Expect(Scanner.LBRACK);
+ P.ParseType();
+ P.Expect(Scanner.RBRACK);
+ P.ParseType();
+ P.Ecart();
+}
+
+
+func (P *Parser) ParseFieldDecl() {
+ P.Trace("FieldDecl");
+ P.ParseIdentList();
+ P.ParseType();
+ P.Ecart();
+}
+
+
+func (P *Parser) ParseStructType() {
+ P.Trace("StructType");
+ P.Expect(Scanner.STRUCT);
+ P.Expect(Scanner.LBRACE);
+ for P.tok != Scanner.RBRACE {
+ P.ParseFieldDecl();
+ if P.tok != Scanner.RBRACE {
+ P.Expect(Scanner.SEMICOLON);
+ }
+ }
+ P.Optional(Scanner.SEMICOLON);
+ P.Expect(Scanner.RBRACE);
+ P.Ecart();
+}
+
+
+func (P *Parser) ParsePointerType() {
+ P.Trace("PointerType");
+ P.Expect(Scanner.MUL);
+ P.ParseType();
+ P.Ecart();
+}
+
+
+func (P *Parser) TryType() bool {
+ P.Trace("Type (try)");
+ 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;
+ }
+ P.Ecart();
+ return true;
+}
+
+
+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();
+ for P.tok != Scanner.RPAREN {
+ P.ParseImportSpec();
+ P.Optional(Scanner.SEMICOLON); // TODO this seems wrong
+ }
+ P.Next();
+ } else {
+ P.ParseImportSpec();
+ }
+ P.Ecart();
+}
+
+
+func (P *Parser) ParseExpressionList() {
+ P.Trace("ExpressionList");
+ P.ParseExpression();
+ for P.tok == Scanner.COMMA {
+ P.Next();
+ P.ParseExpression();
+ }
+ P.Ecart();
+}
+
+
+func (P *Parser) ParseConstSpec() {
+ P.Trace("ConstSpec");
+ P.ParseIdent();
+ P.TryType();
+ if P.tok == Scanner.ASSIGN {
+ P.Next();
+ P.ParseExpression();
+ }
+ P.Ecart();
+}
+
+
+func (P *Parser) ParseConstDecl() {
+ P.Trace("ConstDecl");
+ P.Expect(Scanner.CONST);
+ if P.tok == Scanner.LPAREN {
+ P.Next();
+ for P.tok != Scanner.RPAREN {
+ P.ParseConstSpec();
+ if P.tok != Scanner.RPAREN {
+ P.Expect(Scanner.SEMICOLON);
+ }
+ }
+ P.Next();
+ } else {
+ P.ParseConstSpec();
+ }
+ P.Ecart();
+}
+
+
+func (P *Parser) ParseTypeSpec() {
+ P.Trace("TypeSpec");
+ P.ParseIdent();
+ P.TryType();
+ P.Ecart();
+}
+
+
+func (P *Parser) ParseTypeDecl() {
+ P.Trace("TypeDecl");
+ P.Expect(Scanner.TYPE);
+ if P.tok == Scanner.LPAREN {
+ P.Next();
+ for P.tok != Scanner.RPAREN {
+ P.ParseTypeSpec();
+ if P.tok != Scanner.RPAREN {
+ P.Expect(Scanner.SEMICOLON);
+ }
+ }
+ P.Next();
+ } else {
+ P.ParseTypeSpec();
+ }
+ P.Ecart();
+}
+
+
+func (P *Parser) ParseVarSpec() {
+ P.Trace("VarSpec");
+ P.ParseIdentList();
+ if P.tok == Scanner.ASSIGN {
+ P.Next();
+ P.ParseExpressionList();
+ } else {
+ P.ParseType();
+ 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();
+ for P.tok != Scanner.RPAREN {
+ P.ParseVarSpec();
+ if P.tok != Scanner.RPAREN {
+ P.Expect(Scanner.SEMICOLON);
+ }
+ }
+ P.Next();
+ } else {
+ P.ParseVarSpec();
+ }
+ P.Ecart();
+}
+
+
+func (P *Parser) ParseParameterSection() {
+ P.Trace("ParameterSection");
+ P.ParseIdentList();
+ P.ParseType();
+ 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();
+ }
+ P.Ecart();
+ return res;
+}
+
+
+// Anonymous signatures
+//
+// (params)
+// (params) type
+// (params) (results)
+// (recv) . (params)
+// (recv) . (params) type
+// (recv) . (params) (results)
+
+func (P *Parser) ParseAnonymousSignature() {
+ P.Trace("AnonymousSignature");
+ P.ParseParameters();
+ if P.tok == Scanner.PERIOD {
+ P.Next();
+ P.ParseParameters();
+ }
+ P.TryResult();
+ P.Ecart();
+}
+
+
+// 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() {
+ P.Trace("NamedSignature");
+ if P.tok == Scanner.LPAREN {
+ P.ParseParameters();
+ }
+ P.ParseIdent(); // function name
+ P.ParseParameters();
+ P.TryResult();
+ P.Ecart();
+}
+
+
+func (P *Parser) ParseDeclaration();
+func (P *Parser) TryStatement() bool;
+func (P *Parser) ParseStatementList();
+func (P *Parser) ParseBlock();
+func (P *Parser) ParsePrimaryExpr();
+
+
+func (P *Parser) ParsePrimaryExprList() {
+ P.Trace("PrimaryExprList");
+ P.ParsePrimaryExpr();
+ for P.tok == Scanner.COMMA {
+ P.Next();
+ P.ParsePrimaryExpr();
+ }
+ P.Ecart();
+}
+
+
+func (P *Parser) ParseBuiltinStat() {
+ P.Trace("BuiltinStat");
+ P.Expect(Scanner.IDENT);
+ P.ParseExpressionList(); // TODO should be optional
+ P.Ecart();
+}
+
+
+func (P *Parser) ParseSimpleStat() {
+ P.Trace("SimpleStat");
+ P.ParseExpression();
+ if P.tok == Scanner.COLON {
+ P.Next();
+ P.Ecart();
+ return;
+ }
+ if P.tok == Scanner.COMMA {
+ P.Next();
+ P.ParsePrimaryExprList();
+ }
+ switch P.tok {
+ case Scanner.ASSIGN: fallthrough;
+ case Scanner.DEFINE: 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.Next();
+ P.ParseExpressionList();
+ case Scanner.INC:
+ P.Next();
+ case 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) ParseStatement() {
+ P.Trace("Statement");
+ if !P.TryStatement() {
+ P.Error(P.beg, "statement expected");
+ }
+ P.Ecart();
+}
+
+
+func (P *Parser) ParseIfStat() {
+ P.Trace("IfStat");
+ P.Expect(Scanner.IF);
+ if P.tok != Scanner.LBRACE {
+ P.ParseSimpleStat();
+ if P.tok == Scanner.SEMICOLON {
+ P.Next();
+ P.ParseExpression();
+ }
+ }
+ P.ParseBlock();
+ if P.tok == Scanner.ELSE {
+ P.Next();
+ if P.tok == Scanner.IF {
+ P.ParseIfStat();
+ } else {
+ // TODO should be P.ParseBlock()
+ P.ParseStatement();
+ }
+ }
+ P.Ecart();
+}
+
+
+func (P *Parser) ParseForStat() {
+ P.Trace("ForStat");
+ P.Expect(Scanner.FOR);
+ 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();
+ 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);
+ if P.tok != Scanner.LBRACE {
+ P.ParseSimpleStat();
+ if P.tok == Scanner.SEMICOLON {
+ P.Next();
+ P.ParseExpression();
+ }
+ }
+ P.Expect(Scanner.LBRACE);
+ for P.tok != Scanner.RBRACE {
+ P.ParseCaseClause();
+ }
+ P.Expect(Scanner.RBRACE);
+ 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();
+ P.Ecart();
+}
+
+
+func (P *Parser) ParseSelectStat() bool {
+ P.Trace("SelectStat");
+ P.Expect(Scanner.SELECT);
+ P.Expect(Scanner.LBRACE);
+ for P.tok != Scanner.RBRACE {
+ 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: fallthrough;
+ case Scanner.FUNC:
+ P.ParseDeclaration();
+ case Scanner.GTR:
+ P.ParseSimpleStat(); // send
+ case Scanner.IDENT:
+ switch P.ident {
+ case "print", "panic":
+ P.ParseBuiltinStat();
+ default:
+ 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();
+ 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"
+ }
+ P.Ecart();
+ return res;
+}
+
+
+func (P *Parser) ParseStatementList() {
+ P.Trace("StatementList");
+ for P.TryStatement() {
+ P.Optional(Scanner.SEMICOLON);
+ }
+ P.Ecart();
+}
+
+
+func (P *Parser) ParseBlock() {
+ P.Trace("Block");
+ P.Expect(Scanner.LBRACE);
+ if P.tok != Scanner.RBRACE && P.tok != Scanner.SEMICOLON {
+ P.ParseStatementList();
+ }
+ P.Optional(Scanner.SEMICOLON);
+ P.Expect(Scanner.RBRACE);
+ P.Ecart();
+}
+
+
+func (P *Parser) ParseFuncDecl() {
+ P.Trace("FuncDecl");
+ P.Expect(Scanner.FUNC);
+ P.ParseNamedSignature();
+ if P.tok == Scanner.SEMICOLON {
+ // forward declaration
+ P.Next();
+ } else {
+ P.ParseBlock();
+ }
+ P.Ecart();
+}
+
+
+func (P *Parser) ParseExportDecl() {
+ P.Trace("ExportDecl");
+ P.Expect(Scanner.EXPORT);
+ if P.tok == Scanner.LPAREN {
+ P.Next();
+ for P.tok != Scanner.RPAREN {
+ P.ParseIdent();
+ P.Optional(Scanner.COMMA); // TODO this seems wrong
+ }
+ P.Next();
+ } else {
+ P.ParseIdent();
+ for P.tok == Scanner.COMMA {
+ P.Next();
+ P.ParseIdent();
+ }
+ }
+ P.Ecart();
+}
+
+
+func (P *Parser) ParseDeclaration() {
+ P.Trace("Declaration");
+ indent := P.indent;
+ switch P.tok {
+ case Scanner.CONST:
+ P.ParseConstDecl();
+ case Scanner.TYPE:
+ P.ParseTypeDecl();
+ case Scanner.VAR:
+ P.ParseVarDecl();
+ case Scanner.FUNC:
+ P.ParseFuncDecl();
+ case Scanner.EXPORT:
+ P.ParseExportDecl();
+ default:
+ P.Error(P.beg, "declaration expected");
+ }
+ if indent != P.indent {
+ panic "imbalanced tracing code"
+ }
+ P.Ecart();
+}
+
+
+func (P *Parser) ParseNew() {
+ 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();
+}
+
+
+func (P *Parser) ParseOperand() {
+ P.Trace("Operand");
+ switch P.tok {
+ case Scanner.IDENT:
+ P.ParseQualifiedIdent();
+ 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.NEW:
+ P.ParseNew();
+ default:
+ P.Error(P.beg, "operand expected");
+ }
+ P.Ecart();
+}
+
+
+func (P *Parser) ParseSelectorOrTypeAssertion() {
+ 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();
+}
+
+
+func (P *Parser) ParseIndexOrSlice() {
+ P.Trace("IndexOrSlice");
+ P.Expect(Scanner.LBRACK);
+ P.ParseExpression();
+ if P.tok == Scanner.COLON {
+ P.Next();
+ P.ParseExpression();
+ }
+ P.Expect(Scanner.RBRACK);
+ P.Ecart();
+}
+
+
+func (P *Parser) ParseInvocation() {
+ P.Trace("Invocation");
+ P.Expect(Scanner.LPAREN);
+ if P.tok != Scanner.RPAREN {
+ P.ParseExpressionList();
+ }
+ P.Expect(Scanner.RPAREN);
+ P.Ecart();
+}
+
+
+func (P *Parser) ParsePrimaryExpr() {
+ P.Trace("PrimaryExpr");
+ P.ParseOperand();
+ for {
+ switch P.tok {
+ case Scanner.PERIOD:
+ P.ParseSelectorOrTypeAssertion();
+ case Scanner.LBRACK:
+ P.ParseIndexOrSlice();
+ case Scanner.LPAREN:
+ P.ParseInvocation();
+ default:
+ P.Ecart();
+ return;
+ }
+ }
+ P.Ecart();
+}
+
+
+func (P *Parser) ParseUnaryExpr() {
+ P.Trace("UnaryExpr");
+ switch P.tok {
+ case Scanner.ADD: fallthrough;
+ case Scanner.SUB: fallthrough;
+ case Scanner.NOT: fallthrough;
+ case Scanner.XOR: fallthrough;
+ case Scanner.LSS: fallthrough;
+ case Scanner.GTR: fallthrough;
+ case Scanner.MUL: fallthrough;
+ case Scanner.AND:
+ P.Next();
+ P.ParseUnaryExpr();
+ P.Ecart();
+ return;
+ }
+ P.ParsePrimaryExpr();
+ P.Ecart();
+}
+
+
+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.EQL, Scanner.NEQ, Scanner.LSS, Scanner.LEQ, Scanner.GTR, Scanner.GEQ:
+ return 3;
+ case Scanner.ADD, Scanner.SUB, Scanner.OR, Scanner.XOR:
+ return 4;
+ case Scanner.MUL, Scanner.QUO, Scanner.REM, Scanner.SHL, Scanner.SHR, Scanner.AND:
+ return 5;
+ }
+ return 0;
+}
+
+
+func (P *Parser) ParseBinaryExpr(prec1 int) {
+ P.Trace("BinaryExpr");
+ P.ParseUnaryExpr();
+ for prec := Precedence(P.tok); prec >= prec1; prec-- {
+ for Precedence(P.tok) == prec {
+ P.Next();
+ P.ParseBinaryExpr(prec + 1);
+ }
+ }
+ P.Ecart();
+}
+
+
+func (P *Parser) ParseExpression() {
+ P.Trace("Expression");
+ indent := P.indent;
+ P.ParseBinaryExpr(1);
+ if indent != P.indent {
+ panic "imbalanced tracing code";
+ }
+ P.Ecart();
+}
+
+
+func (P *Parser) ParseProgram() {
+ P.Trace("Program");
+ P.Expect(Scanner.PACKAGE);
+ P.ParseIdent();
+ P.Optional(Scanner.SEMICOLON);
+
+ for P.tok == Scanner.IMPORT {
+ P.ParseImportDecl();
+ P.Optional(Scanner.SEMICOLON);
+ }
+
+ for P.tok != Scanner.EOF {
+ P.ParseDeclaration();
+ P.Optional(Scanner.SEMICOLON);
+ }
+ P.Ecart();
+}