()
| 241 | } |
| 242 | |
| 243 | func (p *Parser) parseClass() { |
| 244 | // Skip annotations |
| 245 | for p.peek().Value == "@" { |
| 246 | // Skip annotation until next line or identifier? |
| 247 | // Simple skip: @Annotation or @Annotation(args) |
| 248 | p.next() // @ |
| 249 | p.next() // Name |
| 250 | if p.peek().Value == "(" { |
| 251 | p.next() |
| 252 | p.skipBalanced("(", ")") |
| 253 | } |
| 254 | } |
| 255 | |
| 256 | // Skip modifiers |
| 257 | modifiers := []string{"public", "private", "protected", "abstract", "static", "final"} |
| 258 | for contains(modifiers, p.peek().Value) { |
| 259 | p.next() |
| 260 | } |
| 261 | |
| 262 | typeStr := p.peek().Value |
| 263 | if typeStr != "class" && typeStr != "interface" { |
| 264 | // Maybe enum or just skip |
| 265 | p.next() |
| 266 | return |
| 267 | } |
| 268 | p.next() // consume class/interface |
| 269 | |
| 270 | className := p.next().Value |
| 271 | classNode := &ClassNode{ |
| 272 | Name: className, |
| 273 | Type: typeStr, |
| 274 | StartLine: p.tokens[p.pos-1].Line, |
| 275 | } |
| 276 | |
| 277 | // Handle extends/implements |
| 278 | for p.peek().Value != "{" && p.pos < len(p.tokens) { |
| 279 | t := p.next() |
| 280 | if t.Value == "extends" { |
| 281 | classNode.Extends = p.next().Value |
| 282 | } else if t.Value == "implements" { |
| 283 | for p.peek().Value != "{" { |
| 284 | impl := p.next() |
| 285 | if impl.Value != "," { |
| 286 | classNode.Implements = append(classNode.Implements, impl.Value) |
| 287 | } |
| 288 | } |
| 289 | } |
| 290 | } |
| 291 | |
| 292 | p.consume("{") |
| 293 | |
| 294 | // Parse Class Body |
| 295 | p.parseClassBody(classNode) |
| 296 | |
| 297 | p.file.Classes = append(p.file.Classes, classNode) |
| 298 | } |
| 299 | |
| 300 | func (p *Parser) parseClassBody(classNode *ClassNode) { |
no test coverage detected