144 lines
2.9 KiB
Go
144 lines
2.9 KiB
Go
|
package parser
|
||
|
|
||
|
import (
|
||
|
"go.arsenm.dev/amu/ast"
|
||
|
"go.arsenm.dev/amu/scanner"
|
||
|
)
|
||
|
|
||
|
// parseList attempts to parse a list
|
||
|
func (p *Parser) parseList(tok scanner.Token, lit string) *ast.List {
|
||
|
// Create new list
|
||
|
list := &ast.List{}
|
||
|
|
||
|
// If token is not WORD or literal is not "=list"
|
||
|
if tok != scanner.WORD || lit != "=list" {
|
||
|
// Return nil as this list is invalid
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
tok, lit = p.scan()
|
||
|
|
||
|
// If token is not PUNCT or literal is not "["
|
||
|
if tok != scanner.PUNCT || lit != "[" {
|
||
|
// Return nil as this list is invalid
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
tok, lit = p.scan()
|
||
|
|
||
|
// If token is not WORD (the name of the function)
|
||
|
if tok != scanner.WORD {
|
||
|
// Return nil as this list is invalid
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
list.Type = lit
|
||
|
|
||
|
tok, lit = p.scan()
|
||
|
|
||
|
// If token is not PUNCT or literal is not "]"
|
||
|
if tok != scanner.PUNCT || lit != "]" {
|
||
|
// Return nil as this list is invalid
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
parseLoop:
|
||
|
for {
|
||
|
// If end of file
|
||
|
if tok == scanner.EOF {
|
||
|
// Return whatever was parsed so far
|
||
|
return list
|
||
|
}
|
||
|
|
||
|
// Create new list item at level 0
|
||
|
item := ast.ListItem{Level: 0}
|
||
|
|
||
|
for {
|
||
|
// Scan token
|
||
|
tok, lit = p.scan()
|
||
|
|
||
|
// If end of file
|
||
|
if tok == scanner.EOF {
|
||
|
// Return whatever was parsed so far
|
||
|
return list
|
||
|
}
|
||
|
|
||
|
// If token is not punctuation or literal is not "."
|
||
|
if tok != scanner.PUNCT || lit != "." {
|
||
|
// Break out of loop as this is the end of level
|
||
|
break
|
||
|
}
|
||
|
|
||
|
// Increment item level
|
||
|
item.Level++
|
||
|
}
|
||
|
|
||
|
for tok != scanner.PUNCT && lit != "." {
|
||
|
// If token is WORD and literal is "=end"
|
||
|
if tok == scanner.WORD && lit == "=end" {
|
||
|
// Scan token
|
||
|
tok, lit = p.scan()
|
||
|
// If token is not PUNCT and literal is not "["
|
||
|
if tok != scanner.PUNCT && lit != "[" {
|
||
|
// Return nil as this is not a valid list
|
||
|
return nil
|
||
|
}
|
||
|
// Scan token
|
||
|
tok, lit = p.scan()
|
||
|
// If token is not PUNCT and literal is not "]"
|
||
|
if tok != scanner.PUNCT && lit != "]" {
|
||
|
// Return nil as this is not a valid list
|
||
|
return nil
|
||
|
}
|
||
|
// Add item to list
|
||
|
list.Items = append(list.Items, item)
|
||
|
// Stop parsing
|
||
|
break parseLoop
|
||
|
}
|
||
|
|
||
|
// If end of file
|
||
|
if tok == scanner.EOF {
|
||
|
// Return whatever was parsed so far
|
||
|
return list
|
||
|
}
|
||
|
|
||
|
// Unscan character as it will be required for para
|
||
|
p.unscan()
|
||
|
// Attempt to parse para until one newline encountered
|
||
|
para := p.parsePara(1)
|
||
|
if para == nil {
|
||
|
break
|
||
|
}
|
||
|
// Add para to item content
|
||
|
item.Content = append(item.Content, para)
|
||
|
|
||
|
// Scan token for next loop
|
||
|
tok, lit = p.scan()
|
||
|
|
||
|
// if end of line
|
||
|
if tok == scanner.EOL {
|
||
|
// Scan again
|
||
|
tok, lit = p.scan()
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// If token is part of level
|
||
|
if tok == scanner.PUNCT && lit == "." {
|
||
|
// Unscan for next level loop
|
||
|
p.unscan()
|
||
|
}
|
||
|
|
||
|
// If no content in item
|
||
|
if len(item.Content) == 0 {
|
||
|
// Continue to next item
|
||
|
continue
|
||
|
}
|
||
|
|
||
|
// Add item to list items
|
||
|
list.Items = append(list.Items, item)
|
||
|
}
|
||
|
|
||
|
// Return lists
|
||
|
return list
|
||
|
}
|