2017-07-14 02:18:23 +02:00
|
|
|
package expressions
|
2017-06-25 18:36:28 +02:00
|
|
|
|
|
|
|
import "strconv"
|
|
|
|
|
2017-06-25 22:21:31 +02:00
|
|
|
%%{
|
|
|
|
machine expression;
|
|
|
|
write data;
|
|
|
|
access lex.;
|
|
|
|
variable p lex.p;
|
|
|
|
variable pe lex.pe;
|
|
|
|
}%%
|
2017-06-25 18:36:28 +02:00
|
|
|
|
2017-06-25 22:21:31 +02:00
|
|
|
type lexer struct {
|
2017-07-13 15:55:36 +02:00
|
|
|
parseValue
|
2017-06-25 22:21:31 +02:00
|
|
|
data []byte
|
|
|
|
p, pe, cs int
|
|
|
|
ts, te, act int
|
|
|
|
}
|
|
|
|
|
2017-06-26 04:00:36 +02:00
|
|
|
func (l* lexer) token() string {
|
|
|
|
return string(l.data[l.ts:l.te])
|
|
|
|
}
|
|
|
|
|
2017-06-25 22:21:31 +02:00
|
|
|
func newLexer(data []byte) *lexer {
|
|
|
|
lex := &lexer{
|
|
|
|
data: data,
|
|
|
|
pe: len(data),
|
|
|
|
}
|
|
|
|
%% write init;
|
|
|
|
return lex
|
|
|
|
}
|
|
|
|
|
|
|
|
func (lex *lexer) Lex(out *yySymType) int {
|
|
|
|
eof := lex.pe
|
|
|
|
tok := 0
|
2017-06-25 18:36:28 +02:00
|
|
|
|
|
|
|
%%{
|
2017-06-26 02:20:58 +02:00
|
|
|
action Bool {
|
|
|
|
tok = LITERAL
|
2017-06-26 04:00:36 +02:00
|
|
|
out.val = lex.token() == "true"
|
2017-06-26 02:47:31 +02:00
|
|
|
fbreak;
|
2017-06-26 02:20:58 +02:00
|
|
|
}
|
2017-07-07 14:09:42 +02:00
|
|
|
action Identifier {
|
2017-06-25 22:21:31 +02:00
|
|
|
tok = IDENTIFIER
|
2017-06-26 04:00:36 +02:00
|
|
|
out.name = lex.token()
|
2017-06-25 22:21:31 +02:00
|
|
|
fbreak;
|
|
|
|
}
|
2017-06-26 13:50:53 +02:00
|
|
|
action Int {
|
|
|
|
tok = LITERAL
|
|
|
|
n, err := strconv.ParseInt(lex.token(), 10, 64)
|
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
2017-06-26 14:23:50 +02:00
|
|
|
out.val = int(n)
|
2017-06-26 13:50:53 +02:00
|
|
|
fbreak;
|
|
|
|
}
|
|
|
|
action Float {
|
2017-06-26 02:20:58 +02:00
|
|
|
tok = LITERAL
|
2017-06-26 04:00:36 +02:00
|
|
|
n, err := strconv.ParseFloat(lex.token(), 64)
|
2017-06-25 22:21:31 +02:00
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
2017-06-26 02:47:31 +02:00
|
|
|
out.val = n
|
2017-06-25 22:21:31 +02:00
|
|
|
fbreak;
|
|
|
|
}
|
2017-06-26 18:51:56 +02:00
|
|
|
action String {
|
|
|
|
tok = LITERAL
|
|
|
|
// TODO unescape \x
|
|
|
|
out.val = string(lex.data[lex.ts+1:lex.te-1])
|
|
|
|
fbreak;
|
|
|
|
}
|
2017-06-26 04:00:36 +02:00
|
|
|
action Relation { tok = RELATION; out.name = lex.token(); fbreak; }
|
2017-06-25 22:21:31 +02:00
|
|
|
|
2017-07-07 17:55:41 +02:00
|
|
|
identifier = (alpha | '_') . (alnum | '_' | '-')* '?'? ;
|
2017-07-16 18:54:20 +02:00
|
|
|
# TODO is this the form for a property? (in which case can share w/ identifier)
|
|
|
|
property = '.' (alpha | '_') . (alnum | '_' | '-')* '?' ? ;
|
2017-06-26 18:51:56 +02:00
|
|
|
int = '-'? digit+ ;
|
2017-07-16 18:54:20 +02:00
|
|
|
float = '-'? digit+ ('.' digit+)? ;
|
2017-06-26 18:51:56 +02:00
|
|
|
string = '"' (any - '"')* '"' | "'" (any - "'")* "'" ; # TODO escapes
|
2017-06-25 22:21:31 +02:00
|
|
|
|
|
|
|
main := |*
|
2017-07-13 15:12:02 +02:00
|
|
|
# statement selectors, should match constants in parser.go
|
2017-07-12 20:25:41 +02:00
|
|
|
"%assign " => { tok = ASSIGN; fbreak; };
|
2017-07-13 17:07:45 +02:00
|
|
|
"{%cycle " => { tok = CYCLE; fbreak; };
|
2017-07-13 17:59:11 +02:00
|
|
|
"%loop " => { tok = LOOP; fbreak; };
|
|
|
|
"{%when " => { tok = WHEN; fbreak; };
|
2017-07-13 15:12:02 +02:00
|
|
|
|
|
|
|
# literals
|
2017-06-26 18:51:56 +02:00
|
|
|
int => Int;
|
2017-06-26 13:50:53 +02:00
|
|
|
float => Float;
|
2017-06-26 18:51:56 +02:00
|
|
|
string => String;
|
2017-07-13 15:12:02 +02:00
|
|
|
|
|
|
|
# constants
|
2017-06-26 02:20:58 +02:00
|
|
|
("true" | "false") => Bool;
|
2017-07-07 14:09:42 +02:00
|
|
|
"nil" => { tok = LITERAL; out.val = nil; fbreak; };
|
2017-07-13 15:12:02 +02:00
|
|
|
|
|
|
|
# relations
|
2017-06-26 15:06:55 +02:00
|
|
|
"==" => { tok = EQ; fbreak; };
|
2017-06-27 23:54:24 +02:00
|
|
|
"!=" => { tok = NEQ; fbreak; };
|
2017-06-28 23:18:48 +02:00
|
|
|
">=" => { tok = GE; fbreak; };
|
|
|
|
"<=" => { tok = LE; fbreak; };
|
2017-06-27 23:54:24 +02:00
|
|
|
"and" => { tok = AND; fbreak; };
|
|
|
|
"or" => { tok = OR; fbreak; };
|
|
|
|
"contains" => { tok = CONTAINS; fbreak; };
|
2017-07-13 15:12:02 +02:00
|
|
|
|
|
|
|
# keywords
|
2017-06-27 19:18:01 +02:00
|
|
|
"in" => { tok = IN; fbreak; };
|
2017-07-16 18:54:20 +02:00
|
|
|
".." => { tok = DOTDOT; fbreak; };
|
2017-07-13 15:12:02 +02:00
|
|
|
|
2017-07-07 14:09:42 +02:00
|
|
|
identifier ':' => { tok = KEYWORD; out.name = string(lex.data[lex.ts:lex.te-1]); fbreak; };
|
|
|
|
identifier => Identifier;
|
|
|
|
property => { tok = PROPERTY; out.name = string(lex.data[lex.ts+1:lex.te]); fbreak; };
|
2017-07-13 15:12:02 +02:00
|
|
|
|
2017-06-25 22:21:31 +02:00
|
|
|
space+;
|
2017-06-26 15:06:55 +02:00
|
|
|
any => { tok = int(lex.data[lex.ts]); fbreak; };
|
2017-06-25 22:21:31 +02:00
|
|
|
*|;
|
|
|
|
|
2017-06-25 18:36:28 +02:00
|
|
|
write exec;
|
2017-06-25 22:21:31 +02:00
|
|
|
}%%
|
2017-06-25 18:36:28 +02:00
|
|
|
|
2017-06-25 22:21:31 +02:00
|
|
|
return tok
|
2017-06-25 18:36:28 +02:00
|
|
|
}
|
|
|
|
|
2017-06-25 22:21:31 +02:00
|
|
|
func (lex *lexer) Error(e string) {
|
2017-07-02 13:51:24 +02:00
|
|
|
// fmt.Println("scan error:", e)
|
|
|
|
}
|