amu/parser/list.go

146 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() *ast.List {
// Create new list
list := &ast.List{}
tok, lit := p.scan()
// 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
}