123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239 |
- package glisp
- import (
- "errors"
- "fmt"
- "strconv"
- )
- type Parser struct {
- lexer *Lexer
- env *Glisp
- }
- var UnexpectedEnd error = errors.New("Unexpected end of input")
- const SliceDefaultCap = 10
- func ParseList(parser *Parser) (Sexp, error) {
- lexer := parser.lexer
- tok, err := lexer.PeekNextToken()
- if err != nil {
- return SexpNull, err
- }
- if tok.typ == TokenEnd {
- _, _ = lexer.GetNextToken()
- return SexpEnd, UnexpectedEnd
- }
- if tok.typ == TokenRParen {
- _, _ = lexer.GetNextToken()
- return SexpNull, nil
- }
- var start SexpPair
- expr, err := ParseExpression(parser)
- if err != nil {
- return SexpNull, err
- }
- start.head = expr
- tok, err = lexer.PeekNextToken()
- if err != nil {
- return SexpNull, err
- }
- if tok.typ == TokenDot {
- // eat up the dot
- _, _ = lexer.GetNextToken()
- expr, err = ParseExpression(parser)
- if err != nil {
- return SexpNull, err
- }
- // eat up the end paren
- tok, err = lexer.GetNextToken()
- if err != nil {
- return SexpNull, err
- }
- // make sure it was actually an end paren
- if tok.typ != TokenRParen {
- return SexpNull, errors.New("extra value in dotted pair")
- }
- start.tail = expr
- return start, nil
- }
- expr, err = ParseList(parser)
- if err != nil {
- return start, err
- }
- start.tail = expr
- return start, nil
- }
- func ParseArray(parser *Parser) (Sexp, error) {
- lexer := parser.lexer
- arr := make([]Sexp, 0, SliceDefaultCap)
- for {
- tok, err := lexer.PeekNextToken()
- if err != nil {
- return SexpEnd, err
- }
- if tok.typ == TokenEnd {
- return SexpEnd, UnexpectedEnd
- }
- if tok.typ == TokenRSquare {
- // pop off the ]
- _, _ = lexer.GetNextToken()
- break
- }
- expr, err := ParseExpression(parser)
- if err != nil {
- return SexpNull, err
- }
- arr = append(arr, expr)
- }
- return SexpArray(arr), nil
- }
- func ParseHash(parser *Parser) (Sexp, error) {
- lexer := parser.lexer
- arr := make([]Sexp, 0, SliceDefaultCap)
- for {
- tok, err := lexer.PeekNextToken()
- if err != nil {
- return SexpEnd, err
- }
- if tok.typ == TokenEnd {
- return SexpEnd, UnexpectedEnd
- }
- if tok.typ == TokenRCurly {
- // pop off the }
- _, _ = lexer.GetNextToken()
- break
- }
- expr, err := ParseExpression(parser)
- if err != nil {
- return SexpNull, err
- }
- arr = append(arr, expr)
- }
- var list SexpPair
- list.head = parser.env.MakeSymbol("hash")
- list.tail = MakeList(arr)
- return list, nil
- }
- func ParseExpression(parser *Parser) (Sexp, error) {
- lexer := parser.lexer
- env := parser.env
- tok, err := lexer.GetNextToken()
- if err != nil {
- return SexpEnd, err
- }
- switch tok.typ {
- case TokenLParen:
- return ParseList(parser)
- case TokenLSquare:
- return ParseArray(parser)
- case TokenLCurly:
- return ParseHash(parser)
- case TokenQuote:
- expr, err := ParseExpression(parser)
- if err != nil {
- return SexpNull, err
- }
- return MakeList([]Sexp{env.MakeSymbol("quote"), expr}), nil
- case TokenBacktick:
- expr, err := ParseExpression(parser)
- if err != nil {
- return SexpNull, err
- }
- return MakeList([]Sexp{env.MakeSymbol("syntax-quote"), expr}), nil
- case TokenTilde:
- expr, err := ParseExpression(parser)
- if err != nil {
- return SexpNull, err
- }
- return MakeList([]Sexp{env.MakeSymbol("unquote"), expr}), nil
- case TokenTildeAt:
- expr, err := ParseExpression(parser)
- if err != nil {
- return SexpNull, err
- }
- return MakeList([]Sexp{env.MakeSymbol("unquote-splicing"), expr}), nil
- case TokenSymbol:
- return env.MakeSymbol(tok.str), nil
- case TokenBool:
- return SexpBool(tok.str == "true"), nil
- case TokenDecimal:
- i, err := strconv.ParseInt(tok.str, 10, SexpIntSize)
- if err != nil {
- return SexpNull, err
- }
- return SexpInt(i), nil
- case TokenHex:
- i, err := strconv.ParseInt(tok.str, 16, SexpIntSize)
- if err != nil {
- return SexpNull, err
- }
- return SexpInt(i), nil
- case TokenOct:
- i, err := strconv.ParseInt(tok.str, 8, SexpIntSize)
- if err != nil {
- return SexpNull, err
- }
- return SexpInt(i), nil
- case TokenBinary:
- i, err := strconv.ParseInt(tok.str, 2, SexpIntSize)
- if err != nil {
- return SexpNull, err
- }
- return SexpInt(i), nil
- case TokenChar:
- return SexpChar(tok.str[0]), nil
- case TokenString:
- return SexpStr(tok.str), nil
- case TokenFloat:
- f, err := strconv.ParseFloat(tok.str, SexpFloatSize)
- if err != nil {
- return SexpNull, err
- }
- return SexpFloat(f), nil
- case TokenEnd:
- return SexpEnd, nil
- }
- return SexpNull, errors.New(fmt.Sprint("Invalid syntax, didn't know what to do with ", tok.typ, " ", tok))
- }
- func ParseTokens(env *Glisp, lexer *Lexer) ([]Sexp, error) {
- expressions := make([]Sexp, 0, SliceDefaultCap)
- parser := Parser{lexer, env}
- for {
- expr, err := ParseExpression(&parser)
- if err != nil {
- return expressions, err
- }
- if expr == SexpEnd {
- break
- }
- expressions = append(expressions, expr)
- }
- return expressions, nil
- }
|