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. STATEMENTS -> STATEMENT STATEMENTS | . STATEMENT -> EXPRESSION eos | BLOCK . WORDOPS -> WORDOP WORDOPS | . EXPRESSION -> SETTER | GETTER | COMMAND. COMMAND -> WORDVALUE PARAMETERS. PARAMETERS -> PARAMETER PARAMETERS | . PARAMETER -> WORDVALUE | PARENTHESIS | GETTER | ARRARY | BLOCK . PARENTHESIS -> '(' EXPRESSION ')' . BLOCK -> '{' STATEMENTS '}' . WORDVALUE -> word | VALUE. VALUE -> string | integer | float | symbol. SETTER -> set word PARAMETERS . 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() return accepted } } return NoToken() } func (parser *Parser) ParseMany(kind AstKind, parent Ast, parsefunc func(*Parser) Ast) Ast { children := make([]Ast, 0) for sub := parsefunc(parser); sub != nil && !AstIsError(sub); sub = parsefunc(parser) { children = append(children, sub) } return NewAst(kind, parent, children, NoToken()) return ast } func (parser *Parser) NewAstError(message string) Ast { sv := StringValue(message + " at token " + parser.current.String()) 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 { ast := NewAst(astkind, nil, NoToken()) for _, parsefunc := range parsefuncs { sub := parsefunc(parser) if sub != nil { ast.AppendChild(sub) return ast } } return nil } func (parser *Parser) ParseRequireAny(astkind AstKind, parsefuncs ...(func(*Parser) Ast)) Ast { ast := parser.ParseAny(astkind, parsefuncs...) if ast == nil { err := parser.NewAstError("Unexpected token") return err } return ast } func (parser *Parser) ParseValue() Ast { value := parser.Accept(TokenKindInteger, TokenKindString, TokenKindBoolean, TokenKindFloat, TokenKindSymbol) if value.IsNone() { return nil } return NewAst(AstKindValue, nil, value) } func (parser *Parser) ParseWordValue() Ast { value := parser.Accept(TokenKindInteger, TokenKindString, TokenKindBoolean, TokenKindFloat, TokenKindSymbol, TokenKindType, TokenKindWord) if value.IsNone() { return nil } return NewAst(AstKindWordValue, nil, value) } func (parser *Parser) ParseArgument() Ast { return parser.ParseAny(AstKindArgument, (*Parser).ParseWordValue, (*Parser).ParseGet, (*Parser).ParseSet, (*Parser).ParseParenthesis, (*Parser).ParseList, (*Parser).ParseBlock) } func (parser *Parser) ParseArguments() Ast { return parser.ParseMany(AstKindArguments, (*Parser).ParseArgument) } func (parser *Parser) ParseList() Ast { op := parser.Accept(TokenKindOpenList) if op.IsNone() { return nil } ast := NewAst(AstKindList, nil, op) args := parser.ParseArguments() if AstIsError(args) { return args } if cp := parser.Accept(TokenKindCloseList); cp.IsNone() { return parser.NewAstError("expected closing brackets") } ast.AppendChild(args) return ast } func (parser *Parser) ParseParenthesis() Ast { op := parser.Accept(TokenKindOpenParen) if op.IsNone() { return nil } ast := NewAst(AstKindParenthesis, nil, op) expr := parser.ParseExpression() if expr == nil { return parser.NewAstError("expected expression") } if AstIsError(expr) { return expr } if cp := parser.Accept(TokenKindCloseParen); cp.IsNone() { return parser.NewAstError("expected closing parenthesis") } ast.AppendChild(expr) return ast } func (parser *Parser) ParseBlock() Ast { op := parser.Accept(TokenKindOpenBlock) if op.IsNone() { return nil } ast := NewAst(AstKindBlock, nil, op) stats := parser.ParseStatements() if stats == nil { return parser.NewAstError("expected expression") } if AstIsError(stats) { return stats } if cp := parser.Accept(TokenKindCloseBlock); cp.IsNone() { 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 { target := parser.Accept(TokenKindWord, TokenKindType, TokenKindSymbol) ast := NewAst(AstKindTarget, nil, target) if target.IsNone() { paren := parser.ParseParenthesis() if paren == nil { return parser.NewAstError("expected word, symbol or parenthesis") } ast.AppendChild(paren) } return ast } func (parser *Parser) ParseSet() Ast { set := parser.Accept(TokenKindSet) if set.IsNone() { return nil } ast := NewAst(AstKindSet, nil, set) target := parser.ParseTarget() ast.AppendChild(target) argument := parser.ParseArgument() if argument == nil { return parser.NewAstError("Expected argument to set") } ast.AppendChild(argument) return ast } func (parser *Parser) ParseGet() Ast { get := parser.Accept(TokenKindGet) if get.IsNone() { return nil } ast := NewAst(AstKindGet, nil, get) target := parser.ParseTarget() ast.AppendChild(target) return ast } func (parser *Parser) ParseCommand() Ast { word := parser.Accept(TokenKindWord, TokenKindType) if word.IsNone() { return nil } arguments := parser.ParseArguments() command := NewAst(AstKindCommand, nil, word) command.AppendChild(arguments) return command } func (parser *Parser) ParseExpression() Ast { exp := parser.ParseRequireAny(AstKindExpression, (*Parser).ParseSet, (*Parser).ParseGet, (*Parser).ParseCommand) return exp } func (parser *Parser) ParseEmptyStatement() Ast { eox := parser.Accept(TokenKindEOX) if eox.IsNone() { return nil } ast := NewAst(AstKindEnd, nil, eox) return ast } func (parser *Parser) ParseStatement() Ast { ast := parser.ParseAny(AstKindStatement, (*Parser).ParseBlock, (*Parser).ParseSet, (*Parser).ParseGet, (*Parser).ParseCommand, (*Parser).ParseParenthesis) if eox := parser.Accept(TokenKindEOX); eox.IsNone() { return parser.NewAstError("expected end of statement") } return ast } func (parser *Parser) ParseStatements() Ast { return parser.ParseMany(AstKindStatements, (*Parser).ParseStatement) } func (parser *Parser) ParseProgram() Ast { eof := parser.Accept(TokenKindEOF) aeof := NewAst(AstKindEnd, nil, eof) // be lenient with missing EOF for now... children := append(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 }