%{ #include "mooscript-parser-private.h" #include "mooscript-yacc.h" static MSNode * node_list_add (MSParser *parser, MSNodeList *list, MSNode *node) { if (!list) { list = _ms_node_list_new (); _ms_parser_add_node (parser, list); } if (!node) { MSValue *none = ms_value_none (); node = MS_NODE (_ms_node_value_new (none)); ms_value_unref (none); _ms_parser_add_node (parser, node); } _ms_node_list_add (list, node); return MS_NODE (list); } static MSNode * node_function (MSParser *parser, MSNode *func, MSNodeList *args) { MSNodeFunction *node; g_return_val_if_fail (func != NULL, NULL); g_return_val_if_fail (!args || MS_IS_NODE_LIST (args), NULL); node = _ms_node_function_new (func, args); _ms_parser_add_node (parser, node); return MS_NODE (node); } static MSNode * node_if_else (MSParser *parser, MSNode *condition, MSNode *then_, MSNodeList *elif_, MSNode *else_) { MSNodeIfElse *node; g_return_val_if_fail (condition && then_, NULL); node = _ms_node_if_else_new (condition, then_, elif_, else_); _ms_parser_add_node (parser, node); return MS_NODE (node); } static MSNode * node_condition (MSParser *parser, MSNode *condition, MSNode *then_) { MSNode *tuple; tuple = node_list_add (parser, NULL, condition); tuple = node_list_add (parser, MS_NODE_LIST (tuple), then_); return tuple; } static MSNode * node_while (MSParser *parser, MSCondType type, MSNode *cond, MSNode *what) { MSNodeWhile *loop; g_return_val_if_fail (cond != NULL, NULL); loop = _ms_node_while_new (type, cond, what); _ms_parser_add_node (parser, loop); return MS_NODE (loop); } static MSNode * node_for (MSParser *parser, MSNode *var, MSNode *list, MSNode *what) { MSNodeFor *loop; g_return_val_if_fail (var && list, NULL); loop = _ms_node_for_new (var, list, what); _ms_parser_add_node (parser, loop); return MS_NODE (loop); } static MSNode * node_var (MSParser *parser, const char *name) { MSNodeVar *node; node = _ms_node_var_new (name); _ms_parser_add_node (parser, node); return MS_NODE (node); } static MSNode * node_assignment (MSParser *parser, const char *name, MSNode *val) { MSNodeAssign *node; MSNode *var; g_return_val_if_fail (name && name[0], NULL); g_return_val_if_fail (val != NULL, NULL); var = node_var (parser, name); node = _ms_node_assign_new (MS_NODE_VAR (var), val); _ms_parser_add_node (parser, node); return MS_NODE (node); } static MSNode * node_binary_op (MSParser *parser, MSBinaryOp op, MSNode *lval, MSNode *rval) { MSNodeFunction *node; g_return_val_if_fail (lval && rval, NULL); node = _ms_node_binary_op_new (op, lval, rval); _ms_parser_add_node (parser, node); return MS_NODE (node); } static MSNode * node_unary_op (MSParser *parser, MSUnaryOp op, MSNode *val) { MSNodeFunction *node; g_return_val_if_fail (val != NULL, NULL); node = _ms_node_unary_op_new (op, val); _ms_parser_add_node (parser, node); return MS_NODE (node); } static MSNode * node_int (MSParser *parser, int n) { MSNodeValue *node; MSValue *value; value = ms_value_int (n); node = _ms_node_value_new (value); ms_value_unref (value); _ms_parser_add_node (parser, node); return MS_NODE (node); } static MSNode * node_string (MSParser *parser, const char *string) { MSNodeValue *node; MSValue *value; value = ms_value_string (string); node = _ms_node_value_new (value); ms_value_unref (value); _ms_parser_add_node (parser, node); return MS_NODE (node); } static MSNode * node_value_list (MSParser *parser, MSNodeList *list) { MSNodeValList *node; node = _ms_node_val_list_new (list); _ms_parser_add_node (parser, node); return MS_NODE (node); } static MSNode * node_value_range (MSParser *parser, MSNode *first, MSNode *last) { MSNodeValList *node; node = _ms_node_val_range_new (first, last); _ms_parser_add_node (parser, node); return MS_NODE (node); } static MSNode * node_get_item (MSParser *parser, MSNode *obj, MSNode *key) { MSNodeGetItem *node; node = _ms_node_get_item_new (obj, key); _ms_parser_add_node (parser, node); return MS_NODE (node); } static MSNode * node_set_item (MSParser *parser, MSNode *obj, MSNode *key, MSNode *val) { MSNodeSetItem *node; node = _ms_node_set_item_new (obj, key, val); _ms_parser_add_node (parser, node); return MS_NODE (node); } static MSNode * node_dict (MSParser *parser, MSNodeList *list) { MSNodeDict *node; node = _ms_node_dict_new (list); _ms_parser_add_node (parser, node); return MS_NODE (node); } static MSNode * node_dict_entry (MSParser *parser, const char *key, MSNode *val) { MSNodeDictEntry *node; node = _ms_node_dict_entry_new (key, val); _ms_parser_add_node (parser, node); return MS_NODE (node); } static MSNode * node_return (MSParser *parser, MSNode *val) { MSNodeReturn *node; node = _ms_node_return_new (val); _ms_parser_add_node (parser, node); return MS_NODE (node); } static MSNode * node_break (MSParser *parser) { MSNodeBreak *node; node = _ms_node_break_new (MS_BREAK_BREAK); _ms_parser_add_node (parser, node); return MS_NODE (node); } static MSNode * node_continue (MSParser *parser) { MSNodeBreak *node; node = _ms_node_break_new (MS_BREAK_CONTINUE); _ms_parser_add_node (parser, node); return MS_NODE (node); } static MSNode * node_env_var (MSParser *parser, MSNode *var, MSNode *deflt) { MSNodeEnvVar *node; node = _ms_node_env_var_new (var, deflt); _ms_parser_add_node (parser, node); return MS_NODE (node); } static MSNode * node_dict_elm (MSParser *parser, MSNode *dict, const char *key) { MSNodeDictElm *node; node = _ms_node_dict_elm_new (dict, key); _ms_parser_add_node (parser, node); return MS_NODE (node); } static MSNode * node_dict_assign (MSParser *parser, MSNode *dict, const char *key, MSNode *val) { MSNodeDictAssign *node; node = _ms_node_dict_assign_new (dict, key, val); _ms_parser_add_node (parser, node); return MS_NODE (node); } %} %name-prefix="_ms_script_yy" %error-verbose %lex-param {MSParser *parser} %parse-param {MSParser *parser} /* %expect 1 */ %union { int ival; const char *str; MSNode *node; } %token IDENTIFIER %token LITERAL %token VARIABLE %token NUMBER %type program stmt stmt_or_error %type if_stmt elif_block ternary loop assignment %type simple_expr compound_expr expr variable %type list_elms dict_elms dict_entry %token IF THEN ELSE ELIF FI %token WHILE DO OD FOR IN %token CONTINUE BREAK RETURN %token EQ NEQ LE GE %token AND OR NOT %token UMINUS %token TWODOTS %left '-' '+' %left '*' '/' %left '%' %left EQ NEQ '<' '>' GE LE %left OR %left AND %left NOT %left '#' %left UMINUS %% script: program { _ms_parser_set_top_node (parser, $1); } ; program: stmt_or_error { $$ = node_list_add (parser, NULL, $1); } | program stmt_or_error { $$ = node_list_add (parser, MS_NODE_LIST ($1), $2); } ; stmt_or_error: error ';' { $$ = NULL; } | stmt ';' { $$ = $1; } ; stmt: /* empty */ { $$ = NULL; } | expr | if_stmt | loop | assignment /* not an expr because otherwise 'var = var + 2' gets parsed as '(var = var) + 2'*/ | CONTINUE { $$ = node_continue (parser); } | BREAK { $$ = node_break (parser); } | RETURN { $$ = node_return (parser, NULL); } | RETURN expr { $$ = node_return (parser, $2); } ; loop: WHILE expr DO program OD { $$ = node_while (parser, MS_COND_BEFORE, $2, $4); } | DO program WHILE expr { $$ = node_while (parser, MS_COND_AFTER, $4, $2); } | FOR variable IN expr DO program OD { $$ = node_for (parser, $2, $4, $6); } ; if_stmt: IF expr THEN program FI { $$ = node_if_else (parser, $2, $4, NULL, NULL); } | IF expr THEN program ELSE program FI { $$ = node_if_else (parser, $2, $4, NULL, $6); } | IF expr THEN program elif_block FI { $$ = node_if_else (parser, $2, $4, MS_NODE_LIST ($5), NULL); } | IF expr THEN program elif_block ELSE program FI { $$ = node_if_else (parser, $2, $4, MS_NODE_LIST ($5), $7); } ; elif_block: ELIF expr THEN program { $$ = node_list_add (parser, NULL, node_condition (parser, $2, $4)); } | elif_block ELIF expr THEN program { $$ = node_list_add (parser, MS_NODE_LIST ($1), node_condition (parser, $3, $5)); } ; expr: simple_expr | compound_expr | ternary ; assignment: IDENTIFIER '=' expr { $$ = node_assignment (parser, $1, $3); } | simple_expr '[' expr ']' '=' expr { $$ = node_set_item (parser, $1, $3, $6); } | simple_expr '[' error ']' '=' expr { $$ = NULL; } | simple_expr '.' IDENTIFIER '=' expr { $$ = node_dict_assign (parser, $1, $3, $5); } ; ternary: simple_expr '?' simple_expr ':' simple_expr { $$ = node_if_else (parser, $1, $3, NULL, $5); } ; compound_expr: expr '+' expr { $$ = node_binary_op (parser, MS_OP_PLUS, $1, $3); } | expr '-' expr { $$ = node_binary_op (parser, MS_OP_MINUS, $1, $3); } | expr '/' expr { $$ = node_binary_op (parser, MS_OP_DIV, $1, $3); } | expr '*' expr { $$ = node_binary_op (parser, MS_OP_MULT, $1, $3); } | expr AND expr { $$ = node_binary_op (parser, MS_OP_AND, $1, $3); } | expr OR expr { $$ = node_binary_op (parser, MS_OP_OR, $1, $3); } | expr EQ expr { $$ = node_binary_op (parser, MS_OP_EQ, $1, $3); } | expr NEQ expr { $$ = node_binary_op (parser, MS_OP_NEQ, $1, $3); } | expr '<' expr { $$ = node_binary_op (parser, MS_OP_LT, $1, $3); } | expr '>' expr { $$ = node_binary_op (parser, MS_OP_GT, $1, $3); } | expr LE expr { $$ = node_binary_op (parser, MS_OP_LE, $1, $3); } | expr GE expr { $$ = node_binary_op (parser, MS_OP_GE, $1, $3); } | '-' simple_expr %prec UMINUS { $$ = node_unary_op (parser, MS_OP_UMINUS, $2); } | NOT simple_expr { $$ = node_unary_op (parser, MS_OP_NOT, $2); } | '#' simple_expr { $$ = node_unary_op (parser, MS_OP_LEN, $2); } | simple_expr '%' simple_expr { $$ = node_binary_op (parser, MS_OP_FORMAT, $1, $3); } | simple_expr IN simple_expr { $$ = node_binary_op (parser, MS_OP_IN, $1, $3); } ; simple_expr: NUMBER { $$ = node_int (parser, $1); } | LITERAL { $$ = node_string (parser, $1); } | variable | '(' stmt ')' { $$ = $2; } | '(' error ')' { $$ = NULL; } | '[' list_elms ']' { $$ = node_value_list (parser, MS_NODE_LIST ($2)); } | '[' error ']' { $$ = NULL; } | '{' dict_elms '}' { $$ = node_dict (parser, $2 ? MS_NODE_LIST ($2) : NULL); } | '{' error '}' { $$ = NULL; } | '[' expr TWODOTS expr ']' { $$ = node_value_range (parser, $2, $4); } | simple_expr '(' list_elms ')' { $$ = node_function (parser, $1, $3 ? MS_NODE_LIST ($3) : NULL); } | simple_expr '[' expr ']' { $$ = node_get_item (parser, $1, $3); } | simple_expr '.' IDENTIFIER { $$ = node_dict_elm (parser, $1, $3); } | '$' '(' stmt ')' { $$ = node_env_var (parser, $3, NULL); } | '$' '(' stmt ',' stmt ')' { $$ = node_env_var (parser, $3, $5); } | '$' IDENTIFIER { $$ = node_env_var (parser, node_string (parser, $2), NULL); } ; list_elms: /* empty */ { $$ = NULL; } | expr { $$ = node_list_add (parser, NULL, $1); } | list_elms ',' expr { $$ = node_list_add (parser, MS_NODE_LIST ($1), $3); } ; dict_elms: /* empty */ { $$ = NULL; } | dict_entry { $$ = node_list_add (parser, NULL, $1); } | dict_elms ',' dict_entry { $$ = node_list_add (parser, MS_NODE_LIST ($1), $3); } ; dict_entry: IDENTIFIER '=' expr { $$ = node_dict_entry (parser, $1, $3); } ; variable: IDENTIFIER { $$ = node_var (parser, $1); } ; %%