Robert Griesemer | 835cd46 | 2008-07-07 17:27:14 -0700 | [diff] [blame] | 1 | // Copyright 2009 The Go Authors. All rights reserved. |
| 2 | // Use of this source code is governed by a BSD-style |
| 3 | // license that can be found in the LICENSE file. |
| 4 | |
| 5 | package Parser |
| 6 | |
| 7 | import Scanner "scanner" |
| 8 | |
| 9 | |
| 10 | export Parser |
| 11 | type Parser struct { |
Robert Griesemer | c40be3b | 2008-07-08 16:39:04 -0700 | [diff] [blame] | 12 | verbose, indent int; |
Robert Griesemer | 835cd46 | 2008-07-07 17:27:14 -0700 | [diff] [blame] | 13 | S *Scanner.Scanner; |
| 14 | tok int; // one token look-ahead |
| 15 | beg, end int; // token position |
Robert Griesemer | c40be3b | 2008-07-08 16:39:04 -0700 | [diff] [blame] | 16 | ident string; // last ident seen |
Robert Griesemer | 835cd46 | 2008-07-07 17:27:14 -0700 | [diff] [blame] | 17 | } |
| 18 | |
| 19 | |
Robert Griesemer | c40be3b | 2008-07-08 16:39:04 -0700 | [diff] [blame] | 20 | func (P *Parser) PrintIndent() { |
| 21 | for i := P.indent; i > 0; i-- { |
Robert Griesemer | 415397e | 2008-07-09 14:48:26 -0700 | [diff] [blame] | 22 | print ". "; |
Robert Griesemer | c40be3b | 2008-07-08 16:39:04 -0700 | [diff] [blame] | 23 | } |
| 24 | } |
| 25 | |
| 26 | |
| 27 | func (P *Parser) Trace(msg string) { |
| 28 | if P.verbose > 0 { |
| 29 | P.PrintIndent(); |
| 30 | print msg, " {\n"; |
| 31 | P.indent++; |
| 32 | } |
| 33 | } |
| 34 | |
| 35 | |
| 36 | func (P *Parser) Ecart() { |
| 37 | if P.verbose > 0 { |
| 38 | P.indent--; |
| 39 | P.PrintIndent(); |
| 40 | print "}\n"; |
| 41 | } |
| 42 | } |
| 43 | |
| 44 | |
| 45 | func (P *Parser) Next() { |
| 46 | P.tok, P.beg, P.end = P.S.Scan(); |
| 47 | if P.tok == Scanner.IDENT { |
| 48 | P.ident = P.S.src[P.beg : P.end]; |
| 49 | } |
| 50 | if P.verbose > 1 { |
| 51 | P.PrintIndent(); |
| 52 | print Scanner.TokenName(P.tok), "\n"; |
| 53 | } |
| 54 | } |
| 55 | |
| 56 | |
| 57 | func (P *Parser) Open(S *Scanner.Scanner, verbose int) { |
Robert Griesemer | 835cd46 | 2008-07-07 17:27:14 -0700 | [diff] [blame] | 58 | P.verbose = verbose; |
Robert Griesemer | c40be3b | 2008-07-08 16:39:04 -0700 | [diff] [blame] | 59 | P.indent = 0; |
Robert Griesemer | 835cd46 | 2008-07-07 17:27:14 -0700 | [diff] [blame] | 60 | P.S = S; |
| 61 | P.Next(); |
| 62 | } |
| 63 | |
| 64 | |
Robert Griesemer | 8be580e | 2008-07-10 14:42:33 -0700 | [diff] [blame^] | 65 | func (P *Parser) Error(pos int, msg string) { |
| 66 | P.S.Error(pos, msg); |
Robert Griesemer | 8e4ee00 | 2008-07-08 18:37:31 -0700 | [diff] [blame] | 67 | P.Next(); // make progress |
Robert Griesemer | 835cd46 | 2008-07-07 17:27:14 -0700 | [diff] [blame] | 68 | } |
| 69 | |
| 70 | |
| 71 | func (P *Parser) Expect(tok int) { |
Robert Griesemer | 8e4ee00 | 2008-07-08 18:37:31 -0700 | [diff] [blame] | 72 | if P.tok == tok { |
| 73 | P.Next() |
| 74 | } else { |
Robert Griesemer | 8be580e | 2008-07-10 14:42:33 -0700 | [diff] [blame^] | 75 | P.Error(P.beg, "expected '" + Scanner.TokenName(tok) + "', found '" + Scanner.TokenName(P.tok) + "'"); |
Robert Griesemer | 835cd46 | 2008-07-07 17:27:14 -0700 | [diff] [blame] | 76 | } |
Robert Griesemer | 835cd46 | 2008-07-07 17:27:14 -0700 | [diff] [blame] | 77 | } |
| 78 | |
| 79 | |
Robert Griesemer | 8e4ee00 | 2008-07-08 18:37:31 -0700 | [diff] [blame] | 80 | func (P *Parser) Optional(tok int) { |
| 81 | if P.tok == tok { |
| 82 | P.Next(); |
| 83 | } |
| 84 | } |
| 85 | |
| 86 | |
| 87 | func (P *Parser) TryType() bool; |
Robert Griesemer | 835cd46 | 2008-07-07 17:27:14 -0700 | [diff] [blame] | 88 | func (P *Parser) ParseExpression(); |
| 89 | |
| 90 | |
| 91 | func (P *Parser) ParseIdent() { |
Robert Griesemer | c40be3b | 2008-07-08 16:39:04 -0700 | [diff] [blame] | 92 | if P.verbose > 0 { |
| 93 | P.PrintIndent(); |
| 94 | print "Ident = \"", P.ident, "\"\n"; |
| 95 | } |
Robert Griesemer | 835cd46 | 2008-07-07 17:27:14 -0700 | [diff] [blame] | 96 | P.Expect(Scanner.IDENT); |
| 97 | } |
| 98 | |
| 99 | |
| 100 | func (P *Parser) ParseIdentList() { |
| 101 | P.Trace("IdentList"); |
| 102 | P.ParseIdent(); |
| 103 | for P.tok == Scanner.COMMA { |
| 104 | P.Next(); |
| 105 | P.ParseIdent(); |
| 106 | } |
Robert Griesemer | c40be3b | 2008-07-08 16:39:04 -0700 | [diff] [blame] | 107 | P.Ecart(); |
Robert Griesemer | 835cd46 | 2008-07-07 17:27:14 -0700 | [diff] [blame] | 108 | } |
| 109 | |
| 110 | |
| 111 | func (P *Parser) ParseQualifiedIdent() { |
| 112 | P.Trace("QualifiedIdent"); |
| 113 | P.ParseIdent(); |
| 114 | if P.tok == Scanner.PERIOD { |
| 115 | P.Next(); |
| 116 | P.ParseIdent(); |
| 117 | } |
Robert Griesemer | c40be3b | 2008-07-08 16:39:04 -0700 | [diff] [blame] | 118 | P.Ecart(); |
Robert Griesemer | 835cd46 | 2008-07-07 17:27:14 -0700 | [diff] [blame] | 119 | } |
| 120 | |
| 121 | |
| 122 | func (P *Parser) ParseTypeName() { |
| 123 | P.Trace("TypeName"); |
| 124 | P.ParseQualifiedIdent(); |
Robert Griesemer | c40be3b | 2008-07-08 16:39:04 -0700 | [diff] [blame] | 125 | P.Ecart(); |
Robert Griesemer | 835cd46 | 2008-07-07 17:27:14 -0700 | [diff] [blame] | 126 | } |
| 127 | |
| 128 | |
Robert Griesemer | 8e4ee00 | 2008-07-08 18:37:31 -0700 | [diff] [blame] | 129 | func (P *Parser) ParseType() { |
| 130 | P.Trace("Type"); |
| 131 | if !P.TryType() { |
Robert Griesemer | 8be580e | 2008-07-10 14:42:33 -0700 | [diff] [blame^] | 132 | P.Error(P.beg, "type expected"); |
Robert Griesemer | 8e4ee00 | 2008-07-08 18:37:31 -0700 | [diff] [blame] | 133 | } |
| 134 | P.Ecart(); |
| 135 | } |
| 136 | |
| 137 | |
Robert Griesemer | 835cd46 | 2008-07-07 17:27:14 -0700 | [diff] [blame] | 138 | func (P *Parser) ParseArrayType() { |
| 139 | P.Trace("ArrayType"); |
| 140 | P.Expect(Scanner.LBRACK); |
| 141 | if P.tok != Scanner.RBRACK { |
| 142 | P.ParseExpression(); |
| 143 | } |
| 144 | P.Expect(Scanner.RBRACK); |
| 145 | P.ParseType(); |
Robert Griesemer | c40be3b | 2008-07-08 16:39:04 -0700 | [diff] [blame] | 146 | P.Ecart(); |
Robert Griesemer | 835cd46 | 2008-07-07 17:27:14 -0700 | [diff] [blame] | 147 | } |
| 148 | |
| 149 | |
| 150 | func (P *Parser) ParseChannelType() { |
| 151 | P.Trace("ChannelType"); |
Robert Griesemer | 8e4ee00 | 2008-07-08 18:37:31 -0700 | [diff] [blame] | 152 | P.Expect(Scanner.CHAN); |
| 153 | switch P.tok { |
| 154 | case Scanner.LSS: fallthrough |
| 155 | case Scanner.GTR: |
| 156 | P.Next(); |
| 157 | } |
| 158 | P.ParseType(); |
Robert Griesemer | c40be3b | 2008-07-08 16:39:04 -0700 | [diff] [blame] | 159 | P.Ecart(); |
Robert Griesemer | 835cd46 | 2008-07-07 17:27:14 -0700 | [diff] [blame] | 160 | } |
| 161 | |
| 162 | |
Robert Griesemer | 1e9adf8 | 2008-07-09 10:45:04 -0700 | [diff] [blame] | 163 | func (P *Parser) ParseParameters(); |
| 164 | func (P *Parser) TryResult() bool; |
| 165 | |
| 166 | |
| 167 | func (P *Parser) ParseMethodDecl() { |
| 168 | P.Trace("MethodDecl"); |
| 169 | P.ParseIdent(); |
| 170 | P.ParseParameters(); |
| 171 | P.TryResult(); |
| 172 | P.Optional(Scanner.SEMICOLON); |
Robert Griesemer | c40be3b | 2008-07-08 16:39:04 -0700 | [diff] [blame] | 173 | P.Ecart(); |
Robert Griesemer | 835cd46 | 2008-07-07 17:27:14 -0700 | [diff] [blame] | 174 | } |
| 175 | |
| 176 | |
Robert Griesemer | 1e9adf8 | 2008-07-09 10:45:04 -0700 | [diff] [blame] | 177 | func (P *Parser) ParseInterfaceType() { |
| 178 | P.Trace("InterfaceType"); |
| 179 | P.Expect(Scanner.INTERFACE); |
| 180 | P.Expect(Scanner.LBRACE); |
| 181 | for P.tok != Scanner.RBRACE { |
| 182 | P.ParseMethodDecl(); |
| 183 | } |
| 184 | P.Next(); |
| 185 | P.Ecart(); |
| 186 | } |
| 187 | |
| 188 | |
| 189 | func (P *Parser) ParseAnonymousSignature(); |
| 190 | |
| 191 | |
Robert Griesemer | 835cd46 | 2008-07-07 17:27:14 -0700 | [diff] [blame] | 192 | func (P *Parser) ParseFunctionType() { |
| 193 | P.Trace("FunctionType"); |
Robert Griesemer | 1e9adf8 | 2008-07-09 10:45:04 -0700 | [diff] [blame] | 194 | P.Expect(Scanner.FUNC); |
| 195 | P.ParseAnonymousSignature(); |
Robert Griesemer | c40be3b | 2008-07-08 16:39:04 -0700 | [diff] [blame] | 196 | P.Ecart(); |
Robert Griesemer | 835cd46 | 2008-07-07 17:27:14 -0700 | [diff] [blame] | 197 | } |
| 198 | |
| 199 | |
| 200 | func (P *Parser) ParseMapType() { |
| 201 | P.Trace("MapType"); |
| 202 | P.Expect(Scanner.MAP); |
| 203 | P.Expect(Scanner.LBRACK); |
| 204 | P.ParseType(); |
| 205 | P.Expect(Scanner.RBRACK); |
| 206 | P.ParseType(); |
Robert Griesemer | c40be3b | 2008-07-08 16:39:04 -0700 | [diff] [blame] | 207 | P.Ecart(); |
Robert Griesemer | 835cd46 | 2008-07-07 17:27:14 -0700 | [diff] [blame] | 208 | } |
| 209 | |
| 210 | |
| 211 | func (P *Parser) ParseFieldDecl() { |
| 212 | P.Trace("FieldDecl"); |
| 213 | P.ParseIdentList(); |
| 214 | P.ParseType(); |
Robert Griesemer | c40be3b | 2008-07-08 16:39:04 -0700 | [diff] [blame] | 215 | P.Ecart(); |
Robert Griesemer | 835cd46 | 2008-07-07 17:27:14 -0700 | [diff] [blame] | 216 | } |
| 217 | |
| 218 | |
| 219 | func (P *Parser) ParseStructType() { |
| 220 | P.Trace("StructType"); |
| 221 | P.Expect(Scanner.STRUCT); |
| 222 | P.Expect(Scanner.LBRACE); |
Robert Griesemer | c40be3b | 2008-07-08 16:39:04 -0700 | [diff] [blame] | 223 | for P.tok != Scanner.RBRACE { |
Robert Griesemer | 835cd46 | 2008-07-07 17:27:14 -0700 | [diff] [blame] | 224 | P.ParseFieldDecl(); |
Robert Griesemer | c40be3b | 2008-07-08 16:39:04 -0700 | [diff] [blame] | 225 | if P.tok != Scanner.RBRACE { |
| 226 | P.Expect(Scanner.SEMICOLON); |
Robert Griesemer | 835cd46 | 2008-07-07 17:27:14 -0700 | [diff] [blame] | 227 | } |
| 228 | } |
Robert Griesemer | 8e4ee00 | 2008-07-08 18:37:31 -0700 | [diff] [blame] | 229 | P.Optional(Scanner.SEMICOLON); |
Robert Griesemer | 835cd46 | 2008-07-07 17:27:14 -0700 | [diff] [blame] | 230 | P.Expect(Scanner.RBRACE); |
Robert Griesemer | c40be3b | 2008-07-08 16:39:04 -0700 | [diff] [blame] | 231 | P.Ecart(); |
Robert Griesemer | 835cd46 | 2008-07-07 17:27:14 -0700 | [diff] [blame] | 232 | } |
| 233 | |
| 234 | |
| 235 | func (P *Parser) ParsePointerType() { |
| 236 | P.Trace("PointerType"); |
| 237 | P.Expect(Scanner.MUL); |
| 238 | P.ParseType(); |
Robert Griesemer | c40be3b | 2008-07-08 16:39:04 -0700 | [diff] [blame] | 239 | P.Ecart(); |
Robert Griesemer | 835cd46 | 2008-07-07 17:27:14 -0700 | [diff] [blame] | 240 | } |
| 241 | |
| 242 | |
Robert Griesemer | 8e4ee00 | 2008-07-08 18:37:31 -0700 | [diff] [blame] | 243 | func (P *Parser) TryType() bool { |
| 244 | P.Trace("Type (try)"); |
Robert Griesemer | 835cd46 | 2008-07-07 17:27:14 -0700 | [diff] [blame] | 245 | switch P.tok { |
| 246 | case Scanner.IDENT: |
| 247 | P.ParseTypeName(); |
| 248 | case Scanner.LBRACK: |
| 249 | P.ParseArrayType(); |
| 250 | case Scanner.CHAN: |
| 251 | P.ParseChannelType(); |
| 252 | case Scanner.INTERFACE: |
| 253 | P.ParseInterfaceType(); |
| 254 | case Scanner.FUNC: |
| 255 | P.ParseFunctionType(); |
| 256 | case Scanner.MAP: |
| 257 | P.ParseMapType(); |
| 258 | case Scanner.STRUCT: |
| 259 | P.ParseStructType(); |
| 260 | case Scanner.MUL: |
| 261 | P.ParsePointerType(); |
| 262 | default: |
Robert Griesemer | 8e4ee00 | 2008-07-08 18:37:31 -0700 | [diff] [blame] | 263 | P.Ecart(); |
| 264 | return false; |
Robert Griesemer | 835cd46 | 2008-07-07 17:27:14 -0700 | [diff] [blame] | 265 | } |
Robert Griesemer | c40be3b | 2008-07-08 16:39:04 -0700 | [diff] [blame] | 266 | P.Ecart(); |
Robert Griesemer | 8e4ee00 | 2008-07-08 18:37:31 -0700 | [diff] [blame] | 267 | return true; |
Robert Griesemer | 835cd46 | 2008-07-07 17:27:14 -0700 | [diff] [blame] | 268 | } |
| 269 | |
| 270 | |
| 271 | func (P *Parser) ParseImportSpec() { |
| 272 | P.Trace("ImportSpec"); |
| 273 | if P.tok == Scanner.PERIOD { |
| 274 | P.Next(); |
| 275 | } else if P.tok == Scanner.IDENT { |
| 276 | P.Next(); |
| 277 | } |
| 278 | P.Expect(Scanner.STRING); |
Robert Griesemer | c40be3b | 2008-07-08 16:39:04 -0700 | [diff] [blame] | 279 | P.Ecart(); |
Robert Griesemer | 835cd46 | 2008-07-07 17:27:14 -0700 | [diff] [blame] | 280 | } |
| 281 | |
| 282 | |
| 283 | func (P *Parser) ParseImportDecl() { |
| 284 | P.Trace("ImportDecl"); |
| 285 | P.Expect(Scanner.IMPORT); |
| 286 | if P.tok == Scanner.LPAREN { |
Robert Griesemer | 33069d39 | 2008-07-09 10:16:33 -0700 | [diff] [blame] | 287 | P.Next(); |
| 288 | for P.tok != Scanner.RPAREN { |
Robert Griesemer | 835cd46 | 2008-07-07 17:27:14 -0700 | [diff] [blame] | 289 | P.ParseImportSpec(); |
Robert Griesemer | 33069d39 | 2008-07-09 10:16:33 -0700 | [diff] [blame] | 290 | P.Optional(Scanner.SEMICOLON); // TODO this seems wrong |
Robert Griesemer | 835cd46 | 2008-07-07 17:27:14 -0700 | [diff] [blame] | 291 | } |
Robert Griesemer | 33069d39 | 2008-07-09 10:16:33 -0700 | [diff] [blame] | 292 | P.Next(); |
Robert Griesemer | 835cd46 | 2008-07-07 17:27:14 -0700 | [diff] [blame] | 293 | } else { |
| 294 | P.ParseImportSpec(); |
| 295 | } |
Robert Griesemer | c40be3b | 2008-07-08 16:39:04 -0700 | [diff] [blame] | 296 | P.Ecart(); |
Robert Griesemer | 835cd46 | 2008-07-07 17:27:14 -0700 | [diff] [blame] | 297 | } |
| 298 | |
| 299 | |
| 300 | func (P *Parser) ParseExpressionList() { |
Robert Griesemer | c40be3b | 2008-07-08 16:39:04 -0700 | [diff] [blame] | 301 | P.Trace("ExpressionList"); |
Robert Griesemer | 835cd46 | 2008-07-07 17:27:14 -0700 | [diff] [blame] | 302 | P.ParseExpression(); |
| 303 | for P.tok == Scanner.COMMA { |
| 304 | P.Next(); |
| 305 | P.ParseExpression(); |
| 306 | } |
Robert Griesemer | c40be3b | 2008-07-08 16:39:04 -0700 | [diff] [blame] | 307 | P.Ecart(); |
Robert Griesemer | 835cd46 | 2008-07-07 17:27:14 -0700 | [diff] [blame] | 308 | } |
| 309 | |
| 310 | |
| 311 | func (P *Parser) ParseConstSpec() { |
| 312 | P.Trace("ConstSpec"); |
| 313 | P.ParseIdent(); |
Robert Griesemer | 8e4ee00 | 2008-07-08 18:37:31 -0700 | [diff] [blame] | 314 | P.TryType(); |
Robert Griesemer | 835cd46 | 2008-07-07 17:27:14 -0700 | [diff] [blame] | 315 | if P.tok == Scanner.ASSIGN { |
| 316 | P.Next(); |
| 317 | P.ParseExpression(); |
| 318 | } |
Robert Griesemer | c40be3b | 2008-07-08 16:39:04 -0700 | [diff] [blame] | 319 | P.Ecart(); |
Robert Griesemer | 835cd46 | 2008-07-07 17:27:14 -0700 | [diff] [blame] | 320 | } |
| 321 | |
| 322 | |
| 323 | func (P *Parser) ParseConstDecl() { |
| 324 | P.Trace("ConstDecl"); |
| 325 | P.Expect(Scanner.CONST); |
| 326 | if P.tok == Scanner.LPAREN { |
Robert Griesemer | 8e4ee00 | 2008-07-08 18:37:31 -0700 | [diff] [blame] | 327 | P.Next(); |
| 328 | for P.tok != Scanner.RPAREN { |
Robert Griesemer | 835cd46 | 2008-07-07 17:27:14 -0700 | [diff] [blame] | 329 | P.ParseConstSpec(); |
Robert Griesemer | 8e4ee00 | 2008-07-08 18:37:31 -0700 | [diff] [blame] | 330 | if P.tok != Scanner.RPAREN { |
| 331 | P.Expect(Scanner.SEMICOLON); |
| 332 | } |
Robert Griesemer | 835cd46 | 2008-07-07 17:27:14 -0700 | [diff] [blame] | 333 | } |
Robert Griesemer | 8e4ee00 | 2008-07-08 18:37:31 -0700 | [diff] [blame] | 334 | P.Next(); |
Robert Griesemer | 835cd46 | 2008-07-07 17:27:14 -0700 | [diff] [blame] | 335 | } else { |
| 336 | P.ParseConstSpec(); |
| 337 | } |
Robert Griesemer | c40be3b | 2008-07-08 16:39:04 -0700 | [diff] [blame] | 338 | P.Ecart(); |
Robert Griesemer | 835cd46 | 2008-07-07 17:27:14 -0700 | [diff] [blame] | 339 | } |
| 340 | |
| 341 | |
| 342 | func (P *Parser) ParseTypeSpec() { |
| 343 | P.Trace("TypeSpec"); |
| 344 | P.ParseIdent(); |
Robert Griesemer | 8e4ee00 | 2008-07-08 18:37:31 -0700 | [diff] [blame] | 345 | P.TryType(); |
Robert Griesemer | c40be3b | 2008-07-08 16:39:04 -0700 | [diff] [blame] | 346 | P.Ecart(); |
Robert Griesemer | 835cd46 | 2008-07-07 17:27:14 -0700 | [diff] [blame] | 347 | } |
| 348 | |
| 349 | |
| 350 | func (P *Parser) ParseTypeDecl() { |
| 351 | P.Trace("TypeDecl"); |
| 352 | P.Expect(Scanner.TYPE); |
| 353 | if P.tok == Scanner.LPAREN { |
Robert Griesemer | 8e4ee00 | 2008-07-08 18:37:31 -0700 | [diff] [blame] | 354 | P.Next(); |
| 355 | for P.tok != Scanner.RPAREN { |
Robert Griesemer | 835cd46 | 2008-07-07 17:27:14 -0700 | [diff] [blame] | 356 | P.ParseTypeSpec(); |
Robert Griesemer | 8e4ee00 | 2008-07-08 18:37:31 -0700 | [diff] [blame] | 357 | if P.tok != Scanner.RPAREN { |
| 358 | P.Expect(Scanner.SEMICOLON); |
| 359 | } |
Robert Griesemer | 835cd46 | 2008-07-07 17:27:14 -0700 | [diff] [blame] | 360 | } |
Robert Griesemer | 8e4ee00 | 2008-07-08 18:37:31 -0700 | [diff] [blame] | 361 | P.Next(); |
Robert Griesemer | 835cd46 | 2008-07-07 17:27:14 -0700 | [diff] [blame] | 362 | } else { |
| 363 | P.ParseTypeSpec(); |
| 364 | } |
Robert Griesemer | c40be3b | 2008-07-08 16:39:04 -0700 | [diff] [blame] | 365 | P.Ecart(); |
Robert Griesemer | 835cd46 | 2008-07-07 17:27:14 -0700 | [diff] [blame] | 366 | } |
| 367 | |
| 368 | |
| 369 | func (P *Parser) ParseVarSpec() { |
| 370 | P.Trace("VarSpec"); |
| 371 | P.ParseIdentList(); |
| 372 | if P.tok == Scanner.ASSIGN { |
| 373 | P.Next(); |
| 374 | P.ParseExpressionList(); |
| 375 | } else { |
| 376 | P.ParseType(); |
| 377 | if P.tok == Scanner.ASSIGN { |
| 378 | P.Next(); |
| 379 | P.ParseExpressionList(); |
| 380 | } |
| 381 | } |
Robert Griesemer | c40be3b | 2008-07-08 16:39:04 -0700 | [diff] [blame] | 382 | P.Ecart(); |
Robert Griesemer | 835cd46 | 2008-07-07 17:27:14 -0700 | [diff] [blame] | 383 | } |
| 384 | |
| 385 | |
| 386 | func (P *Parser) ParseVarDecl() { |
| 387 | P.Trace("VarDecl"); |
| 388 | P.Expect(Scanner.VAR); |
| 389 | if P.tok == Scanner.LPAREN { |
Robert Griesemer | 8e4ee00 | 2008-07-08 18:37:31 -0700 | [diff] [blame] | 390 | P.Next(); |
| 391 | for P.tok != Scanner.RPAREN { |
Robert Griesemer | 835cd46 | 2008-07-07 17:27:14 -0700 | [diff] [blame] | 392 | P.ParseVarSpec(); |
Robert Griesemer | 8e4ee00 | 2008-07-08 18:37:31 -0700 | [diff] [blame] | 393 | if P.tok != Scanner.RPAREN { |
| 394 | P.Expect(Scanner.SEMICOLON); |
| 395 | } |
Robert Griesemer | 835cd46 | 2008-07-07 17:27:14 -0700 | [diff] [blame] | 396 | } |
Robert Griesemer | 8e4ee00 | 2008-07-08 18:37:31 -0700 | [diff] [blame] | 397 | P.Next(); |
Robert Griesemer | 835cd46 | 2008-07-07 17:27:14 -0700 | [diff] [blame] | 398 | } else { |
| 399 | P.ParseVarSpec(); |
| 400 | } |
Robert Griesemer | c40be3b | 2008-07-08 16:39:04 -0700 | [diff] [blame] | 401 | P.Ecart(); |
Robert Griesemer | 835cd46 | 2008-07-07 17:27:14 -0700 | [diff] [blame] | 402 | } |
| 403 | |
| 404 | |
| 405 | func (P *Parser) ParseParameterSection() { |
| 406 | P.Trace("ParameterSection"); |
| 407 | P.ParseIdentList(); |
| 408 | P.ParseType(); |
Robert Griesemer | c40be3b | 2008-07-08 16:39:04 -0700 | [diff] [blame] | 409 | P.Ecart(); |
Robert Griesemer | 835cd46 | 2008-07-07 17:27:14 -0700 | [diff] [blame] | 410 | } |
| 411 | |
| 412 | |
| 413 | func (P *Parser) ParseParameterList() { |
| 414 | P.Trace("ParameterList"); |
| 415 | P.ParseParameterSection(); |
| 416 | for P.tok == Scanner.COMMA { |
| 417 | P.Next(); |
| 418 | P.ParseParameterSection(); |
| 419 | } |
Robert Griesemer | c40be3b | 2008-07-08 16:39:04 -0700 | [diff] [blame] | 420 | P.Ecart(); |
Robert Griesemer | 835cd46 | 2008-07-07 17:27:14 -0700 | [diff] [blame] | 421 | } |
| 422 | |
| 423 | |
| 424 | func (P *Parser) ParseParameters() { |
| 425 | P.Trace("Parameters"); |
| 426 | P.Expect(Scanner.LPAREN); |
| 427 | if P.tok != Scanner.RPAREN { |
| 428 | P.ParseParameterList(); |
| 429 | } |
| 430 | P.Expect(Scanner.RPAREN); |
Robert Griesemer | c40be3b | 2008-07-08 16:39:04 -0700 | [diff] [blame] | 431 | P.Ecart(); |
Robert Griesemer | 835cd46 | 2008-07-07 17:27:14 -0700 | [diff] [blame] | 432 | } |
| 433 | |
| 434 | |
Robert Griesemer | 1e9adf8 | 2008-07-09 10:45:04 -0700 | [diff] [blame] | 435 | func (P *Parser) TryResult() bool { |
| 436 | P.Trace("Result (try)"); |
| 437 | res := false; |
Robert Griesemer | 835cd46 | 2008-07-07 17:27:14 -0700 | [diff] [blame] | 438 | if P.tok == Scanner.LPAREN { |
| 439 | // TODO: here we allow empty returns - should proably fix this |
| 440 | P.ParseParameters(); |
Robert Griesemer | 1e9adf8 | 2008-07-09 10:45:04 -0700 | [diff] [blame] | 441 | res = true; |
Robert Griesemer | 835cd46 | 2008-07-07 17:27:14 -0700 | [diff] [blame] | 442 | } else { |
Robert Griesemer | 1e9adf8 | 2008-07-09 10:45:04 -0700 | [diff] [blame] | 443 | res = P.TryType(); |
Robert Griesemer | 835cd46 | 2008-07-07 17:27:14 -0700 | [diff] [blame] | 444 | } |
Robert Griesemer | c40be3b | 2008-07-08 16:39:04 -0700 | [diff] [blame] | 445 | P.Ecart(); |
Robert Griesemer | 1e9adf8 | 2008-07-09 10:45:04 -0700 | [diff] [blame] | 446 | return res; |
| 447 | } |
| 448 | |
| 449 | |
| 450 | // Anonymous signatures |
| 451 | // |
| 452 | // (params) |
| 453 | // (params) type |
| 454 | // (params) (results) |
| 455 | // (recv) . (params) |
| 456 | // (recv) . (params) type |
| 457 | // (recv) . (params) (results) |
| 458 | |
| 459 | func (P *Parser) ParseAnonymousSignature() { |
| 460 | P.Trace("AnonymousSignature"); |
| 461 | P.ParseParameters(); |
| 462 | if P.tok == Scanner.PERIOD { |
| 463 | P.Next(); |
| 464 | P.ParseParameters(); |
| 465 | } |
| 466 | P.TryResult(); |
| 467 | P.Ecart(); |
Robert Griesemer | 835cd46 | 2008-07-07 17:27:14 -0700 | [diff] [blame] | 468 | } |
| 469 | |
| 470 | |
| 471 | // Named signatures |
| 472 | // |
| 473 | // name (params) |
| 474 | // name (params) type |
| 475 | // name (params) (results) |
| 476 | // (recv) name (params) |
| 477 | // (recv) name (params) type |
| 478 | // (recv) name (params) (results) |
| 479 | |
| 480 | func (P *Parser) ParseNamedSignature() { |
| 481 | P.Trace("NamedSignature"); |
| 482 | if P.tok == Scanner.LPAREN { |
| 483 | P.ParseParameters(); |
| 484 | } |
Robert Griesemer | 835cd46 | 2008-07-07 17:27:14 -0700 | [diff] [blame] | 485 | P.ParseIdent(); // function name |
Robert Griesemer | 835cd46 | 2008-07-07 17:27:14 -0700 | [diff] [blame] | 486 | P.ParseParameters(); |
Robert Griesemer | 1e9adf8 | 2008-07-09 10:45:04 -0700 | [diff] [blame] | 487 | P.TryResult(); |
Robert Griesemer | c40be3b | 2008-07-08 16:39:04 -0700 | [diff] [blame] | 488 | P.Ecart(); |
Robert Griesemer | 835cd46 | 2008-07-07 17:27:14 -0700 | [diff] [blame] | 489 | } |
| 490 | |
| 491 | |
| 492 | func (P *Parser) ParseDeclaration(); |
Robert Griesemer | 8e4ee00 | 2008-07-08 18:37:31 -0700 | [diff] [blame] | 493 | func (P *Parser) TryStatement() bool; |
Robert Griesemer | c40be3b | 2008-07-08 16:39:04 -0700 | [diff] [blame] | 494 | func (P *Parser) ParseStatementList(); |
Robert Griesemer | 835cd46 | 2008-07-07 17:27:14 -0700 | [diff] [blame] | 495 | func (P *Parser) ParseBlock(); |
Robert Griesemer | c40be3b | 2008-07-08 16:39:04 -0700 | [diff] [blame] | 496 | func (P *Parser) ParsePrimaryExpr(); |
Robert Griesemer | 835cd46 | 2008-07-07 17:27:14 -0700 | [diff] [blame] | 497 | |
| 498 | |
| 499 | func (P *Parser) ParsePrimaryExprList() { |
| 500 | P.Trace("PrimaryExprList"); |
Robert Griesemer | c40be3b | 2008-07-08 16:39:04 -0700 | [diff] [blame] | 501 | P.ParsePrimaryExpr(); |
| 502 | for P.tok == Scanner.COMMA { |
| 503 | P.Next(); |
| 504 | P.ParsePrimaryExpr(); |
| 505 | } |
| 506 | P.Ecart(); |
| 507 | } |
| 508 | |
| 509 | |
| 510 | func (P *Parser) ParseBuiltinStat() { |
| 511 | P.Trace("BuiltinStat"); |
| 512 | P.Expect(Scanner.IDENT); |
| 513 | P.ParseExpressionList(); // TODO should be optional |
| 514 | P.Ecart(); |
Robert Griesemer | 835cd46 | 2008-07-07 17:27:14 -0700 | [diff] [blame] | 515 | } |
| 516 | |
| 517 | |
| 518 | func (P *Parser) ParseSimpleStat() { |
| 519 | P.Trace("SimpleStat"); |
| 520 | P.ParseExpression(); |
Robert Griesemer | 8e4ee00 | 2008-07-08 18:37:31 -0700 | [diff] [blame] | 521 | if P.tok == Scanner.COLON { |
Robert Griesemer | 835cd46 | 2008-07-07 17:27:14 -0700 | [diff] [blame] | 522 | P.Next(); |
Robert Griesemer | 8e4ee00 | 2008-07-08 18:37:31 -0700 | [diff] [blame] | 523 | P.Ecart(); |
| 524 | return; |
| 525 | } |
| 526 | if P.tok == Scanner.COMMA { |
Robert Griesemer | 835cd46 | 2008-07-07 17:27:14 -0700 | [diff] [blame] | 527 | P.Next(); |
| 528 | P.ParsePrimaryExprList(); |
Robert Griesemer | 8e4ee00 | 2008-07-08 18:37:31 -0700 | [diff] [blame] | 529 | } |
| 530 | switch P.tok { |
| 531 | case Scanner.ASSIGN: fallthrough; |
| 532 | case Scanner.DEFINE: fallthrough; |
| 533 | case Scanner.ADD_ASSIGN: fallthrough; |
| 534 | case Scanner.SUB_ASSIGN: fallthrough; |
| 535 | case Scanner.MUL_ASSIGN: fallthrough; |
| 536 | case Scanner.QUO_ASSIGN: fallthrough; |
| 537 | case Scanner.REM_ASSIGN: fallthrough; |
| 538 | case Scanner.AND_ASSIGN: fallthrough; |
| 539 | case Scanner.OR_ASSIGN: fallthrough; |
| 540 | case Scanner.XOR_ASSIGN: fallthrough; |
| 541 | case Scanner.SHL_ASSIGN: fallthrough; |
| 542 | case Scanner.SHR_ASSIGN: |
Robert Griesemer | c40be3b | 2008-07-08 16:39:04 -0700 | [diff] [blame] | 543 | P.Next(); |
| 544 | P.ParseExpressionList(); |
Robert Griesemer | 835cd46 | 2008-07-07 17:27:14 -0700 | [diff] [blame] | 545 | case Scanner.INC: |
| 546 | P.Next(); |
| 547 | case Scanner.DEC: |
| 548 | P.Next(); |
| 549 | } |
Robert Griesemer | c40be3b | 2008-07-08 16:39:04 -0700 | [diff] [blame] | 550 | P.Ecart(); |
| 551 | } |
| 552 | |
| 553 | |
Robert Griesemer | 8e4ee00 | 2008-07-08 18:37:31 -0700 | [diff] [blame] | 554 | func (P *Parser) ParseGoStat() { |
| 555 | P.Trace("GoStat"); |
| 556 | P.Expect(Scanner.GO); |
| 557 | P.ParseExpression(); |
Robert Griesemer | 415397e | 2008-07-09 14:48:26 -0700 | [diff] [blame] | 558 | P.Ecart(); |
Robert Griesemer | 8e4ee00 | 2008-07-08 18:37:31 -0700 | [diff] [blame] | 559 | } |
| 560 | |
| 561 | |
Robert Griesemer | c40be3b | 2008-07-08 16:39:04 -0700 | [diff] [blame] | 562 | func (P *Parser) ParseReturnStat() { |
| 563 | P.Trace("ReturnStat"); |
| 564 | P.Expect(Scanner.RETURN); |
| 565 | if P.tok != Scanner.SEMICOLON && P.tok != Scanner.RBRACE { |
| 566 | P.ParseExpressionList(); |
| 567 | } |
| 568 | P.Ecart(); |
| 569 | } |
| 570 | |
| 571 | |
Robert Griesemer | 8e4ee00 | 2008-07-08 18:37:31 -0700 | [diff] [blame] | 572 | func (P *Parser) ParseControlFlowStat(tok int) { |
| 573 | P.Trace("ControlFlowStat"); |
| 574 | P.Expect(tok); |
Robert Griesemer | c40be3b | 2008-07-08 16:39:04 -0700 | [diff] [blame] | 575 | if P.tok == Scanner.IDENT { |
| 576 | P.ParseIdent(); |
| 577 | } |
| 578 | P.Ecart(); |
| 579 | } |
| 580 | |
| 581 | |
Robert Griesemer | 8e4ee00 | 2008-07-08 18:37:31 -0700 | [diff] [blame] | 582 | func (P *Parser) ParseStatement() { |
| 583 | P.Trace("Statement"); |
| 584 | if !P.TryStatement() { |
Robert Griesemer | 8be580e | 2008-07-10 14:42:33 -0700 | [diff] [blame^] | 585 | P.Error(P.beg, "statement expected"); |
Robert Griesemer | c40be3b | 2008-07-08 16:39:04 -0700 | [diff] [blame] | 586 | } |
| 587 | P.Ecart(); |
Robert Griesemer | 835cd46 | 2008-07-07 17:27:14 -0700 | [diff] [blame] | 588 | } |
| 589 | |
| 590 | |
| 591 | func (P *Parser) ParseIfStat() { |
| 592 | P.Trace("IfStat"); |
| 593 | P.Expect(Scanner.IF); |
| 594 | if P.tok != Scanner.LBRACE { |
| 595 | P.ParseSimpleStat(); |
| 596 | if P.tok == Scanner.SEMICOLON { |
Robert Griesemer | 8e4ee00 | 2008-07-08 18:37:31 -0700 | [diff] [blame] | 597 | P.Next(); |
Robert Griesemer | 835cd46 | 2008-07-07 17:27:14 -0700 | [diff] [blame] | 598 | P.ParseExpression(); |
| 599 | } |
| 600 | } |
| 601 | P.ParseBlock(); |
| 602 | if P.tok == Scanner.ELSE { |
| 603 | P.Next(); |
| 604 | if P.tok == Scanner.IF { |
| 605 | P.ParseIfStat(); |
| 606 | } else { |
| 607 | // TODO should be P.ParseBlock() |
Robert Griesemer | 8e4ee00 | 2008-07-08 18:37:31 -0700 | [diff] [blame] | 608 | P.ParseStatement(); |
Robert Griesemer | 835cd46 | 2008-07-07 17:27:14 -0700 | [diff] [blame] | 609 | } |
| 610 | } |
Robert Griesemer | c40be3b | 2008-07-08 16:39:04 -0700 | [diff] [blame] | 611 | P.Ecart(); |
Robert Griesemer | 835cd46 | 2008-07-07 17:27:14 -0700 | [diff] [blame] | 612 | } |
| 613 | |
| 614 | |
| 615 | func (P *Parser) ParseForStat() { |
| 616 | P.Trace("ForStat"); |
Robert Griesemer | c40be3b | 2008-07-08 16:39:04 -0700 | [diff] [blame] | 617 | P.Expect(Scanner.FOR); |
| 618 | if P.tok != Scanner.LBRACE { |
| 619 | if P.tok != Scanner.SEMICOLON { |
| 620 | P.ParseSimpleStat(); |
| 621 | } |
| 622 | if P.tok == Scanner.SEMICOLON { |
| 623 | P.Next(); |
| 624 | if P.tok != Scanner.SEMICOLON { |
| 625 | P.ParseExpression(); |
| 626 | } |
| 627 | P.Expect(Scanner.SEMICOLON); |
| 628 | if P.tok != Scanner.LBRACE { |
| 629 | P.ParseSimpleStat(); |
| 630 | } |
| 631 | } |
| 632 | } |
| 633 | P.ParseBlock(); |
| 634 | P.Ecart(); |
| 635 | } |
| 636 | |
| 637 | |
| 638 | func (P *Parser) ParseCase() { |
| 639 | P.Trace("Case"); |
| 640 | if P.tok == Scanner.CASE { |
| 641 | P.Next(); |
| 642 | P.ParseExpressionList(); |
| 643 | } else { |
| 644 | P.Expect(Scanner.DEFAULT); |
| 645 | } |
| 646 | P.Expect(Scanner.COLON); |
| 647 | P.Ecart(); |
| 648 | } |
| 649 | |
| 650 | |
| 651 | func (P *Parser) ParseCaseList() { |
| 652 | P.Trace("CaseList"); |
| 653 | P.ParseCase(); |
| 654 | for P.tok == Scanner.CASE || P.tok == Scanner.DEFAULT { |
| 655 | P.ParseCase(); |
| 656 | } |
| 657 | P.Ecart(); |
| 658 | } |
| 659 | |
| 660 | |
| 661 | func (P *Parser) ParseCaseClause() { |
| 662 | P.Trace("CaseClause"); |
| 663 | P.ParseCaseList(); |
| 664 | if P.tok != Scanner.FALLTHROUGH && P.tok != Scanner.RBRACE { |
| 665 | P.ParseStatementList(); |
Robert Griesemer | 8e4ee00 | 2008-07-08 18:37:31 -0700 | [diff] [blame] | 666 | P.Optional(Scanner.SEMICOLON); |
Robert Griesemer | c40be3b | 2008-07-08 16:39:04 -0700 | [diff] [blame] | 667 | } |
| 668 | if P.tok == Scanner.FALLTHROUGH { |
| 669 | P.Next(); |
Robert Griesemer | 8e4ee00 | 2008-07-08 18:37:31 -0700 | [diff] [blame] | 670 | P.Optional(Scanner.SEMICOLON); |
Robert Griesemer | c40be3b | 2008-07-08 16:39:04 -0700 | [diff] [blame] | 671 | } |
| 672 | P.Ecart(); |
Robert Griesemer | 835cd46 | 2008-07-07 17:27:14 -0700 | [diff] [blame] | 673 | } |
| 674 | |
| 675 | |
| 676 | func (P *Parser) ParseSwitchStat() { |
| 677 | P.Trace("SwitchStat"); |
Robert Griesemer | c40be3b | 2008-07-08 16:39:04 -0700 | [diff] [blame] | 678 | P.Expect(Scanner.SWITCH); |
| 679 | if P.tok != Scanner.LBRACE { |
| 680 | P.ParseSimpleStat(); |
| 681 | if P.tok == Scanner.SEMICOLON { |
Robert Griesemer | 8e4ee00 | 2008-07-08 18:37:31 -0700 | [diff] [blame] | 682 | P.Next(); |
Robert Griesemer | c40be3b | 2008-07-08 16:39:04 -0700 | [diff] [blame] | 683 | P.ParseExpression(); |
| 684 | } |
| 685 | } |
| 686 | P.Expect(Scanner.LBRACE); |
| 687 | for P.tok != Scanner.RBRACE { |
| 688 | P.ParseCaseClause(); |
| 689 | } |
| 690 | P.Expect(Scanner.RBRACE); |
| 691 | P.Ecart(); |
Robert Griesemer | 835cd46 | 2008-07-07 17:27:14 -0700 | [diff] [blame] | 692 | } |
| 693 | |
| 694 | |
Robert Griesemer | cab9492 | 2008-07-09 14:01:17 -0700 | [diff] [blame] | 695 | func (P *Parser) ParseCommCase() { |
| 696 | P.Trace("CommCase"); |
| 697 | if P.tok == Scanner.CASE { |
| 698 | P.Next(); |
| 699 | if P.tok == Scanner.GTR { |
| 700 | // send |
| 701 | P.Next(); |
| 702 | P.ParseExpression(); |
| 703 | P.Expect(Scanner.EQL); |
| 704 | P.ParseExpression(); |
| 705 | } else { |
| 706 | // receive |
| 707 | if P.tok != Scanner.LSS { |
| 708 | P.ParseIdent(); |
| 709 | P.Expect(Scanner.ASSIGN); |
| 710 | } |
| 711 | P.Expect(Scanner.LSS); |
| 712 | P.ParseExpression(); |
| 713 | } |
| 714 | } else { |
| 715 | P.Expect(Scanner.DEFAULT); |
| 716 | } |
| 717 | P.Expect(Scanner.COLON); |
| 718 | P.Ecart(); |
| 719 | } |
| 720 | |
| 721 | |
| 722 | func (P *Parser) ParseCommClause() { |
| 723 | P.Trace("CommClause"); |
| 724 | P.ParseCommCase(); |
| 725 | if P.tok != Scanner.CASE && P.tok != Scanner.DEFAULT && P.tok != Scanner.RBRACE { |
| 726 | P.ParseStatementList(); |
| 727 | P.Optional(Scanner.SEMICOLON); |
| 728 | } |
| 729 | P.Ecart(); |
| 730 | } |
| 731 | |
| 732 | |
| 733 | func (P *Parser) ParseRangeStat() bool { |
| 734 | P.Trace("RangeStat"); |
| 735 | P.Expect(Scanner.RANGE); |
| 736 | P.ParseIdentList(); |
| 737 | P.Expect(Scanner.DEFINE); |
| 738 | P.ParseExpression(); |
| 739 | P.ParseBlock(); |
| 740 | P.Ecart(); |
| 741 | } |
| 742 | |
| 743 | |
| 744 | func (P *Parser) ParseSelectStat() bool { |
| 745 | P.Trace("SelectStat"); |
| 746 | P.Expect(Scanner.SELECT); |
| 747 | P.Expect(Scanner.LBRACE); |
| 748 | for P.tok != Scanner.RBRACE { |
| 749 | P.ParseCommClause(); |
| 750 | } |
| 751 | P.Next(); |
| 752 | P.Ecart(); |
| 753 | } |
| 754 | |
| 755 | |
Robert Griesemer | 8e4ee00 | 2008-07-08 18:37:31 -0700 | [diff] [blame] | 756 | func (P *Parser) TryStatement() bool { |
| 757 | P.Trace("Statement (try)"); |
Robert Griesemer | 415397e | 2008-07-09 14:48:26 -0700 | [diff] [blame] | 758 | indent := P.indent; |
| 759 | res := true; |
Robert Griesemer | 835cd46 | 2008-07-07 17:27:14 -0700 | [diff] [blame] | 760 | switch P.tok { |
| 761 | case Scanner.CONST: fallthrough; |
| 762 | case Scanner.TYPE: fallthrough; |
| 763 | case Scanner.VAR: fallthrough; |
| 764 | case Scanner.FUNC: |
| 765 | P.ParseDeclaration(); |
Robert Griesemer | 8e4ee00 | 2008-07-08 18:37:31 -0700 | [diff] [blame] | 766 | case Scanner.GTR: |
| 767 | P.ParseSimpleStat(); // send |
Robert Griesemer | 835cd46 | 2008-07-07 17:27:14 -0700 | [diff] [blame] | 768 | case Scanner.IDENT: |
Robert Griesemer | c40be3b | 2008-07-08 16:39:04 -0700 | [diff] [blame] | 769 | switch P.ident { |
| 770 | case "print", "panic": |
| 771 | P.ParseBuiltinStat(); |
| 772 | default: |
| 773 | P.ParseSimpleStat(); |
| 774 | } |
Robert Griesemer | 835cd46 | 2008-07-07 17:27:14 -0700 | [diff] [blame] | 775 | case Scanner.GO: |
Robert Griesemer | 8e4ee00 | 2008-07-08 18:37:31 -0700 | [diff] [blame] | 776 | P.ParseGoStat(); |
Robert Griesemer | 835cd46 | 2008-07-07 17:27:14 -0700 | [diff] [blame] | 777 | case Scanner.RETURN: |
Robert Griesemer | c40be3b | 2008-07-08 16:39:04 -0700 | [diff] [blame] | 778 | P.ParseReturnStat(); |
Robert Griesemer | 8e4ee00 | 2008-07-08 18:37:31 -0700 | [diff] [blame] | 779 | case Scanner.BREAK, Scanner.CONTINUE, Scanner.GOTO: |
| 780 | P.ParseControlFlowStat(P.tok); |
Robert Griesemer | 835cd46 | 2008-07-07 17:27:14 -0700 | [diff] [blame] | 781 | case Scanner.LBRACE: |
| 782 | P.ParseBlock(); |
| 783 | case Scanner.IF: |
| 784 | P.ParseIfStat(); |
| 785 | case Scanner.FOR: |
| 786 | P.ParseForStat(); |
| 787 | case Scanner.SWITCH: |
| 788 | P.ParseSwitchStat(); |
| 789 | case Scanner.RANGE: |
Robert Griesemer | cab9492 | 2008-07-09 14:01:17 -0700 | [diff] [blame] | 790 | P.ParseRangeStat(); |
Robert Griesemer | 835cd46 | 2008-07-07 17:27:14 -0700 | [diff] [blame] | 791 | case Scanner.SELECT: |
Robert Griesemer | cab9492 | 2008-07-09 14:01:17 -0700 | [diff] [blame] | 792 | P.ParseSelectStat(); |
Robert Griesemer | 835cd46 | 2008-07-07 17:27:14 -0700 | [diff] [blame] | 793 | default: |
Robert Griesemer | c40be3b | 2008-07-08 16:39:04 -0700 | [diff] [blame] | 794 | // no statement found |
Robert Griesemer | 415397e | 2008-07-09 14:48:26 -0700 | [diff] [blame] | 795 | res = false; |
| 796 | } |
| 797 | if indent != P.indent { |
| 798 | panic "imbalanced tracing code" |
Robert Griesemer | 835cd46 | 2008-07-07 17:27:14 -0700 | [diff] [blame] | 799 | } |
Robert Griesemer | c40be3b | 2008-07-08 16:39:04 -0700 | [diff] [blame] | 800 | P.Ecart(); |
Robert Griesemer | 415397e | 2008-07-09 14:48:26 -0700 | [diff] [blame] | 801 | return res; |
Robert Griesemer | 835cd46 | 2008-07-07 17:27:14 -0700 | [diff] [blame] | 802 | } |
| 803 | |
| 804 | |
| 805 | func (P *Parser) ParseStatementList() { |
| 806 | P.Trace("StatementList"); |
Robert Griesemer | 8e4ee00 | 2008-07-08 18:37:31 -0700 | [diff] [blame] | 807 | for P.TryStatement() { |
| 808 | P.Optional(Scanner.SEMICOLON); |
Robert Griesemer | 835cd46 | 2008-07-07 17:27:14 -0700 | [diff] [blame] | 809 | } |
Robert Griesemer | c40be3b | 2008-07-08 16:39:04 -0700 | [diff] [blame] | 810 | P.Ecart(); |
Robert Griesemer | 835cd46 | 2008-07-07 17:27:14 -0700 | [diff] [blame] | 811 | } |
| 812 | |
| 813 | |
| 814 | func (P *Parser) ParseBlock() { |
| 815 | P.Trace("Block"); |
| 816 | P.Expect(Scanner.LBRACE); |
| 817 | if P.tok != Scanner.RBRACE && P.tok != Scanner.SEMICOLON { |
| 818 | P.ParseStatementList(); |
| 819 | } |
Robert Griesemer | 8e4ee00 | 2008-07-08 18:37:31 -0700 | [diff] [blame] | 820 | P.Optional(Scanner.SEMICOLON); |
Robert Griesemer | 835cd46 | 2008-07-07 17:27:14 -0700 | [diff] [blame] | 821 | P.Expect(Scanner.RBRACE); |
Robert Griesemer | c40be3b | 2008-07-08 16:39:04 -0700 | [diff] [blame] | 822 | P.Ecart(); |
Robert Griesemer | 835cd46 | 2008-07-07 17:27:14 -0700 | [diff] [blame] | 823 | } |
| 824 | |
| 825 | |
| 826 | func (P *Parser) ParseFuncDecl() { |
| 827 | P.Trace("FuncDecl"); |
| 828 | P.Expect(Scanner.FUNC); |
| 829 | P.ParseNamedSignature(); |
| 830 | if P.tok == Scanner.SEMICOLON { |
| 831 | // forward declaration |
| 832 | P.Next(); |
| 833 | } else { |
| 834 | P.ParseBlock(); |
| 835 | } |
Robert Griesemer | c40be3b | 2008-07-08 16:39:04 -0700 | [diff] [blame] | 836 | P.Ecart(); |
Robert Griesemer | 835cd46 | 2008-07-07 17:27:14 -0700 | [diff] [blame] | 837 | } |
| 838 | |
| 839 | |
| 840 | func (P *Parser) ParseExportDecl() { |
| 841 | P.Trace("ExportDecl"); |
Robert Griesemer | c40be3b | 2008-07-08 16:39:04 -0700 | [diff] [blame] | 842 | P.Expect(Scanner.EXPORT); |
Robert Griesemer | 33069d39 | 2008-07-09 10:16:33 -0700 | [diff] [blame] | 843 | if P.tok == Scanner.LPAREN { |
Robert Griesemer | c40be3b | 2008-07-08 16:39:04 -0700 | [diff] [blame] | 844 | P.Next(); |
Robert Griesemer | 33069d39 | 2008-07-09 10:16:33 -0700 | [diff] [blame] | 845 | for P.tok != Scanner.RPAREN { |
| 846 | P.ParseIdent(); |
| 847 | P.Optional(Scanner.COMMA); // TODO this seems wrong |
| 848 | } |
| 849 | P.Next(); |
| 850 | } else { |
Robert Griesemer | c40be3b | 2008-07-08 16:39:04 -0700 | [diff] [blame] | 851 | P.ParseIdent(); |
Robert Griesemer | 33069d39 | 2008-07-09 10:16:33 -0700 | [diff] [blame] | 852 | for P.tok == Scanner.COMMA { |
| 853 | P.Next(); |
| 854 | P.ParseIdent(); |
| 855 | } |
Robert Griesemer | c40be3b | 2008-07-08 16:39:04 -0700 | [diff] [blame] | 856 | } |
| 857 | P.Ecart(); |
Robert Griesemer | 835cd46 | 2008-07-07 17:27:14 -0700 | [diff] [blame] | 858 | } |
| 859 | |
| 860 | |
| 861 | func (P *Parser) ParseDeclaration() { |
| 862 | P.Trace("Declaration"); |
Robert Griesemer | 415397e | 2008-07-09 14:48:26 -0700 | [diff] [blame] | 863 | indent := P.indent; |
Robert Griesemer | 835cd46 | 2008-07-07 17:27:14 -0700 | [diff] [blame] | 864 | switch P.tok { |
| 865 | case Scanner.CONST: |
| 866 | P.ParseConstDecl(); |
| 867 | case Scanner.TYPE: |
| 868 | P.ParseTypeDecl(); |
| 869 | case Scanner.VAR: |
| 870 | P.ParseVarDecl(); |
| 871 | case Scanner.FUNC: |
| 872 | P.ParseFuncDecl(); |
| 873 | case Scanner.EXPORT: |
| 874 | P.ParseExportDecl(); |
| 875 | default: |
Robert Griesemer | 8be580e | 2008-07-10 14:42:33 -0700 | [diff] [blame^] | 876 | P.Error(P.beg, "declaration expected"); |
Robert Griesemer | 835cd46 | 2008-07-07 17:27:14 -0700 | [diff] [blame] | 877 | } |
Robert Griesemer | 415397e | 2008-07-09 14:48:26 -0700 | [diff] [blame] | 878 | if indent != P.indent { |
| 879 | panic "imbalanced tracing code" |
| 880 | } |
Robert Griesemer | c40be3b | 2008-07-08 16:39:04 -0700 | [diff] [blame] | 881 | P.Ecart(); |
| 882 | } |
| 883 | |
| 884 | |
| 885 | func (P *Parser) ParseNew() { |
| 886 | P.Trace("New"); |
| 887 | P.Expect(Scanner.NEW); |
| 888 | P.Expect(Scanner.LPAREN); |
| 889 | P.ParseType(); |
| 890 | if P.tok == Scanner.COMMA { |
| 891 | P.Next(); |
| 892 | P.ParseExpressionList() |
| 893 | } |
| 894 | P.Expect(Scanner.RPAREN); |
| 895 | P.Ecart(); |
Robert Griesemer | 835cd46 | 2008-07-07 17:27:14 -0700 | [diff] [blame] | 896 | } |
| 897 | |
| 898 | |
| 899 | func (P *Parser) ParseOperand() { |
| 900 | P.Trace("Operand"); |
Robert Griesemer | c40be3b | 2008-07-08 16:39:04 -0700 | [diff] [blame] | 901 | switch P.tok { |
| 902 | case Scanner.IDENT: |
| 903 | P.ParseQualifiedIdent(); |
Robert Griesemer | c40be3b | 2008-07-08 16:39:04 -0700 | [diff] [blame] | 904 | case Scanner.LPAREN: |
| 905 | P.Next(); |
| 906 | P.ParseExpression(); |
Robert Griesemer | 8e4ee00 | 2008-07-08 18:37:31 -0700 | [diff] [blame] | 907 | P.Expect(Scanner.RPAREN); |
Robert Griesemer | 33069d39 | 2008-07-09 10:16:33 -0700 | [diff] [blame] | 908 | case Scanner.STRING: fallthrough; |
| 909 | case Scanner.NUMBER: fallthrough; |
Robert Griesemer | 8e4ee00 | 2008-07-08 18:37:31 -0700 | [diff] [blame] | 910 | case Scanner.NIL: fallthrough; |
Robert Griesemer | c40be3b | 2008-07-08 16:39:04 -0700 | [diff] [blame] | 911 | case Scanner.IOTA: fallthrough; |
| 912 | case Scanner.TRUE: fallthrough; |
| 913 | case Scanner.FALSE: |
| 914 | P.Next(); |
| 915 | case Scanner.NEW: |
| 916 | P.ParseNew(); |
| 917 | default: |
Robert Griesemer | 8be580e | 2008-07-10 14:42:33 -0700 | [diff] [blame^] | 918 | P.Error(P.beg, "operand expected"); |
Robert Griesemer | c40be3b | 2008-07-08 16:39:04 -0700 | [diff] [blame] | 919 | } |
| 920 | P.Ecart(); |
Robert Griesemer | 835cd46 | 2008-07-07 17:27:14 -0700 | [diff] [blame] | 921 | } |
| 922 | |
| 923 | |
| 924 | func (P *Parser) ParseSelectorOrTypeAssertion() { |
| 925 | P.Trace("SelectorOrTypeAssertion"); |
Robert Griesemer | c40be3b | 2008-07-08 16:39:04 -0700 | [diff] [blame] | 926 | P.Expect(Scanner.PERIOD); |
| 927 | if P.tok == Scanner.IDENT { |
| 928 | P.ParseIdent(); |
| 929 | } else { |
| 930 | P.Expect(Scanner.LPAREN); |
| 931 | P.ParseType(); |
| 932 | P.Expect(Scanner.RPAREN); |
| 933 | } |
| 934 | P.Ecart(); |
Robert Griesemer | 835cd46 | 2008-07-07 17:27:14 -0700 | [diff] [blame] | 935 | } |
| 936 | |
| 937 | |
| 938 | func (P *Parser) ParseIndexOrSlice() { |
| 939 | P.Trace("IndexOrSlice"); |
Robert Griesemer | c40be3b | 2008-07-08 16:39:04 -0700 | [diff] [blame] | 940 | P.Expect(Scanner.LBRACK); |
| 941 | P.ParseExpression(); |
| 942 | if P.tok == Scanner.COLON { |
| 943 | P.Next(); |
| 944 | P.ParseExpression(); |
| 945 | } |
| 946 | P.Expect(Scanner.RBRACK); |
| 947 | P.Ecart(); |
Robert Griesemer | 835cd46 | 2008-07-07 17:27:14 -0700 | [diff] [blame] | 948 | } |
| 949 | |
| 950 | |
| 951 | func (P *Parser) ParseInvocation() { |
| 952 | P.Trace("Invocation"); |
Robert Griesemer | c40be3b | 2008-07-08 16:39:04 -0700 | [diff] [blame] | 953 | P.Expect(Scanner.LPAREN); |
| 954 | if P.tok != Scanner.RPAREN { |
| 955 | P.ParseExpressionList(); |
| 956 | } |
| 957 | P.Expect(Scanner.RPAREN); |
| 958 | P.Ecart(); |
Robert Griesemer | 835cd46 | 2008-07-07 17:27:14 -0700 | [diff] [blame] | 959 | } |
| 960 | |
| 961 | |
| 962 | func (P *Parser) ParsePrimaryExpr() { |
| 963 | P.Trace("PrimaryExpr"); |
| 964 | P.ParseOperand(); |
| 965 | for { |
| 966 | switch P.tok { |
| 967 | case Scanner.PERIOD: |
| 968 | P.ParseSelectorOrTypeAssertion(); |
| 969 | case Scanner.LBRACK: |
| 970 | P.ParseIndexOrSlice(); |
| 971 | case Scanner.LPAREN: |
| 972 | P.ParseInvocation(); |
| 973 | default: |
Robert Griesemer | c40be3b | 2008-07-08 16:39:04 -0700 | [diff] [blame] | 974 | P.Ecart(); |
Robert Griesemer | 835cd46 | 2008-07-07 17:27:14 -0700 | [diff] [blame] | 975 | return; |
| 976 | } |
| 977 | } |
Robert Griesemer | c40be3b | 2008-07-08 16:39:04 -0700 | [diff] [blame] | 978 | P.Ecart(); |
Robert Griesemer | 835cd46 | 2008-07-07 17:27:14 -0700 | [diff] [blame] | 979 | } |
| 980 | |
| 981 | |
| 982 | func (P *Parser) ParseUnaryExpr() { |
| 983 | P.Trace("UnaryExpr"); |
| 984 | switch P.tok { |
| 985 | case Scanner.ADD: fallthrough; |
| 986 | case Scanner.SUB: fallthrough; |
| 987 | case Scanner.NOT: fallthrough; |
| 988 | case Scanner.XOR: fallthrough; |
| 989 | case Scanner.LSS: fallthrough; |
| 990 | case Scanner.GTR: fallthrough; |
| 991 | case Scanner.MUL: fallthrough; |
| 992 | case Scanner.AND: |
Robert Griesemer | c40be3b | 2008-07-08 16:39:04 -0700 | [diff] [blame] | 993 | P.Next(); |
Robert Griesemer | 835cd46 | 2008-07-07 17:27:14 -0700 | [diff] [blame] | 994 | P.ParseUnaryExpr(); |
Robert Griesemer | c40be3b | 2008-07-08 16:39:04 -0700 | [diff] [blame] | 995 | P.Ecart(); |
Robert Griesemer | 835cd46 | 2008-07-07 17:27:14 -0700 | [diff] [blame] | 996 | return; |
| 997 | } |
| 998 | P.ParsePrimaryExpr(); |
Robert Griesemer | c40be3b | 2008-07-08 16:39:04 -0700 | [diff] [blame] | 999 | P.Ecart(); |
Robert Griesemer | 835cd46 | 2008-07-07 17:27:14 -0700 | [diff] [blame] | 1000 | } |
| 1001 | |
| 1002 | |
Robert Griesemer | 415397e | 2008-07-09 14:48:26 -0700 | [diff] [blame] | 1003 | func Precedence(tok int) int { |
| 1004 | // TODO should use a map or array here for lookup |
| 1005 | switch tok { |
Robert Griesemer | 8be580e | 2008-07-10 14:42:33 -0700 | [diff] [blame^] | 1006 | case Scanner.LOR: |
Robert Griesemer | 415397e | 2008-07-09 14:48:26 -0700 | [diff] [blame] | 1007 | return 1; |
Robert Griesemer | 8be580e | 2008-07-10 14:42:33 -0700 | [diff] [blame^] | 1008 | case Scanner.LAND: |
Robert Griesemer | 415397e | 2008-07-09 14:48:26 -0700 | [diff] [blame] | 1009 | return 2; |
| 1010 | case Scanner.EQL, Scanner.NEQ, Scanner.LSS, Scanner.LEQ, Scanner.GTR, Scanner.GEQ: |
| 1011 | return 3; |
| 1012 | case Scanner.ADD, Scanner.SUB, Scanner.OR, Scanner.XOR: |
| 1013 | return 4; |
| 1014 | case Scanner.MUL, Scanner.QUO, Scanner.REM, Scanner.SHL, Scanner.SHR, Scanner.AND: |
| 1015 | return 5; |
| 1016 | } |
| 1017 | return 0; |
| 1018 | } |
| 1019 | |
| 1020 | |
| 1021 | func (P *Parser) ParseBinaryExpr(prec1 int) { |
| 1022 | P.Trace("BinaryExpr"); |
Robert Griesemer | 835cd46 | 2008-07-07 17:27:14 -0700 | [diff] [blame] | 1023 | P.ParseUnaryExpr(); |
Robert Griesemer | 415397e | 2008-07-09 14:48:26 -0700 | [diff] [blame] | 1024 | for prec := Precedence(P.tok); prec >= prec1; prec-- { |
| 1025 | for Precedence(P.tok) == prec { |
Robert Griesemer | 8e4ee00 | 2008-07-08 18:37:31 -0700 | [diff] [blame] | 1026 | P.Next(); |
Robert Griesemer | 415397e | 2008-07-09 14:48:26 -0700 | [diff] [blame] | 1027 | P.ParseBinaryExpr(prec + 1); |
Robert Griesemer | 835cd46 | 2008-07-07 17:27:14 -0700 | [diff] [blame] | 1028 | } |
| 1029 | } |
Robert Griesemer | c40be3b | 2008-07-08 16:39:04 -0700 | [diff] [blame] | 1030 | P.Ecart(); |
Robert Griesemer | 835cd46 | 2008-07-07 17:27:14 -0700 | [diff] [blame] | 1031 | } |
| 1032 | |
| 1033 | |
Robert Griesemer | 835cd46 | 2008-07-07 17:27:14 -0700 | [diff] [blame] | 1034 | func (P *Parser) ParseExpression() { |
| 1035 | P.Trace("Expression"); |
Robert Griesemer | 415397e | 2008-07-09 14:48:26 -0700 | [diff] [blame] | 1036 | indent := P.indent; |
| 1037 | P.ParseBinaryExpr(1); |
| 1038 | if indent != P.indent { |
| 1039 | panic "imbalanced tracing code"; |
| 1040 | } |
Robert Griesemer | c40be3b | 2008-07-08 16:39:04 -0700 | [diff] [blame] | 1041 | P.Ecart(); |
Robert Griesemer | 835cd46 | 2008-07-07 17:27:14 -0700 | [diff] [blame] | 1042 | } |
| 1043 | |
| 1044 | |
| 1045 | func (P *Parser) ParseProgram() { |
| 1046 | P.Trace("Program"); |
| 1047 | P.Expect(Scanner.PACKAGE); |
| 1048 | P.ParseIdent(); |
| 1049 | for P.tok == Scanner.IMPORT { |
| 1050 | P.ParseImportDecl(); |
Robert Griesemer | 8e4ee00 | 2008-07-08 18:37:31 -0700 | [diff] [blame] | 1051 | P.Optional(Scanner.SEMICOLON); |
Robert Griesemer | 835cd46 | 2008-07-07 17:27:14 -0700 | [diff] [blame] | 1052 | } |
| 1053 | for P.tok != Scanner.EOF { |
| 1054 | P.ParseDeclaration(); |
Robert Griesemer | 8e4ee00 | 2008-07-08 18:37:31 -0700 | [diff] [blame] | 1055 | P.Optional(Scanner.SEMICOLON); |
Robert Griesemer | 835cd46 | 2008-07-07 17:27:14 -0700 | [diff] [blame] | 1056 | } |
Robert Griesemer | c40be3b | 2008-07-08 16:39:04 -0700 | [diff] [blame] | 1057 | P.Ecart(); |
Robert Griesemer | 835cd46 | 2008-07-07 17:27:14 -0700 | [diff] [blame] | 1058 | } |