| 
									
										
										
										
											2013-01-08 06:24:26 +08:00
										 |  |  | package rules | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							|  |  |  | 	"errors" | 
					
						
							|  |  |  | 	"fmt" | 
					
						
							| 
									
										
										
										
											2013-01-11 08:17:37 +08:00
										 |  |  |         "github.com/matttproud/prometheus/rules/ast" | 
					
						
							| 
									
										
										
										
											2013-01-08 06:24:26 +08:00
										 |  |  | 	"io" | 
					
						
							|  |  |  | 	"os" | 
					
						
							|  |  |  | 	"strings" | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // NOTE: This parser is non-reentrant due to its dependence on global state.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // GoLex sadly needs these global variables for storing temporary token/parsing information.
 | 
					
						
							|  |  |  | var yylval *yySymType   // For storing extra token information, like the contents of a string.
 | 
					
						
							|  |  |  | var yyline int          // Line number within the current file or buffer.
 | 
					
						
							|  |  |  | var yypos int           // Character position within the current line.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type RulesLexer struct { | 
					
						
							| 
									
										
										
										
											2013-01-11 08:17:37 +08:00
										 |  |  | 	errors []string     // Errors encountered during parsing.
 | 
					
						
							|  |  |  |         startToken int      // Dummy token to simulate multiple start symbols (see below).
 | 
					
						
							|  |  |  |         parsedRules []*Rule // Parsed full rules.
 | 
					
						
							|  |  |  |         parsedExpr ast.Node // Parsed single expression.
 | 
					
						
							| 
									
										
										
										
											2013-01-08 06:24:26 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (lexer *RulesLexer) Lex(lval *yySymType) int { | 
					
						
							|  |  |  | 	yylval = lval | 
					
						
							| 
									
										
										
										
											2013-01-11 08:17:37 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |         // We simulate multiple start symbols for closely-related grammars via dummy tokens. See
 | 
					
						
							|  |  |  |         // http://www.gnu.org/software/bison/manual/html_node/Multiple-start_002dsymbols.html
 | 
					
						
							|  |  |  |         // Reason: we want to be able to parse lists of named rules as well as single expressions.
 | 
					
						
							|  |  |  |         if lexer.startToken != 0 { | 
					
						
							|  |  |  |                 startToken := lexer.startToken | 
					
						
							|  |  |  |                 lexer.startToken = 0 | 
					
						
							|  |  |  |                 return startToken | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	tokenType := yylex() | 
					
						
							|  |  |  | 	return tokenType | 
					
						
							| 
									
										
										
										
											2013-01-08 06:24:26 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (lexer *RulesLexer) Error(errorStr string) { | 
					
						
							|  |  |  | 	err := fmt.Sprintf("Error parsing rules at line %v, char %v: %v", yyline, yypos, errorStr) | 
					
						
							|  |  |  | 	lexer.errors = append(lexer.errors, err) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-01-11 08:17:37 +08:00
										 |  |  | func LoadFromReader(rulesReader io.Reader, singleExpr bool) (interface{}, error) { | 
					
						
							| 
									
										
										
										
											2013-01-08 06:24:26 +08:00
										 |  |  | 	yyin = rulesReader | 
					
						
							|  |  |  | 	yypos = 1 | 
					
						
							|  |  |  | 	yyline = 1 | 
					
						
							| 
									
										
										
										
											2013-01-12 09:35:40 +08:00
										 |  |  |         yydata = "" | 
					
						
							|  |  |  |         yytext = "" | 
					
						
							| 
									
										
										
										
											2013-01-08 06:24:26 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-01-11 08:17:37 +08:00
										 |  |  | 	lexer := &RulesLexer{ | 
					
						
							|  |  |  |                 startToken: START_RULES, | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if singleExpr { | 
					
						
							|  |  |  |                 lexer.startToken = START_EXPRESSION | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-01-08 06:24:26 +08:00
										 |  |  | 	ret := yyParse(lexer) | 
					
						
							|  |  |  | 	if ret != 0 && len(lexer.errors) == 0 { | 
					
						
							|  |  |  | 		lexer.Error("Unknown parser error") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if len(lexer.errors) > 0 { | 
					
						
							|  |  |  | 		err := errors.New(strings.Join(lexer.errors, "\n")) | 
					
						
							| 
									
										
										
										
											2013-01-11 08:17:37 +08:00
										 |  |  | 		return nil, err | 
					
						
							| 
									
										
										
										
											2013-01-08 06:24:26 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-01-11 08:17:37 +08:00
										 |  |  |         if singleExpr{ | 
					
						
							|  |  |  |                 return lexer.parsedExpr, nil | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |                 return lexer.parsedRules, nil | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         panic("") | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func LoadRulesFromReader(rulesReader io.Reader) ([]*Rule, error) { | 
					
						
							|  |  |  |         expr, err := LoadFromReader(rulesReader, false) | 
					
						
							|  |  |  |         if err != nil { | 
					
						
							|  |  |  |                 return nil, err | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         return expr.([]*Rule), err | 
					
						
							| 
									
										
										
										
											2013-01-08 06:24:26 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-01-11 08:17:37 +08:00
										 |  |  | func LoadRulesFromString(rulesString string) ([]*Rule, error) { | 
					
						
							| 
									
										
										
										
											2013-01-08 06:24:26 +08:00
										 |  |  | 	rulesReader := strings.NewReader(rulesString) | 
					
						
							| 
									
										
										
										
											2013-01-11 08:17:37 +08:00
										 |  |  | 	return LoadRulesFromReader(rulesReader) | 
					
						
							| 
									
										
										
										
											2013-01-08 06:24:26 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-01-11 08:17:37 +08:00
										 |  |  | func LoadRulesFromFile(fileName string) ([]*Rule, error) { | 
					
						
							| 
									
										
										
										
											2013-01-08 06:24:26 +08:00
										 |  |  | 	rulesReader, err := os.Open(fileName) | 
					
						
							| 
									
										
										
										
											2013-01-12 09:35:40 +08:00
										 |  |  |         defer rulesReader.Close() | 
					
						
							| 
									
										
										
										
											2013-01-08 06:24:26 +08:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return []*Rule{}, err | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2013-01-11 08:17:37 +08:00
										 |  |  | 	return LoadRulesFromReader(rulesReader) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func LoadExprFromReader(exprReader io.Reader) (ast.Node, error) { | 
					
						
							|  |  |  |         expr, err := LoadFromReader(exprReader, true) | 
					
						
							|  |  |  |         if err != nil { | 
					
						
							|  |  |  |                 return nil, err | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         return expr.(ast.Node), err | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func LoadExprFromString(exprString string) (ast.Node, error) { | 
					
						
							|  |  |  | 	exprReader := strings.NewReader(exprString) | 
					
						
							|  |  |  | 	return LoadExprFromReader(exprReader) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func LoadExprFromFile(fileName string) (ast.Node, error) { | 
					
						
							|  |  |  | 	exprReader, err := os.Open(fileName) | 
					
						
							| 
									
										
										
										
											2013-01-12 09:35:40 +08:00
										 |  |  |         defer exprReader.Close() | 
					
						
							| 
									
										
										
										
											2013-01-11 08:17:37 +08:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return LoadExprFromReader(exprReader) | 
					
						
							| 
									
										
										
										
											2013-01-08 06:24:26 +08:00
										 |  |  | } |