1 Subject: typeof language support
3 This is a proposal for solving the variable existence checking problem.
5 The typeof macro subroutine in Thorsten Haudes Patch collection
6 changes the semantics of the macro language to far into the unusable,
7 because it allows NO_TAG variables everywhere.
9 This approach only changes the semantics in one case: if a function
10 retrns nothing (i.e. NO_TAG) this can be assign to a variable.
12 My trick is to switch the interpreter into a "typeof-mode" where it is
13 allowed to pass the value of a symbol with NO_TAG onto the stack.
15 The syntax is currently limited to check only the type of a symbol.
16 But IMHO this is not a limitation. With this you can check the type of
17 a variable and also the return type of a function, by assigning it to
18 a variable first. To assign the return value to a variable first is
19 not a limitation, else you must evaluate the function twice if you
20 need the return value.
22 For thinks like type(array[key]) we have already the in syntax, which
23 should suffice for this.
27 source/highlightData.c | 2 -
28 source/interpret.c | 74 ++++++++++++++++++++++++++++++++++++++++---------
30 source/parse.y | 10 +++++-
31 4 files changed, 72 insertions(+), 16 deletions(-)
33 diff --quilt old/source/interpret.c new/source/interpret.c
34 --- old/source/interpret.c
35 +++ new/source/interpret.c
36 @@ -106,10 +106,13 @@ static void arrayDisposeNode(rbTreeNode
37 static SparseArrayEntry *allocateSparseArrayEntry(void);
39 /* for internal use only */
40 static int doFreeProg(void);
42 +/* is the intepreter in the special typeof() mode? */
43 +static int inTypeOfMode;
45 static const char *tagToStr(enum typeTags tag);
47 /*#define DEBUG_ASSEMBLY*/
48 /*#define DEBUG_STACK*/
50 @@ -1394,11 +1397,11 @@ static int pushSymVal(void)
52 return execError(errMsg, s->name);
55 return execError("reading non-variable: %s", s->name);
56 - if (symVal.tag == NO_TAG) {
57 + if (symVal.tag == NO_TAG && !inTypeOfMode) {
58 return execError("variable not set: %s", s->name);
63 @@ -1522,11 +1525,11 @@ static int pushArraySymVal(void)
64 if (initEmpty && dataPtr->tag == NO_TAG) {
65 dataPtr->tag = ARRAY_TAG;
66 dataPtr->val.arrayPtr = ArrayNew();
69 - if (dataPtr->tag == NO_TAG) {
70 + if (dataPtr->tag == NO_TAG && !inTypeOfMode) {
71 return execError("variable not set: %s", sym->name);
76 @@ -2489,13 +2492,10 @@ static int callSubroutineFromSymbol(Symb
77 PreemptRequest = False;
78 /* NB nArgs < 0 implies presence of named args array in last position */
79 if (!sym->value.val.subr(FocusWindow, StackP, nArgs, &result, &errMsg))
80 return execError(errMsg, sym->name);
81 if (PC->func == fetchRetVal) {
82 - if (result.tag == NO_TAG) {
83 - return execError("%s does not return a value", sym->name);
88 return PreemptRequest ? STAT_PREEMPT : STAT_OK;
90 @@ -2588,11 +2588,12 @@ static int callSubroutineFromSymbol(Symb
91 PreemptRequest = False;
92 sym->value.val.xtproc(FocusWindow->lastFocus,
93 (XEvent *)&key_event, argList, &numArgs);
94 XtFree((char *)argList);
95 if (PC->func == fetchRetVal) {
96 - return execError("%s does not return a value", sym->name);
100 return PreemptRequest ? STAT_PREEMPT : STAT_OK;
103 /* Calling a non subroutine symbol */
104 @@ -2824,18 +2825,16 @@ static int returnValOrNone(int valOnStac
109 } else if (PC->func == fetchRetVal) {
116 - "using return value of %s which does not return a value",
117 - ((PC-2)->sym->name));
125 /* NULL return PC indicates end of program */
126 return PC == NULL ? STAT_DONE : STAT_OK;
128 @@ -3579,10 +3578,59 @@ static int deleteArrayElement(void)
129 return(execError("attempt to delete from non-array", NULL));
134 +static int typeOfIn(void)
136 + if (inTypeOfMode) {
137 + return(execError("I'm already in typeof-mode", NULL));
145 +static int typeOfOut(void)
150 + if (!inTypeOfMode) {
151 + return(execError("I'm not in typeof-mode", NULL));
158 + retVal.tag = STRING_TAG;
161 + retVal.val.str.rep = PERM_ALLOC_STR("UNDEFINED");
164 + retVal.val.str.rep = PERM_ALLOC_STR("INTEGER");
167 + retVal.val.str.rep = PERM_ALLOC_STR("STRING");
170 + retVal.val.str.rep = PERM_ALLOC_STR("ARRAY");
173 + retVal.val.str.len = strlen(retVal.val.str.rep);
175 + if (PC->func == fetchRetVal) {
183 static int doFreeProg(void)
188 diff --quilt old/source/parse.y new/source/parse.y
189 --- old/source/parse.y
190 +++ new/source/parse.y
191 @@ -92,11 +92,11 @@ static int nextSymIsField = 0;
192 AccumulatorData *acc;
194 %token <sym> STRING SYMBOL FIELD
196 %token DELETE ARG_LOOKUP
197 -%token IF WHILE DO ELSE FOR BREAK CONTINUE RETURN
198 +%token IF WHILE DO ELSE FOR BREAK CONTINUE RETURN TYPEOF
200 %type <num> arrlist arrentry
201 %type <num> arglistopt arglist catlist fnarglsopt fnarglist fnarg
202 %type <inst> cond comastmts comastmtlst for while do else and or arrayexpr mark
204 @@ -347,11 +347,16 @@ arglist: blank expr bla
205 catlist: numexpr %prec CONCAT { $$ = 1; }
206 | catlist numexpr %prec CONCAT { $$ = $1 + 1; }
209 /* function call and its argument lists */
210 -funccall: SYMBOL '(' fnarglsopt ')' {
211 +funccall: TYPEOF '(' {
212 + ADD_OP(OP_TYPEOF_IN);
214 + ADD_OP(OP_TYPEOF_OUT);
216 + | SYMBOL '(' fnarglsopt ')' {
217 ADD_OP(OP_SUBR_CALL);
218 ADD_SYM(PromoteToGlobal($1)); ADD_IMMED($3);
220 | SYMBOL '(' blank '=' blank expr blank ')' {
221 /* a single array replaces the argument list */
222 @@ -705,10 +710,11 @@ static int yylex(void)
223 if (!strcmp(symName, "return")) return RETURN;
224 if (!strcmp(symName, "in")) return IN;
225 if (!strcmp(symName, "$args")) return ARG_LOOKUP;
226 if (!strcmp(symName, "delete") && follow_non_whitespace('(', SYMBOL, DELETE) == DELETE) return DELETE;
227 if (!strcmp(symName, "define")) return DEFINE;
228 + if (!strcmp(symName, "typeof")) return TYPEOF;
229 if (nextSymIsField) {
231 yylval.sym = InstallStringConstSymbol(symName);
234 diff --quilt old/source/highlightData.c new/source/highlightData.c
235 --- old/source/highlightData.c
236 +++ new/source/highlightData.c
237 @@ -553,11 +553,11 @@ static char *DefaultPatternSets[] = {
238 Built-in Special Vars:\"(?<!\\Y)\\$(?:[1-9]|list_dialog_button|n_args|read_status|search_end|shell_cmd_status|string_dialog_button|sub_sep)>\":::String1::\n\
239 Built-in Subrs:\"<(?:append_file|beep|call|calltip|clipboard_to_string|dialog|filename_dialog|dict_(?:insert|complete|save|append|is_element)|focus_window|get_character|get_matching|get_pattern_(by_name|at_pos)|get_range|get_selection|get_style_(by_name|at_pos)|getenv|highlight_calltip_line|kill_calltip|length|list_dialog|max|min|rangeset_(?:add|create|destroy|get_by_name|includes|info|invert|range|set_color|set_mode|set_name|subtract)|read_file|replace_in_string|replace_range|replace_selection|replace_substring|search|search_string|select|select_rectangle|set_cursor_pos|set_transient|shell_command|split|string_compare|string_dialog|string_to_clipboard|substring|t_print|tolower|toupper|valid_number|write_file)(?=\\s*\\()\":::Subroutine::\n\
240 Menu Actions:\"<(?:new(?:_tab|_opposite)?|open|open-dialog|open_dialog|open-selected|open_selected|close|save|save-as|save_as|save-as-dialog|save_as_dialog|revert-to-saved|revert_to_saved|revert_to_saved_dialog|include-file|include_file|include-file-dialog|include_file_dialog|load-macro-file|load_macro_file|load-macro-file-dialog|load_macro_file_dialog|load-tags-file|load_tags_file|load-tags-file-dialog|load_tags_file_dialog|unload_tags_file|load_tips_file|load_tips_file_dialog|unload_tips_file|print|print-selection|print_selection|exit|undo|redo|delete|select-all|select_all|shift-left|shift_left|shift-left-by-tab|shift_left_by_tab|shift-right|shift_right|shift-right-by-tab|shift_right_by_tab|find|find-dialog|find_dialog|find-again|find_again|find-selection|find_selection|find_incremental|start_incremental_find|replace|replace-dialog|replace_dialog|replace-all|replace_all|replace-in-selection|replace_in_selection|replace-again|replace_again|replace_find|replace_find_same|replace_find_again|goto-line-number|goto_line_number|goto-line-number-dialog|goto_line_number_dialog|goto-selected|goto_selected|mark|mark-dialog|mark_dialog|goto-mark|goto_mark|goto-mark-dialog|goto_mark_dialog|match|select_to_matching|goto_matching|find-definition|find_definition|show_tip|split-pane|split_pane|close-pane|close_pane|detach_document(?:_dialog)?|move_document_dialog|(?:next|previous|last)_document|uppercase|lowercase|fill-paragraph|fill_paragraph|control-code-dialog|control_code_dialog|filter-selection-dialog|filter_selection_dialog|filter-selection|filter_selection|execute-command|execute_command|execute-command-dialog|execute_command_dialog|execute-command-line|execute_command_line|shell-menu-command|shell_menu_command|macro-menu-command|macro_menu_command|bg_menu_command|post_window_bg_menu|post_tab_context_menu|beginning-of-selection|beginning_of_selection|end-of-selection|end_of_selection|repeat_macro|repeat_dialog|raise_window|focus_pane|set_statistics_line|set_incremental_search_line|set_show_line_numbers|set_auto_indent|set_wrap_text|set_wrap_margin|set_highlight_syntax|set_make_backup_copy|set_incremental_backup|set_show_matching|set_match_syntax_based|set_overtype_mode|set_locked|set_tab_dist|set_em_tab_dist|set_use_tabs|set_fonts|set_language_mode)(?=\\s*\\()\":::Subroutine::\n\
241 Text Actions:\"<(?:self-insert|self_insert|grab-focus|grab_focus|extend-adjust|extend_adjust|extend-start|extend_start|extend-end|extend_end|secondary-adjust|secondary_adjust|secondary-or-drag-adjust|secondary_or_drag_adjust|secondary-start|secondary_start|secondary-or-drag-start|secondary_or_drag_start|process-bdrag|process_bdrag|move-destination|move_destination|move-to|move_to|move-to-or-end-drag|move_to_or_end_drag|end_drag|copy-to|copy_to|copy-to-or-end-drag|copy_to_or_end_drag|exchange|process-cancel|process_cancel|paste-clipboard|paste_clipboard|copy-clipboard|copy_clipboard|cut-clipboard|cut_clipboard|copy-primary|copy_primary|cut-primary|cut_primary|newline|newline-and-indent|newline_and_indent|newline-no-indent|newline_no_indent|delete-selection|delete_selection|delete-previous-character|delete_previous_character|delete-next-character|delete_next_character|delete-previous-word|delete_previous_word|delete-next-word|delete_next_word|delete-to-start-of-line|delete_to_start_of_line|delete-to-end-of-line|delete_to_end_of_line|forward-character|forward_character|backward-character|backward_character|key-select|key_select|process-up|process_up|process-down|process_down|process-shift-up|process_shift_up|process-shift-down|process_shift_down|process-home|process_home|forward-word|forward_word|backward-word|backward_word|forward-paragraph|forward_paragraph|backward-paragraph|backward_paragraph|beginning-of-line|beginning_of_line|end-of-line|end_of_line|beginning-of-file|beginning_of_file|end-of-file|end_of_file|next-page|next_page|previous-page|previous_page|page-left|page_left|page-right|page_right|toggle-overstrike|toggle_overstrike|scroll-up|scroll_up|scroll-down|scroll_down|scroll_left|scroll_right|scroll-to-line|scroll_to_line|select-all|select_all|deselect-all|deselect_all|focusIn|focusOut|process-return|process_return|process-tab|process_tab|insert-string|insert_string|mouse_pan)(?=\\s*\\()\":::Subroutine::\n\
242 Macro Hooks:\"<(?:(?:pre|post)_(?:open|save)|cursor_moved|modified|(?:losing_)?focus)_hook(?=\\s*\\()\":::Subroutine1::\n\
243 - Keyword:\"<(?:break|continue|define|delete|else|for|if|in|return|while)>\":::Keyword::\n\
244 + Keyword:\"<(?:break|continue|define|delete|else|for|if|in|return|typeof|while)>\":::Keyword::\n\
245 Braces:\"[{}\\[\\]]\":::Keyword::\n\
246 Global Variable:\"\\$[A-Za-z0-9_]+\":::Identifier1::\n\
247 String sq:\"'\":\"'\"::String::\n\
248 String:\"\"\"\":\"\"\"\":\"\\n\":String::\n\
249 String Escape Char:\"\\\\(?:[\\\\\"\"ntbrfave\\n]|[xX][0-9a-fA-F]{1,2}|0*[0-7]{1,3})\":::Text Escape:String:\n\
250 diff --quilt old/source/ops.h new/source/ops.h
253 @@ -55,5 +55,7 @@ OP(ANONARRAY_CLOSE, anonArrayClos
254 OP(NAMED_ARG1, namedArg1) /* N */ /* pop(v,kN..k1), a=ary(), a[k1..kN]=v, push(a) */
255 OP(NAMED_ARGN, namedArgN) /* N */ /* pop(v,kN..k1,a), a[k1..kN]=v, push(a) */
256 OP(SWAP_TOP2, swapTop2) /* pop(v1,v2), push(v1,v2) */
257 OP(SUBR_CALL_STACKED_N, callSubroutineStackedN) /*s*/ /* pop(N,a,pN..p1), call(s) */
258 OP(UNPACKTOARGS, unpackArrayToArgs) /* pop(a), push(a[1]..a[N],a,-(N+1)) */
259 +OP(TYPEOF_IN, typeOfIn) /* enable typeof() */
260 +OP(TYPEOF_OUT, typeOfOut) /* pop(v), push(typeof(v)) */