6 Given a PMC, get a list from it. If the PMC is a TclList,
7 this is as simple as returning the list.
11 .sub __list :multi(TclList)
22 push_eh convert_to_tcl_error
23 $P0 = $P0.'get_list'($S0)
30 # The PMC method only throws a regular exception, we need to tcl-ify it.
32 get_results '0,0', $P0, $S0
39 Given a PMC, get a TclDict from it, converting as needed.
43 .sub __dict :multi(TclDict)
48 .sub __dict :multi(TclList)
51 $P0 = __listToDict(list)
60 $P0 = __stringToDict(value)
69 Given a PMC, get a number from it.
73 .sub __number :multi(TclInt)
78 .sub __number :multi(TclFloat)
83 .sub __number :multi(_)
90 .include 'cclass.pasm'
95 parse = get_root_global ['parrot'; 'TclExpr::Grammar'], 'number'
96 $I0 = find_not_cclass .CCLASS_WHITESPACE, str, 0, len
97 match = parse(str, 'pos'=>$I0, 'grammar'=>'TclExpr::Grammar')
101 $I0 = find_not_cclass .CCLASS_WHITESPACE, str, $I0, $I1
102 if $I0 < len goto NaN
104 unless match goto NaN
106 .local pmc astgrammar, astbuilder, ast
107 astgrammar = new 'TclExpr::PAST::Grammar'
108 astbuilder = astgrammar.apply(match)
109 ast = astbuilder.get('past')
111 .local string className
114 className = ast['class']
117 # XXX We probably shouldn't have to invoke the PIR compiler here.
119 $P0 = new 'CodeString'
120 $P0.emit(".sub 'anon' :anon")
121 $P0.emit('$P0 = new "%0"', className)
122 $P0.emit("$P0 = %0", value)
123 $P0.emit(".return($P0)")
133 $S1 = 'expected floating-point number but got "'
140 =head2 _Tcl::__integer
142 Given a PMC, get an integer from it.
146 .sub __integer :multi(TclInt)
151 .sub __integer :multi(_)
153 .param pmc rawhex :named ('rawhex') :optional
154 .param int has_rawhex :opt_flag
156 unless has_rawhex goto normal
164 push_eh not_integer_eh
165 integer = __number(value)
168 if $S0 != 'TclInt' goto not_integer
176 $S0 = 'expected integer but got "'
182 get_results '0,0', $P99, $S99
183 $I0 = index $S99, 'expected integer'
184 if $I0 == -1 goto not_integer # got some other exception, rewrap it.
185 rethrow $P99 # preserves the invalid octal message.
196 if idx == 'end' goto end
198 $S0 = substr idx, 0, 4
199 if $S0 == 'end-' goto before_end
200 if $S0 == 'end+' goto after_end
235 get_results '0,0', $P99, $S99
238 $S0 .= '": must be integer?[+-]integer? or end?[+-]integer?'
239 $S1 = ' (looks like invalid octal number)'
240 $I0 = index $S99, $S1
241 if $I0 == -1 goto bad_index_done
242 $I0 = index idx, '--'
243 if $I0 != -1 goto bad_index_done # don't squawk on negative indices..
249 =head2 _Tcl::__channel
251 Given a string, return the appropriate channel.
256 .param string channelID
259 channels = find_global 'channels'
262 io_obj = channels[channelID]
263 if null io_obj goto bad_channel
266 if $S0 == 'ParrotIO' goto done
267 if $S0 == 'TCPStream' goto done
269 # should never happen
276 $S0 = 'can not find channel named "'
285 Given an expression, return a subroutine, or optionally, the raw PIR
290 .param string expression
291 .param int pir_only :named('pir_only') :optional
292 .param pmc ns :named('ns') :optional
293 .param int has_ns :opt_flag
298 if expression == '' goto empty
300 parse = get_root_global ['parrot'; 'TclExpr::Grammar'], 'expression'
301 match = parse(expression, 'pos'=>0, 'grammar'=>'TclExpr::Grammar')
303 unless match goto premature_end
304 $I0 = length expression
306 .include 'cclass.pasm'
307 $I1 = find_not_cclass .CCLASS_WHITESPACE, expression, $I1, $I0
308 unless $I0 == $I1 goto extra_tokens
310 .local pmc astgrammar, astbuilder, ast
311 astgrammar = new 'TclExpr::PAST::Grammar'
312 astbuilder = astgrammar.apply(match)
313 ast = astbuilder.get('past')
315 .local string namespace
317 unless has_ns goto build_pir
319 $P0 = ns.'get_name'()
322 if $I0 == 0 goto build_pir
323 $S0 = join "'; '", $P0
329 .local pmc pirgrammar, pirbuilder
331 pirgrammar = new 'TclExpr::PIR::Grammar'
332 pirbuilder = pirgrammar.'apply'(ast)
333 result = pirbuilder.get('result')
337 if pir_only goto only_pir
340 pir = new 'CodeString'
342 pir.emit(".HLL 'Tcl', ''")
343 pir.emit('.namespace %0', namespace)
344 pir.emit(".sub '_anon' :anon")
346 pir.emit(" .return(%0)", ret)
358 $S0 = 'syntax error in expression "' . $S0
359 $S0 = $S0 . '": premature end of expression'
364 $S0 = 'syntax error in expression "' . $S0
365 $S0 = $S0 . '": extra tokens at end of expression'
369 tcl_error "empty expression\nin expression \"\""
372 =head2 _Tcl::__script
374 Given a chunk of tcl code, return a subroutine.
380 .param int pir_only :named('pir_only') :optional
381 .param pmc ns :named('ns') :optional
382 .param int has_ns :opt_flag
383 .param int bsnl :named('bsnl') :optional
384 .param int has_bsnl :opt_flag
385 .param int wrapper :named('wrapper') :optional
386 .param int has_wrapper :opt_flag
391 unless has_bsnl goto end_preamble
392 unless bsnl goto end_preamble
393 code = 'backslash_newline_subst'( code )
396 parse = get_root_global ['parrot'; 'TclExpr::Grammar'], 'program'
397 match = parse(code, 'pos'=>0, 'grammar'=>'TclExpr::Grammar')
399 unless match goto premature_end
402 .include 'cclass.pasm'
403 $I1 = find_not_cclass .CCLASS_WHITESPACE, code, $I1, $I0
404 unless $I0 == $I1 goto extra_tokens
406 .local pmc astgrammar, astbuilder, ast
407 astgrammar = new 'TclExpr::PAST::Grammar'
408 astbuilder = astgrammar.apply(match)
409 ast = astbuilder.get('past')
411 .local string namespace
413 unless has_ns goto build_pir
415 $P0 = ns.'get_name'()
418 if $I0 == 0 goto build_pir
419 $S0 = join "'; '", $P0
425 .local pmc pirgrammar, pirbuilder
427 pirgrammar = new 'TclExpr::PIR::Grammar'
428 pirbuilder = pirgrammar.'apply'(ast)
429 result = pirbuilder.get('result')
435 pir = new 'CodeString'
436 unless pir_only goto do_wrapper
437 if has_wrapper goto do_wrapper
442 pir.emit(".HLL 'Tcl', ''")
443 pir.emit(".loadlib 'tcl_ops'")
444 pir.emit('.namespace %0', namespace)
445 pir.emit(".include 'languages/tcl/src/returncodes.pasm'")
446 pir.emit(".sub '_anon' :anon")
448 pir.emit(' .return(%0)', ret)
450 pir.emit(<<"END_PIR")
453 load_bytecode 'languages/tcl/runtime/tcllib.pir'
457 if pir_only goto only_pir
467 tcl_error "program doesn't match grammar"
470 $S0 = substr code, $I1
471 $S0 = 'extra tokens at end of program: ' . $S0
475 =head2 _Tcl::__namespace
477 Given a string namespace, return an array of names.
483 .param int depth :optional
484 .param int has_depth :opt_flag
486 if has_depth goto depth_set
490 .local pmc colons, split
491 colons = get_root_global ['_tcl'], 'colons'
492 split = get_root_global ['parrot'; 'PGE::Util'], 'split'
495 ns_name = split(colons, name)
496 $I0 = elements ns_name
497 if $I0 == 0 goto relative
499 if $S0 != '' goto relative
510 $P0 = interp['sub'; depth]
511 $P0 = $P0.'get_namespace'()
512 $P0 = $P0.'get_name'()
514 if $S0 == '_tcl' goto relative_loop
519 if $I0 == 0 goto return
528 =head2 _Tcl::__boolean
530 Given a string, return its boolean value if it's a valid boolean. Otherwise,
542 if lc == '1' goto true
543 if lc == '0' goto false
544 if lc == 'true' goto true
545 if lc == 'tru' goto true
546 if lc == 'tr' goto true
547 if lc == 't' goto true
548 if lc == 'false' goto false
549 if lc == 'fals' goto false
550 if lc == 'fal' goto false
551 if lc == 'fa' goto false
552 if lc == 'f' goto false
553 if lc == 'yes' goto true
554 if lc == 'ye' goto true
555 if lc == 'y' goto true
556 if lc == 'no' goto false
557 if lc == 'n' goto false
558 if lc == 'on' goto true
559 if lc == 'off' goto false
560 if lc == 'of' goto false
563 __number = get_hll_global '__number'
566 value = __number(value)
573 $S0 = 'expected boolean value but got "' . $S0
586 =head2 _Tcl::__call_level
588 Given a pmc containing the tcl-style call level, return an int-like pmc
589 indicating the parrot-style level, and an integer with a boolean 0/1 -
590 was this a valid tcl-style level, or did we get this value as a default?
596 .local pmc parrot_level, defaulted, orig_level
597 defaulted = new 'Integer'
600 .local pmc call_chain, __number
601 .local int call_level
602 call_chain = get_root_global ['_tcl'], 'call_chain'
603 call_level = elements call_chain
604 __number = get_root_global ['_tcl'], '__number'
605 orig_level = new 'Integer'
606 orig_level = call_level
608 .local int num_length
611 # Is this an absolute?
613 $S1 = substr $S0, 0, 1, ''
614 if $S1 != '#' goto get_integer
616 parrot_level = __number($S0)
622 parrot_level = __number(tcl_level)
625 if parrot_level < 0 goto default
626 parrot_level = orig_level - parrot_level
631 parrot_level = new 'Integer'
632 parrot_level = orig_level - 1
637 if parrot_level < 0 goto bad_level
638 if parrot_level > orig_level goto bad_level
641 .return(parrot_level,$I1)
645 $S0 = 'bad level "' . $S0
650 =head2 _Tcl::backslash_newline_subst
652 Given a string of tcl code, perform the backslash/newline subsitution.
656 .sub 'backslash_newline_subst'
657 .param string contents
660 len = length contents
662 # perform the backslash-newline substitution
666 if $I0 >= len goto done
667 $I1 = ord contents, $I0
668 if $I1 != 92 goto backslash_loop # \\
671 $I1 = ord contents, $I2
672 if $I1 == 10 goto space # \n
673 if $I1 == 13 goto space # \r
677 if $I0 >= len goto done
678 $I1 = is_cclass .CCLASS_WHITESPACE, contents, $I2
679 if $I1 == 0 goto not_space
684 substr contents, $I0, $I1, ' '
693 # Given a list, reverse the elements in the list.
694 # Might make sense to make this a method on one of the parrot types we
705 dec high # need index, not count
709 if high <= low goto loop_end
710 swap_one = value[low]
711 swap_two = value[high]
712 value[low] = swap_two
713 value[high] = swap_one
726 # vim: expandtab shiftwidth=4 ft=pir: