package muesli import ( _ "bufio" _ "bytes" _ "errors" "fmt" _ "io" _ "os" _ "reflect" _ "runtime" _ "strings" _ "unicode" // "gitlab.com/beoran/woe/graphviz" // _ "gitlab.com/beoran/woe/monolog" ) /* Grammar: Desrired syntax (verified LL(1) on smlweb.cpsc.ucalgary.ca) PROGRAM -> STATEMENTS. CLOSED -> BLOCK | LIST | PARENTHESIS . STATEMENTS -> STATEMENT STATEMENTS | . STATEMENT -> CLOSED | EXPRESSION eos | eos . COMMAND -> word PARAMETERS. PARAMETERS -> PARAMETER PARAMETERS | . PARAMETER -> WORDVALUE | GETTER | SETTER | CLOSED . EXPRESSION -> COMMAND | GETTER | SETTER | VALUE. PARENTHESIS -> closeparen EXPRESSION openparen . BLOCK -> openblock STATEMENTS closeblock . LIST -> openlist PARAMETERS closelist . VALUE -> string | int | float | symbol | type . WORDVALUE -> word | VALUE. SETTER -> set word PARAMETER . GETTER -> get word . * * program -> statements * statements -> statement+ * statement -> get / set / command * */ type Parser struct { Lexer *Lexer current Token LoggerWrapper } func (parser *Parser) SetLogger(logger Logger) { parser.LoggerWrapper = LoggerWrapper{logger} } func (parser *Parser) Advance() { token := parser.Lexer.Lex() parser.current = token parser.LogDebug("Next token: %s\n", token.String()) } /* Looks at the current token and advances the lexer if the token is of any of the token kinds given in kinds. In this case it will return the accepted token and advance the parser. Otherwise, if no token kind matches, the lexer does not advance and the current token remains the same, except if that was nil.*/ func (parser *Parser) Accept(kinds ...TokenKind) Token { if parser.current.IsNone() { parser.Advance() } for _, kind := range kinds { if kind == parser.current.TokenKind { accepted := parser.current parser.Advance() parser.LogDebug("Accept: Accepted token: %s\n", accepted.String()) return accepted } } if parser.current.TokenKind == TokenKindEOF { parser.LogDebug("Unexpected EOF\n") return parser.Lexer.MakeErrorfToken("Unexpected EOF in Accept") } parser.LogDebug("Accept: No Token: no %s in %v.", parser.current.TokenKind, kinds) return NoToken() } func (parser *Parser) ParseMany(kind AstKind, parent *Ast, parsefunc func(*Parser) *Ast) *Ast { children := EmptyAstArray() for sub := parsefunc(parser); parser.current.TokenKind != TokenKindEOF && !sub.IsNone() && !sub.IsError(); sub = parsefunc(parser) { children = append(children, sub) } if kind == AstKindFlatten { if parent == nil { panic("Why nil?") } parent.AppendChildren(children...) return parent } else { return NewAst(kind, parent, children, NoToken()) } } func (parser *Parser) NewAstError(message string, args ...interface{}) *Ast { sv := StringValue(fmt.Sprintf(message+" at token "+parser.current.String(), args)) pos := parser.current.Position tok := NewToken(TokenKindError, sv, pos) return NewAst(AstKindError, nil, EmptyAstArray(), tok) } func (parser *Parser) ParseAny(astkind AstKind, parsefuncs ...(func(*Parser) *Ast)) *Ast { var ast * Ast if astkind != AstKindFlatten { ast = NewEmptyAst(astkind) } for _, parsefunc := range parsefuncs { parser.LogDebug("ParseAny: %s: trying: %s", astkind, GetFunctionName(parsefunc)) sub := parsefunc(parser) if !sub.IsNone() { if astkind == AstKindFlatten { return sub } else if sub.IsFlatten() { return ast } else { ast.AppendChild(sub) } return ast } } return NewAstNone() } func (parser *Parser) ParseRequireAny(astkind AstKind, parsefuncs ...(func(*Parser) *Ast)) *Ast { ast := parser.ParseAny(astkind, parsefuncs...) if ast.IsNone() { err := parser.NewAstError("Unexpected token in %v", parsefuncs) return err } return ast } // Also handles none or error vales of the token func (parser *Parser) NewAst(kind AstKind, parent * Ast, children []*Ast, value Token) *Ast{ if value.IsNone() { return NewAstNone() } if value.IsError() { return NewAst(AstKindError, parent, children, value) } return NewAst(kind, parent, children, value) } func (parser *Parser) ParseValue() *Ast { parser.LogDebug("ParseValue: %s\n", parser.current.String()) value := parser.Accept(TokenKindInteger, TokenKindString, TokenKindBoolean, TokenKindNil, TokenKindFloat, TokenKindSymbol) return parser.NewAst(AstKindValue, nil, EmptyAstArray(), value) } func (parser *Parser) ParseWordValue() *Ast { parser.LogDebug("ParseWordValue: %s\n", parser.current.String()) value := parser.Accept(TokenKindInteger, TokenKindString, TokenKindBoolean, TokenKindNil, TokenKindFloat, TokenKindSymbol, TokenKindType, TokenKindWord) return parser.NewAst(AstKindWordValue, nil, EmptyAstArray(), value) } func (parser *Parser) ParseArgument() *Ast { parser.LogDebug("ParseArgument: %s\n", parser.current.String()) return parser.ParseAny(AstKindArgument, (*Parser).ParseGet, (*Parser).ParseSet, (*Parser).ParseClosed, (*Parser).ParseWordValue) } func (parser *Parser) ParseArguments() *Ast { parser.LogDebug("ParseArgument: %s\n", parser.current.String()) return parser.ParseMany(AstKindArguments, nil, (*Parser).ParseArgument) } func (parser *Parser) ParseList() *Ast { parser.LogDebug("ParseList: %s\n", parser.current.String()) op := parser.Accept(TokenKindOpenList) if op.IsNone() { return NewAstNone() } if op.IsError() { return parser.NewAstError("Unexpected value.") } ast := NewAstWithToken(AstKindList, op) args := parser.ParseArguments() if AstIsError(args) { return args } if cp := parser.Accept(TokenKindCloseList); cp.IsNone() || cp.IsError() { return parser.NewAstError("expected closing brackets") } ast.AppendChild(args) return ast } func (parser *Parser) ParseParenthesis() *Ast { parser.LogDebug("ParseParenthesis: %s\n", parser.current.String()) op := parser.Accept(TokenKindOpenParen) if op.IsNone() { return NewAstNone() } if op.IsError() { return parser.NewAstError("Unexpected value.") } ast := NewAstWithToken(AstKindParenthesis, op) expr := parser.ParseExpression() if expr.IsNone() { return parser.NewAstError("expected expression") } if AstIsError(expr) { return expr } if cp := parser.Accept(TokenKindCloseParen); cp.IsNone() || cp.IsError() { return parser.NewAstError("expected closing parenthesis") } ast.AppendChild(expr) return ast } func (parser *Parser) ParseBlock() *Ast { parser.LogDebug("ParseBlock: %s\n", parser.current.String()) op := parser.Accept(TokenKindOpenBlock) if op.IsNone() { return NewAstNone() } if op.IsError() { return parser.NewAstError("Unexpected value.") } ast := NewAstWithToken(AstKindBlock, op) stats := parser.ParseStatements() if stats.IsNone() { return parser.NewAstError("expected expression") } if AstIsError(stats) { return stats } if cp := parser.Accept(TokenKindCloseBlock); cp.IsNone() || cp.IsError() { return parser.NewAstError("expected closing block") } ast.AppendChild(stats) return ast } /* Parses the target of a set or get expression */ func (parser *Parser) ParseTarget() *Ast { parser.LogDebug("ParseTarget: %s\n", parser.current.String()) target := parser.Accept(TokenKindWord, TokenKindType, TokenKindSymbol) ast := NewAstWithToken(AstKindTarget, target) if target.IsNone() { paren := parser.ParseParenthesis() if paren.IsNone() { return parser.NewAstError("expected word, symbol or parenthesis") } ast.AppendChild(paren) } return ast } func (parser *Parser) ParseSet() *Ast { parser.LogDebug("ParseSet: %s\n", parser.current.String()) set := parser.Accept(TokenKindSet) if set.IsNone() { return NewAstNone() } ast := NewAstWithToken(AstKindSet, set) target := parser.ParseTarget() ast.AppendChild(target) argument := parser.ParseArgument() if argument.IsNone() { return parser.NewAstError("Expected argument to set") } ast.AppendChild(argument) return ast } func (parser *Parser) ParseGet() *Ast { parser.LogDebug("ParseGet: %s\n", parser.current.String()) get := parser.Accept(TokenKindGet) if get.IsNone() { return NewAstNone() } ast := NewAstWithToken(AstKindGet, get) target := parser.ParseTarget() ast.AppendChild(target) return ast } func (parser *Parser) ParseCommand() *Ast { parser.LogDebug("ParseCommand: %s\n", parser.current.String()) word := parser.Accept(TokenKindWord, TokenKindType) if word.IsNone() { return NewAstNone() } arguments := parser.ParseArguments() command := NewAstWithToken(AstKindCommand, word) command.AppendChild(arguments) return command } func (parser *Parser) ParseClosed() *Ast { parser.LogDebug("ParseClosed: %s\n", parser.current.String()) exp := parser.ParseAny(AstKindClosed, (*Parser).ParseParenthesis, (*Parser).ParseBlock, (*Parser).ParseList) return exp } func (parser *Parser) ParseExpression() *Ast { parser.LogDebug("ParseExpression: %s\n", parser.current.String()) exp := parser.ParseRequireAny(AstKindExpression, (*Parser).ParseCommand, (*Parser).ParseSet, (*Parser).ParseGet, (*Parser).ParseValue ) return exp } func (parser *Parser) ParseExpressionStatement() *Ast { parser.LogDebug("ParseExpressionStatement: %s\n", parser.current.String()) expr := parser.ParseExpression() if expr.IsNone() { return NewAstNone() } if eox := parser.Accept(TokenKindEOX); eox.IsNone() { return parser.NewAstError("expected end of statement") } return NewAstNone() } func (parser *Parser) ParseEmptyStatement() *Ast { parser.LogDebug("ParseEmptyStatement: %s\n", parser.current.String()) if eox := parser.Accept(TokenKindEOX); eox.IsNone() { return parser.NewAstError("expected end of statement") } return NewAstWithToken(AstKindStatement, parser.current) } func (parser *Parser) ParseStatement() *Ast { parser.LogDebug("ParseStatement: %s\n", parser.current.String()) ast := parser.ParseAny(AstKindStatement, (*Parser).ParseClosed, (*Parser).ParseExpressionStatement, (*Parser).ParseEmptyStatement) return ast } func (parser *Parser) ParseStatements() *Ast { parser.LogDebug("ParseStatements: %s\n", parser.current.String()) return parser.ParseMany(AstKindStatements, nil, (*Parser).ParseStatement) } func (parser *Parser) ParseProgram() *Ast { parser.LogDebug("ParseProgram: %s\n", parser.current.String()) stats := parser.ParseStatements() // Be lenient with missing EOF for now... eof := parser.Accept(TokenKindEOF) aeof := NewAstWithToken(AstKindEnd, eof) if eof.IsNone() { aeof = parser.NewAstError("Expceted EOF, have: %s", parser.current.String()) } children := []*Ast{stats, aeof} return NewAst(AstKindProgram, nil, children, NoToken()) } func (parser *Parser) Parse() *Ast { ast := parser.ParseProgram() return ast } func NewParser(lexer *Lexer) *Parser { parser := &Parser{lexer, NoToken(), LoggerWrapper{nil}} return parser } func NewParserFromString(input string) *Parser { lexer := NewLexerFromString(input) return NewParser(lexer) } func NewParserFromFilename(filename string) (*Parser, error) { lexer, err := NewLexerFromFilename(filename) if err != nil { return nil, err } return NewParser(lexer), nil }