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 | VALUE. COMMAND -> WORDVALUE PARAMETERS. PARAMETERS -> PARAMETER PARAMETERS | . PARAMETER -> WORDVALUE | PARENTHESIS | GETTER | ARRARY | BLOCK . PARENTHESIS -> '(' EXPRESSION ')' . BLOCK -> '{' STATEMENTS '}' . WORDVALUE -> word | VALUE. VALUE -> string | integer | float | symbol | boolean | nil. 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.IsNone() && !sub.IsError(); sub = parsefunc(parser) { children = append(children, sub) } 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 { ast := NewEmptyAst(astkind) for _, parsefunc := range parsefuncs { parser.LogDebug("ParseAny: trying: %s", GetFunctionName(parsefunc)) sub := parsefunc(parser) if !sub.IsNone() { 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 } func (parser *Parser) ParseValue() Ast { value := parser.Accept(TokenKindInteger, TokenKindString, TokenKindBoolean, TokenKindNil, TokenKindFloat, TokenKindSymbol) if value.IsNone() { return NewAstNone() } return NewAst(AstKindValue, nil, EmptyAstArray(), value) } func (parser *Parser) ParseWordValue() Ast { value := parser.Accept(TokenKindInteger, TokenKindString, TokenKindBoolean, TokenKindFloat, TokenKindSymbol, TokenKindType, TokenKindWord) if value.IsNone() { return NewAstNone() } return NewAst(AstKindWordValue, nil, EmptyAstArray(), 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, nil, (*Parser).ParseArgument) } func (parser *Parser) ParseList() Ast { op := parser.Accept(TokenKindOpenList) if op.IsNone() { return NewAstNone() } ast := NewAstWithToken(AstKindList, 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 NewAstNone() } 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() { return parser.NewAstError("expected closing parenthesis") } ast.AppendChild(expr) return ast } func (parser *Parser) ParseBlock() Ast { op := parser.Accept(TokenKindOpenBlock) if op.IsNone() { return NewAstNone() } 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() { 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 := 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 { 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 { 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 { 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) ParseExpression() Ast { exp := parser.ParseRequireAny(AstKindExpression, (*Parser).ParseSet, (*Parser).ParseGet, (*Parser).ParseCommand, (*Parser).ParseValue ) return exp } func (parser *Parser) ParseEmptyStatement() Ast { eox := parser.Accept(TokenKindEOX) if eox.IsNone() { return NewAstNone() } ast := NewAstWithToken(AstKindEnd, eox) return ast } func (parser *Parser) ParseStatement() Ast { ast := parser.ParseRequireAny(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, nil, (*Parser).ParseStatement) } func (parser *Parser) ParseProgram() Ast { eof := parser.Accept(TokenKindEOF) aeof := NewAstWithToken(AstKindEnd, eof) stats := parser.ParseStatements() // Be lenient with missing EOF for now... 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 }