DoPointerType(x *PointerType);
// Declarations
+ DoImportDecl(x *ImportDecl);
DoConstDecl(x *ConstDecl);
DoTypeDecl(x *TypeDecl);
DoVarDecl(x *VarDecl);
DoVarDeclList(x *VarDeclList);
DoFuncDecl(x *FuncDecl);
+ DoMethodDecl(x *MethodDecl);
DoDeclaration(x *Declaration);
// Expressions
DoSelector(x *Selector);
// Statements
+ DoLabel(x *Label);
DoBlock(x *Block);
DoExprStat(x *ExprStat);
DoAssignment(x *Assignment);
DoReturnStat(x *ReturnStat);
DoIncDecStat(x *IncDecStat);
DoControlFlowStat(x *ControlFlowStat);
-
+ DoGoStat(x *GoStat);
+
// Program
DoProgram(x *Program);
}
// Thus, empty lists can be represented by nil.
export type List struct {
- a *[] Node
+ a *[] Node;
}
export type InterfaceType struct {
+ pos int; // position of "interface"
+ methods *List; // list of *MethodDecl
}
}
+export type ImportDecl struct {
+ ident *Ident;
+ file string;
+}
+
+
export type ConstDecl struct {
ident *Ident;
typ Type;
}
+export type MethodDecl struct {
+ ident *Ident;
+ typ *FunctionType;
+}
+
+
func (x *VarDeclList) Visit(v Visitor) { v.DoVarDeclList(x); }
+func (x *ImportDecl) Visit(v Visitor) { v.DoImportDecl(x); }
func (x *ConstDecl) Visit(v Visitor) { v.DoConstDecl(x); }
func (x *TypeDecl) Visit(v Visitor) { v.DoTypeDecl(x); }
func (x *VarDecl) Visit(v Visitor) { v.DoVarDecl(x); }
func (x *FuncDecl) Visit(v Visitor) { v.DoFuncDecl(x); }
+func (x *MethodDecl) Visit(v Visitor) { v.DoMethodDecl(x); }
func (x *Declaration) Visit(v Visitor) { v.DoDeclaration(x); }
}
+export type Label struct {
+ pos int; // position of ":"
+ ident Expr; // should be ident
+}
+
+
export type Block struct {
pos int; // position of "{"
stats *List;
}
+export type GoStat struct {
+ pos int; // position of "go"
+ expr Expr;
+}
+
+
func (x *Block) Visit(v Visitor) { v.DoBlock(x); }
+func (x *Label) Visit(v Visitor) { v.DoLabel(x); }
func (x *ExprStat) Visit(v Visitor) { v.DoExprStat(x); }
func (x *Assignment) Visit(v Visitor) { v.DoAssignment(x); }
func (x *IfStat) Visit(v Visitor) { v.DoIfStat(x); }
func (x *ReturnStat) Visit(v Visitor) { v.DoReturnStat(x); }
func (x *IncDecStat) Visit(v Visitor) { v.DoIncDecStat(x); }
func (x *ControlFlowStat) Visit(v Visitor) { v.DoControlFlowStat(x); }
+func (x *GoStat) Visit(v Visitor) { v.DoGoStat(x); }
+
// ----------------------------------------------------------------------------
// Program
func (P *Parser) ParseVarDeclList() *AST.VarDeclList {
P.Trace("VarDeclList");
- res := new(AST.VarDeclList);
- res.idents = P.ParseIdentList();
- res.typ = P.ParseVarType();
+ vars := new(AST.VarDeclList);
+ vars.idents = P.ParseIdentList();
+ vars.typ = P.ParseVarType();
P.Ecart();
- return res;
+ return vars;
}
}
-func (P *Parser) ParseMethodDecl() {
+func (P *Parser) ParseMethodDecl() *AST.MethodDecl {
P.Trace("MethodDecl");
- ident := P.ParseIdent();
- P.ParseFunctionType();
+ decl := new(AST.MethodDecl);
+ decl.ident = P.ParseIdent();
+ decl.typ = P.ParseFunctionType();
P.Optional(Scanner.SEMICOLON);
P.Ecart();
+ return decl;
}
func (P *Parser) ParseInterfaceType() *AST.InterfaceType {
P.Trace("InterfaceType");
+ typ := new(AST.InterfaceType);
+ typ.pos = P.pos;
+ typ.methods = AST.NewList();
+
P.Expect(Scanner.INTERFACE);
P.Expect(Scanner.LBRACE);
P.OpenScope();
P.level--;
- for P.tok >= Scanner.IDENT {
- P.ParseMethodDecl();
+ for P.tok == Scanner.IDENT {
+ typ.methods.Add(P.ParseMethodDecl());
}
P.level++;
P.CloseScope();
P.Expect(Scanner.RBRACE);
P.Ecart();
- return nil;
+ return typ;
}
P.Expect(Scanner.LBRACE);
P.OpenScope();
P.level--;
- for P.tok >= Scanner.IDENT {
+ for P.tok == Scanner.IDENT {
typ.fields.Add(P.ParseVarDeclList());
if P.tok != Scanner.RBRACE {
P.Expect(Scanner.SEMICOLON);
func (P *Parser) ParseBlock() *AST.Block {
P.Trace("Block");
- pos := P.pos;
+ block := new(AST.Block);
+ block.pos = P.pos;
+
P.Expect(Scanner.LBRACE);
P.OpenScope();
- var stats *AST.List;
if P.tok != Scanner.RBRACE && P.tok != Scanner.SEMICOLON {
- stats = P.ParseStatementList();
+ block.stats = P.ParseStatementList();
}
P.Optional(Scanner.SEMICOLON);
P.CloseScope();
P.Expect(Scanner.RBRACE);
P.Ecart();
-
- x := new(AST.Block);
- x.pos, x.stats = pos, stats;
- return x;
+ return block;
}
func (P *Parser) ParseOperand() AST.Expr {
P.Trace("Operand");
- var z AST.Expr;
+ var op AST.Expr;
+
switch P.tok {
case Scanner.IDENT:
- z = P.ParseIdent();
+ op = P.ParseIdent();
case Scanner.LPAREN:
P.Next();
- z = P.ParseExpression();
+ op = P.ParseExpression();
P.Expect(Scanner.RPAREN);
case Scanner.INT, Scanner.FLOAT, Scanner.STRING:
- x := new(AST.Literal);
- x.pos, x.tok, x.val = P.pos, P.tok, P.val;
- z = x;
+ lit := new(AST.Literal);
+ lit.pos, lit.tok, lit.val = P.pos, P.tok, P.val;
+ op = lit;
P.Next();
case Scanner.FUNC:
- z = P.ParseFunctionLit();
+ op = P.ParseFunctionLit();
case Scanner.HASH:
P.Next();
P.ParseType();
P.ParseCompositeLit();
- z = nil;
+ op = AST.NIL;
default:
if P.tok != Scanner.IDENT {
typ, ok := P.TryType();
if ok {
- z = P.ParseCompositeLit();
+ op = P.ParseCompositeLit();
break;
}
}
}
P.Ecart();
- return z;
+ return op;
}
}
-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.ARROW:
- 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(prec1 int) AST.Expr {
P.Trace("BinaryExpr");
x := P.ParseUnaryExpr();
- for prec := Precedence(P.tok); prec >= prec1; prec-- {
- for Precedence(P.tok) == prec {
+ 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);
switch P.tok {
case Scanner.COLON:
// label declaration
+ l := new(AST.Label);
+ l.pos = P.pos;
+ if x.len() == 1 {
+ l.ident = x.at(0);
+ } else {
+ P.Error(P.pos, "illegal label declaration");
+ l.ident = AST.NIL;
+ }
P.Next(); // consume ":"
+ stat = l;
case
Scanner.DEFINE, Scanner.ASSIGN, Scanner.ADD_ASSIGN,
pos, tok := P.pos, P.tok;
P.Next();
y := P.ParseExpressionList();
- asgn := new(AST.Assignment);
- asgn.pos, asgn.tok, asgn.lhs, asgn.rhs = pos, tok, x, y;
- stat = asgn;
+ a := new(AST.Assignment);
+ a.pos, a.tok, a.lhs, a.rhs = pos, tok, x, y;
+ stat = a;
default:
if P.tok == Scanner.INC || P.tok == Scanner.DEC {
P.Next();
stat = s;
} else {
- xstat := new(AST.ExprStat);
+ s := new(AST.ExprStat);
if x != nil && x.len() > 0 {
- xstat.expr = x.at(0);
+ s.expr = x.at(0);
} else {
// this is a syntax error
- xstat.expr = AST.NIL;
+ s.expr = AST.NIL;
}
- stat = xstat;
+ stat = s;
}
}
}
-func (P *Parser) ParseGoStat() {
+func (P *Parser) ParseGoStat() *AST.GoStat {
P.Trace("GoStat");
+ stat := new(AST.GoStat);
+ stat.pos = P.pos;
+
P.Expect(Scanner.GO);
- P.ParseExpression();
+ stat.expr = P.ParseExpression();
P.Ecart();
+ return stat;
}
case Scanner.MUL, Scanner.ARROW, Scanner.IDENT, Scanner.LPAREN:
stat = P.ParseSimpleStat();
case Scanner.GO:
- P.ParseGoStat();
+ stat = P.ParseGoStat();
case Scanner.RETURN:
stat = P.ParseReturnStat();
case Scanner.BREAK, Scanner.CONTINUE, Scanner.GOTO:
// ----------------------------------------------------------------------------
// Declarations
-func (P *Parser) ParseImportSpec() {
+func (P *Parser) ParseImportSpec() *AST.ImportDecl {
P.Trace("ImportSpec");
+ decl := new(AST.ImportDecl);
+
if P.tok == Scanner.PERIOD {
P.Error(P.pos, `"import ." not yet handled properly`);
P.Next();
} else if P.tok == Scanner.IDENT {
- P.ParseIdent();
+ decl.ident = P.ParseIdent();
}
if P.tok == Scanner.STRING {
// TODO eventually the scanner should strip the quotes
+ decl.file = P.val;
P.Next();
} else {
P.Expect(Scanner.STRING); // use Expect() error handling
}
P.Ecart();
+ return decl;
}
// TODO Replace this by using function pointers derived from methods.
func (P *Parser) ParseSpec(exported bool, keyword int) AST.Decl {
- var decl AST.Decl = AST.NIL;
switch keyword {
- case Scanner.IMPORT: P.ParseImportSpec();
- case Scanner.CONST: decl = P.ParseConstSpec(exported);
- case Scanner.TYPE: decl = P.ParseTypeSpec(exported);
- case Scanner.VAR: decl = P.ParseVarSpec(exported);
- default: panic("UNREACHABLE");
+ case Scanner.IMPORT: return P.ParseImportSpec();
+ case Scanner.CONST: return P.ParseConstSpec(exported);
+ case Scanner.TYPE: return P.ParseTypeSpec(exported);
+ case Scanner.VAR: return P.ParseVarSpec(exported);
}
- return decl;
+ panic("UNREACHABLE");
+ return AST.NIL;
}
}
for P.tok == Scanner.IMPORT {
- P.ParseDecl(false, Scanner.IMPORT);
+ decls.Add(P.ParseDecl(false, Scanner.IMPORT));
P.Optional(Scanner.SEMICOLON);
}
// Printer implements AST.Visitor
type Printer struct {
indent int;
+ prec int; // operator precedence
}
func (P *Printer) Print(x AST.Node) {
+ outer := P.prec;
+ P.prec = 0;
x.Visit(P);
+ P.prec = outer;
}
// Types
func (P *Printer) DoFunctionType(x *AST.FunctionType) {
- /*
- if x.recv != nil {
- P.DoVarDeclList(x.recv);
- }
- */
P.String("(");
P.PrintList(x.params);
- P.String(") ");
+ P.String(")");
}
func (P *Printer) DoMapType(x *AST.MapType) {
+ P.String("[");
+ P.Print(x.key);
+ P.String("] ");
+ P.Print(x.val);
}
func (P *Printer) DoInterfaceType(x *AST.InterfaceType) {
+ P.String("interface {");
+ if x.methods.len() > 0 {
+ P.NewLine(1);
+ for i := 0; i < x.methods.len(); i++ {
+ if i > 0 {
+ P.NewLine(0);
+ }
+ P.Print(x.methods.at(i));
+ P.String(";");
+ }
+ P.NewLine(-1);
+ }
+ P.String("}");
}
func (P *Printer) DoBlock(x *AST.Block);
+func (P *Printer) DoImportDecl(x *AST.ImportDecl) {
+ if x.ident != nil {
+ P.Print(x.ident);
+ P.String(" ");
+ }
+ P.String(x.file);
+}
+
+
func (P *Printer) DoConstDecl(x *AST.ConstDecl) {
P.Print(x.ident);
P.String(" ");
}
P.DoIdent(x.ident);
P.DoFunctionType(x.typ);
+ P.String(" ");
if x.body != nil {
P.DoBlock(x.body);
} else {
}
+func (P *Printer) DoMethodDecl(x *AST.MethodDecl) {
+ P.DoIdent(x.ident);
+ P.DoFunctionType(x.typ);
+}
+
+
func (P *Printer) DoDeclaration(x *AST.Declaration) {
P.String(Scanner.TokenName(x.tok));
P.String(" ");
// Expressions
func (P *Printer) DoBinary(x *AST.Binary) {
- print("(");
+ outer := P.prec;
+ P.prec = Scanner.Precedence(x.tok);
+
+ if P.prec < outer {
+ print("(");
+ }
+
P.Print(x.x);
P.String(" " + Scanner.TokenName(x.tok) + " ");
P.Print(x.y);
- print(")");
+
+ if P.prec < outer {
+ print(")");
+ }
+
+ P.prec = outer;
}
// Statements
func (P *Printer) DoBlock(x *AST.Block) {
- if x == nil || x.stats == nil {
- P.NewLine(0);
- return;
- }
-
P.String("{");
- P.NewLine(1);
- for i := 0; i < x.stats.len(); i++ {
- if i > 0 {
- P.NewLine(0);
+ if x.stats != nil {
+ P.NewLine(1);
+ for i := 0; i < x.stats.len(); i++ {
+ if i > 0 {
+ P.NewLine(0);
+ }
+ P.Print(x.stats.at(i));
}
- P.Print(x.stats.at(i));
+ P.NewLine(-1);
}
- P.NewLine(-1);
P.String("}");
}
+func (P *Printer) DoLabel(x *AST.Label) {
+ P.Print(x.ident);
+ P.String(":");
+}
+
+
func (P *Printer) DoExprStat(x *AST.ExprStat) {
P.Print(x.expr);
- P.String(";");
+ //P.String(";");
}
P.PrintList(x.lhs);
P.String(" " + Scanner.TokenName(x.tok) + " ");
P.PrintList(x.rhs);
- P.String(";");
+ //P.String(";");
}
func (P *Printer) DoIncDecStat(x *AST.IncDecStat) {
P.Print(x.expr);
P.String(Scanner.TokenName(x.tok));
- P.String(";");
+ //P.String(";");
}
}
+func (P *Printer) DoGoStat(x *AST.GoStat) {
+ P.String("go ");
+ P.Print(x.expr);
+ P.String(";");
+}
+
+
// ----------------------------------------------------------------------------
// Program