Author: mdiep
Date: Mon Aug 1 21:24:40 2005
New Revision: 8763
Added:
trunk/languages/tcl/lib/parser.pir
trunk/languages/tcl/lib/tclcommand.pir
trunk/languages/tcl/lib/tclconst.pir
trunk/languages/tcl/lib/tclvar.pir
Removed:
trunk/languages/tcl/classes/tclparser.pmc
Modified:
trunk/MANIFEST
trunk/config/gen/makefiles/tcl.in
trunk/languages/tcl/lib/commands/catch.pir
trunk/languages/tcl/lib/commands/eval.pir
trunk/languages/tcl/lib/commands/for.pir
trunk/languages/tcl/lib/commands/foreach.pir
trunk/languages/tcl/lib/commands/if.pir
trunk/languages/tcl/lib/commands/proc.pir
trunk/languages/tcl/lib/commands/puts.pir
trunk/languages/tcl/lib/commands/source.pir
trunk/languages/tcl/lib/commands/time.pir
trunk/languages/tcl/lib/commands/while.pir
trunk/languages/tcl/lib/expression.pir
trunk/languages/tcl/lib/interpret.pir
trunk/languages/tcl/lib/list_to_string.pir
trunk/languages/tcl/lib/string_to_list.pir
trunk/languages/tcl/lib/tclword.pir
trunk/languages/tcl/t/tcl_command_subst.t
trunk/languages/tcl/tcl.pir
trunk/languages/tcl/tcl.pir_template
trunk/languages/tcl/tcl.pl
Log:
The new PIR based parser for ParTcl:
* More correct parsing
* Broken octal escapes (at the moment)
* Poor documentation (also at the moment)
* A few other broken features that need tests
Modified: trunk/MANIFEST
==============================================================================
--- trunk/MANIFEST (original)
+++ trunk/MANIFEST Mon Aug 1 21:24:40 2005
@@ -1362,7 +1362,6 @@ languages/tcl/classes/tclint.pmc
languages/tcl/classes/tcllist.pmc [tcl]
languages/tcl/classes/tclstring.pmc [tcl]
languages/tcl/classes/tclobject.pmc [tcl]
-languages/tcl/classes/tclparser.pmc [tcl]
languages/tcl/docs/expr.pod [tcl]
languages/tcl/docs/hacks.pod [tcl]
languages/tcl/docs/howto.pod [tcl]
@@ -1421,7 +1420,11 @@ languages/tcl/lib/interpret.pir
languages/tcl/lib/list.pir [tcl]
languages/tcl/lib/list_to_string.pir [tcl]
languages/tcl/lib/macros/is_space.pir [tcl]
+languages/tcl/lib/parser.pir [tcl]
languages/tcl/lib/string_to_list.pir [tcl]
+languages/tcl/lib/tclcommand.pir [tcl]
+languages/tcl/lib/tclconst.pir [tcl]
+languages/tcl/lib/tclvar.pir [tcl]
languages/tcl/lib/tclword.pir [tcl]
languages/tcl/lib/tcl.p6r [tcl]
languages/tcl/lib/variables.pir [tcl]
Modified: trunk/config/gen/makefiles/tcl.in
==============================================================================
--- trunk/config/gen/makefiles/tcl.in (original)
+++ trunk/config/gen/makefiles/tcl.in Mon Aug 1 21:24:40 2005
@@ -14,8 +14,7 @@ PMCS = \
tclint \
tclfloat \
tcllist \
- tclarray \
- tclparser
+ tclarray
DEPS = $(PARROT) \
lib${slash}commands${slash}append.pir \
@@ -64,14 +63,16 @@ lib${slash}expression.pir \
lib${slash}get_var.pir \
lib${slash}interpret.pir \
lib${slash}list.pir \
+lib${slash}list_to_string.pir \
lib${slash}macros${slash}is_space.pir \
+lib${slash}parser.pir \
lib${slash}string_to_list.pir \
lib${slash}tcl.p6r \
lib${slash}variables.pir \
tcl.pir_template \
tcl.pl
-tcl.pbc: pmcs lib${slash}tcllib.pbc lib${slash}tclword.pbc tcl.pir
+tcl.pbc: pmcs lib${slash}tcllib.pbc lib${slash}tclcommand.pbc
lib${slash}tclconst.pbc lib${slash}tclvar.pbc lib${slash}tclword.pbc tcl.pir
$(PARROT) --output=tcl.pbc tcl.pir
pmcs:
@@ -89,6 +90,15 @@ lib${slash}tcllib.pir: $(DEPS)
lib${slash}tcllib.pbc: lib${slash}tcllib.pir
$(PARROT) --output=$(LIBPATH)${slash}tcllib.pbc
$(LIBPATH)${slash}tcllib.pir
+lib${slash}tclcommand.pbc: lib${slash}tclcommand.pir
+ $(PARROT) --output=$(LIBPATH)${slash}tclcommand.pbc
$(LIBPATH)${slash}tclcommand.pir
+
+lib${slash}tclconst.pbc: lib${slash}tclconst.pir
+ $(PARROT) --output=$(LIBPATH)${slash}tclconst.pbc
$(LIBPATH)${slash}tclconst.pir
+
+lib${slash}tclvar.pbc: lib${slash}tclvar.pir
+ $(PARROT) --output=$(LIBPATH)${slash}tclvar.pbc
$(LIBPATH)${slash}tclvar.pir
+
lib${slash}tclword.pbc: lib${slash}tclword.pir
$(PARROT) --output=$(LIBPATH)${slash}tclword.pbc
$(LIBPATH)${slash}tclword.pir
Modified: trunk/languages/tcl/lib/commands/catch.pir
==============================================================================
--- trunk/languages/tcl/lib/commands/catch.pir (original)
+++ trunk/languages/tcl/lib/commands/catch.pir Mon Aug 1 21:24:40 2005
@@ -14,10 +14,10 @@
.local pmc retval
.local string varname,sigil_varname
.local string code
- .local pmc parser
+ .local pmc parse
.local pmc interpret
return_type = TCL_OK
- parser = find_global "_Tcl", "parser"
+ parse = find_global "_Tcl", "parse"
interpret = find_global "_Tcl", "__interpret"
.local int call_level
@@ -27,7 +27,7 @@
if argc == 0 goto badargs
if argc > 2 goto badargs
code = argv[0]
- $P1 = parser."parse"(code,0,0)
+ $P1 = parse(code)
register $P1
# ignoring $P0 here.
($I0,$P0) = interpret($P1)
Modified: trunk/languages/tcl/lib/commands/eval.pir
==============================================================================
--- trunk/languages/tcl/lib/commands/eval.pir (original)
+++ trunk/languages/tcl/lib/commands/eval.pir Mon Aug 1 21:24:40 2005
@@ -17,9 +17,9 @@
.local int looper
- .local pmc parser
+ .local pmc parse
.local pmc interpret
- parser = find_global "_Tcl", "parser"
+ parse = find_global "_Tcl", "parse"
interpret = find_global "_Tcl", "__interpret"
expr = ""
@@ -36,7 +36,7 @@ loop:
goto loop
loop_done:
- $P1 = parser."parse"(expr,0,0)
+ $P1 = parse(expr)
register $P1
.return interpret($P1)
Modified: trunk/languages/tcl/lib/commands/for.pir
==============================================================================
--- trunk/languages/tcl/lib/commands/for.pir (original)
+++ trunk/languages/tcl/lib/commands/for.pir Mon Aug 1 21:24:40 2005
@@ -16,22 +16,22 @@
.local pmc retval
.local int return_type
- .local pmc parser, interpret
+ .local pmc parse, interpret
.local pmc expression_p, expression_i
- parser = find_global "_Tcl", "parser"
+ parse = find_global "_Tcl", "parse"
interpret = find_global "_Tcl", "__interpret"
expression_p = find_global "_Tcl", "__expression_parse"
expression_i = find_global "_Tcl", "__expression_interpret"
# Parse the bits that are code.
$S0 = start_p
- start_parsed = parser."parse"($S0,0,0)
+ start_parsed = parse($S0)
register start_parsed
$S0 = next_p
- next_parsed = parser."parse"($S0,0,0)
+ next_parsed = parse($S0)
register next_parsed
$S0 = body_p
- body_parsed = parser."parse"($S0,0,0)
+ body_parsed = parse($S0)
register body_parsed
Modified: trunk/languages/tcl/lib/commands/foreach.pir
==============================================================================
--- trunk/languages/tcl/lib/commands/foreach.pir (original)
+++ trunk/languages/tcl/lib/commands/foreach.pir Mon Aug 1 21:24:40 2005
@@ -7,7 +7,7 @@
argv = foldup
.local int return_type
- .local pmc parser,interpret,retval
+ .local pmc parse,interpret,retval
retval = new TclString
retval = ""
@@ -23,7 +23,7 @@
.local pmc __list
__list = find_global "_Tcl", "__list"
- parser = find_global "_Tcl", "parser"
+ parse = find_global "_Tcl", "parse"
interpret = find_global "_Tcl", "__interpret"
return_type = TCL_OK
@@ -77,7 +77,7 @@ got_list:
goto arg_loop
arg_done:
.local pmc parsed
- parsed = parser."parse"(body,0,0)
+ parsed = parse(body)
register parsed
.local pmc iterator
Modified: trunk/languages/tcl/lib/commands/if.pir
==============================================================================
--- trunk/languages/tcl/lib/commands/if.pir (original)
+++ trunk/languages/tcl/lib/commands/if.pir Mon Aug 1 21:24:40 2005
@@ -24,9 +24,9 @@
handling_else = 0
.local int counter
- .local pmc parser,interpret
+ .local pmc parse,interpret
.local pmc expression_p,expression_i
- parser = find_global "_Tcl", "parser"
+ parse = find_global "_Tcl", "parse"
interpret = find_global "_Tcl", "__interpret"
expression_p = find_global "_Tcl", "__expression_parse"
expression_i = find_global "_Tcl", "__expression_interpret"
@@ -109,7 +109,7 @@ do_else:
code = else
done:
- $P1 = parser."parse"(code,0,0)
+ $P1 = parse(code)
register $P1
.return interpret($P1) #tailcall
Modified: trunk/languages/tcl/lib/commands/proc.pir
==============================================================================
--- trunk/languages/tcl/lib/commands/proc.pir (original)
+++ trunk/languages/tcl/lib/commands/proc.pir Mon Aug 1 21:24:40 2005
@@ -17,8 +17,8 @@ Create a PIR sub on the fly for this use
.local pmc retval
return_type = TCL_OK
- .local pmc parser
- parser = find_global "_Tcl", "parser"
+ .local pmc parse
+ parse = find_global "_Tcl", "parse"
.local pmc __list
__list = find_global "_Tcl", "__list"
@@ -36,7 +36,7 @@ got_args:
# Save the parsed body.
.local pmc parsed_body
$S0 = body_p
- parsed_body = parser."parse"($S0,0,0)
+ parsed_body = parse($S0)
register parsed_body
# XXX these need to go away - for now, we'll just escape
Modified: trunk/languages/tcl/lib/commands/puts.pir
==============================================================================
--- trunk/languages/tcl/lib/commands/puts.pir (original)
+++ trunk/languages/tcl/lib/commands/puts.pir Mon Aug 1 21:24:40 2005
@@ -56,7 +56,8 @@ two_arg_channel:
goto done
one_arg:
- $S1 = argv[0]
+ $P0 = argv[0]
+ $S1 = $P0
print $S1
print "\n"
goto done
Modified: trunk/languages/tcl/lib/commands/source.pir
==============================================================================
--- trunk/languages/tcl/lib/commands/source.pir (original)
+++ trunk/languages/tcl/lib/commands/source.pir Mon Aug 1 21:24:40 2005
@@ -14,9 +14,9 @@
.local string chunk, filename, contents
.local int code,type
- .local pmc retval, handle, parser
+ .local pmc retval, handle, parse
- parser = find_global "_Tcl", "parser"
+ parse = find_global "_Tcl", "parse"
.local pmc interpret
interpret = find_global "_Tcl", "__interpret"
@@ -42,7 +42,7 @@ loop:
goto loop
gotfile:
- $P1 = parser."parse"(contents,0,0)
+ $P1 = parse(contents)
register $P1
(code,retval) = interpret($P1)
goto done
Modified: trunk/languages/tcl/lib/commands/time.pir
==============================================================================
--- trunk/languages/tcl/lib/commands/time.pir (original)
+++ trunk/languages/tcl/lib/commands/time.pir Mon Aug 1 21:24:40 2005
@@ -15,8 +15,8 @@
.local int return_type
return_type = TCL_OK
- .local pmc parser,interpret
- parser = find_global "_Tcl", "parser"
+ .local pmc parse,interpret
+ parse = find_global "_Tcl", "parse"
interpret = find_global "_Tcl", "__interpret"
.local string script
@@ -38,7 +38,7 @@ twoargs:
run:
script = argv[0]
- $P1 = parser."parse"(script,0,0)
+ $P1 = parse(script)
register $P1
time $N1
Modified: trunk/languages/tcl/lib/commands/while.pir
==============================================================================
--- trunk/languages/tcl/lib/commands/while.pir (original)
+++ trunk/languages/tcl/lib/commands/while.pir Mon Aug 1 21:24:40 2005
@@ -12,20 +12,21 @@
.local pmc retval, parsed_code
.local int return_type
- .local pmc parser
+ .local pmc parse
.local pmc interpret
.local pmc expression_p
.local pmc expression_i
- parser = find_global "_Tcl", "parser"
+ parse = find_global "_Tcl", "parse"
interpret = find_global "_Tcl", "__interpret"
expression_p = find_global "_Tcl", "__expression_parse"
expression_i = find_global "_Tcl", "__expression_interpret"
-while_loop:
$S0 = body_p
- parsed_code = parser."parse"($S0,0,0)
+ parsed_code = parse($S0)
register parsed_code
+
+while_loop:
(return_type,retval) = expression_p(cond_p)
if return_type == TCL_ERROR goto done_done
(return_type,retval) = expression_i(retval)
Modified: trunk/languages/tcl/lib/expression.pir
==============================================================================
--- trunk/languages/tcl/lib/expression.pir (original)
+++ trunk/languages/tcl/lib/expression.pir Mon Aug 1 21:24:40 2005
@@ -28,9 +28,6 @@ however, then we're returning the invoka
.local pmc precedences # Global list of operator precedence
precedences = find_global "_Tcl", "precedence"
- .local pmc parser
- parser = find_global "_Tcl", "parser"
-
if I3 == 1 goto pmc_arg
# if I2 isn't one here, we should blow up. But who's counting.
expr = S5
@@ -85,15 +82,34 @@ get_parenthetical:
# string and call ourselves recursively.
# (XXX should unroll this recursion.)
- if char != 40 goto get_variable
- # where do we close?
- $I1 = parser."match_close"(expr,chunk_start)
- #.match_close(expr,chunk_start,$I1)
- #error_S = "missing close parenthesis"
- if $I1 <= 0 goto die_horribly
- $I1 = $I1 - 2
- inc chunk_start
- substr $S1, expr, chunk_start, $I1
+ if char != 40 goto get_variable # (
+ .local int depth
+ depth = 1
+ $I1 = chunk_start
+get_paren_loop:
+ inc $I1
+ if $I1 >= expr_length goto die_horribly
+ $I0 = ord expr, $I1
+ if $I0 == 41 goto get_paren_loop_right
+ if $I0 == 40 goto get_paren_loop_left
+ if $I0 == 92 goto get_paren_loop_backslash
+ goto get_paren_loop
+get_paren_loop_right:
+ dec depth
+ if depth == 0 goto get_paren_done
+ goto get_paren_loop
+get_paren_loop_left:
+ inc depth
+ goto get_paren_loop
+get_paren_loop_backslash:
+ inc $I1
+ goto get_paren_loop
+
+get_paren_done:
+ $I0 = $I1 - chunk_start
+ dec $I0
+ inc chunk_start
+ substr $S1, expr, chunk_start, $I0
$P9 = new String
$P9 = $S1
@@ -108,7 +124,7 @@ get_parenthetical:
chunk[1] = retval
push chunks, chunk
- chunk_start = chunk_start + $I1
+ chunk_start += $I0
inc chunk_start
goto chunk_loop
@@ -854,21 +870,42 @@ dd:
.local pmc func,operand
.local int start_paren_pos
-
- .local pmc parser
- parser = find_global "_Tcl", "parser"
+ .local int expr_length
+ expr_length = length expr
# if we are starting with the text of a defined function,
# and it's followed by a (),
index start_paren_pos, expr, "(", start
if start_paren_pos == -1 goto fail
- #.match_close(expr,start_paren_pos,$I1)
- $I1 = parser."match_close"(expr,start_paren_pos)
- if $I1 <= 0 goto fail
+
+ .local int depth
+ depth = 1
+ $I0 = start_paren_pos
+loop:
+ inc $I0
+ if $I0 >= expr_length goto fail
+ $I1 = ord expr, $I0
+ if $I1 == 40 goto left
+ if $I1 == 41 goto right
+ if $I1 == 92 goto backslash
+ goto loop
+left:
+ inc depth
+ goto loop
+right:
+ dec depth
+ if depth == 0 goto loop_done
+ goto loop
+backslash:
+ inc $I0
+ goto loop
+
+loop_done:
+ $I1 = $I0 - start_paren_pos
+ dec $I1
# so, we know that the function name must be before the first (
-
.local int len
len = start_paren_pos - start
@@ -888,7 +925,7 @@ dd:
inc start_paren_pos
.local int len_operand
- len_operand = $I1 - 2
+ len_operand = $I1
substr $S1, expr, start_paren_pos, len_operand
$P9 = new String
Modified: trunk/languages/tcl/lib/interpret.pir
==============================================================================
--- trunk/languages/tcl/lib/interpret.pir (original)
+++ trunk/languages/tcl/lib/interpret.pir Mon Aug 1 21:24:40 2005
@@ -14,83 +14,18 @@ Given a pre-parsed chunk of Tcl, interpr
return_type = TCL_OK
.local pmc retval
- # Which command are we processing?
- .local int command_num,num_commands
- command_num = -1
- num_commands = commands
- .local pmc command
- .local string proc,sigil_proc
- .local pmc args,my_cmd,parsed_body,argument_list
-
-end_scope:
- inc command_num
- if command_num == num_commands goto done
- if return_type != TCL_OK goto done
- command = commands[command_num]
-
- # this should stringify the tclword object, which performs
- # all necessary substitutions.
- $P0 = command[0]
- (return_type,retval) = $P0.__get_pmc()
-
- if return_type != TCL_OK goto done
- proc = retval
- sigil_proc = "&" . proc
-
- .local int num_args,arg_num
- num_args = command
- arg_num = 1
-
- # The subs we're calling expect flattened args,
- # as passed with the ":flag" arg adverb.
-
- .local string caller_sub_text
-
- push_eh no_command
- my_cmd = find_global "Tcl", sigil_proc
- clear_eh
- # we can't delete commands, so we store deleted commands
- # as null PMCs
- isnull my_cmd, no_command
+ .local int elems, i
+ elems = commands
+ i = 0
-got_command:
- .local pmc folded_args
- folded_args = new TclList
- .local pmc current_word
-
-loop:
- if arg_num == num_args goto loop_done
- current_word = command[arg_num]
- (return_type,retval) = current_word.__get_pmc()
+ .local pmc command
+next_command:
+ if i == elems goto done
if return_type != TCL_OK goto done
-
- push folded_args, retval
- inc arg_num
- goto loop
-
-loop_done:
- (return_type,retval) = my_cmd(folded_args :flat)
- goto end_scope
-
-no_command:
- $P1 = find_global "Tcl", "$tcl_interactive"
- unless $P1 goto no_command_non_interactive
-
- # XXX Should probably make sure this wasn't redefined on us.
- my_cmd = find_global "Tcl", "&unknown"
-
- # Add the command into the unknown handler, and fix our bookkeeping
- unshift command, proc
- inc num_args
-
- goto got_command
-
-no_command_non_interactive:
- return_type = TCL_ERROR
- $S0 = "invalid command name \""
- $S0 .= proc
- $S0 .= "\""
- retval = $S0
+ command = commands[i]
+ (return_type, retval) = command.interpret()
+ inc i
+ goto next_command
done:
.return(return_type,retval)
Modified: trunk/languages/tcl/lib/list_to_string.pir
==============================================================================
--- trunk/languages/tcl/lib/list_to_string.pir (original)
+++ trunk/languages/tcl/lib/list_to_string.pir Mon Aug 1 21:24:40 2005
@@ -42,6 +42,24 @@ right_brace:
check_list_done:
if count != 0 goto escape
+ # {}'d constructs
+check_spaces:
+ $I0 = find_whitespace $S0, 0
+ if $I0 != -1 goto quote
+
+check_left_bracket:
+ $I0 = index $S0, "["
+ if $I0 != -1 goto quote
+
+check_dollar_sign:
+ $I0 = index $S0, "$"
+ if $I0 != -1 goto quote
+
+check_semi_colon:
+ $I0 = index $S0, ";"
+ if $I0 != -1 goto quote
+
+ # \'d constructs
check_right_bracket:
$I0 = index $S0, "]"
if $I0 != -1 goto escape
@@ -50,7 +68,11 @@ check_backslash:
$I0 = index $S0, "\\"
if $I0 != -1 goto escape
- goto check_spaces
+check_quotes:
+ $I0 = index $S0, "\""
+ if $I0 != -1 goto escape
+
+ goto append_elem
escape:
$P0 = new String
@@ -61,26 +83,9 @@ escape:
$P0."replace"("{", "\\{")
$P0."replace"(" ", "\\ ")
$P0."replace"("]", "\\]")
+ $P0."replace"("\"", "\\\"")
- $S0 = $P0
- goto append_elem
-
-check_spaces:
- $I0 = find_whitespace $S0, 0
- if $I0 != -1 goto quote
-
-check_left_bracket:
- $I0 = index $S0, "["
- if $I0 != -1 goto quote
-
-check_dollar_sign:
- $I0 = index $S0, "$"
- if $I0 != -1 goto quote
-
-check_semi_colon:
- $I0 = index $S0, ";"
- if $I0 != -1 goto quote
-
+ $S0 = $P0
goto append_elem
empty:
Added: trunk/languages/tcl/lib/parser.pir
==============================================================================
--- (empty file)
+++ trunk/languages/tcl/lib/parser.pir Mon Aug 1 21:24:40 2005
@@ -0,0 +1,423 @@
+.namespace [ "_Tcl" ]
+
+.sub parse
+ .param string tcl_code
+
+ .local int len
+ len = length tcl_code
+
+ # perform the backslash-newline substitution
+ $I0 = -1
+loop:
+ inc $I0
+ if $I0 >= len goto get_commands
+ $I1 = ord tcl_code, $I0
+ if $I1 != 92 goto loop # \\
+ inc $I0
+ $I2 = $I0
+ $I1 = ord tcl_code, $I2
+ if $I1 != 10 goto loop # \n
+space:
+ inc $I2
+ if $I0 >= len goto get_commands
+ $I1 = is_whitespace tcl_code, $I2
+ if $I1 == 0 goto not_space
+ goto space
+not_space:
+ dec $I0
+ $I1 = $I2 - $I0
+ substr tcl_code, $I0, $I1, " "
+ dec $I1
+ len -= $I1
+ goto loop
+
+get_commands:
+ # an array of commands
+ .local pmc commands
+ commands = new TclList
+
+ # position in the file
+ .local int pos
+ pos = 0
+ # characters that end commands
+ .local pmc chars
+ chars = new Hash
+ chars[10] = 1 # \n
+ chars[59] = 1 # ;
+
+next_command:
+ .local pmc command
+ (command, pos) = get_command(tcl_code, chars, pos)
+ isnull command, done
+
+ push commands, command
+ goto next_command
+
+done:
+ .return(commands)
+.end
+
+.sub get_command
+ .param string tcl_code
+ .param pmc chars
+ .param int pos
+
+get:
+ .local pmc command
+ null command
+
+ # try to get a command name
+ .local pmc word
+ (word, pos) = get_word(tcl_code, chars, pos)
+ isnull word, check
+
+ $I0 = find_type "TclCommand"
+ command = new $I0
+ setattribute command, "TclCommand\x00name", word
+
+next_word:
+ (word, pos) = get_word(tcl_code, chars, pos)
+ isnull word, done
+ push command, word
+ goto next_word
+
+check:
+ $I0 = length tcl_code
+ if pos >= $I0 goto done
+ inc pos
+ goto get
+
+done:
+ inc pos
+ .return(command, pos)
+.end
+
+.sub get_word
+ .param string tcl_code
+ .param pmc chars
+ .param int pos
+ dec pos
+
+ .local int len
+ len = length tcl_code
+
+ .local pmc word
+ null word
+
+eat_space:
+ inc pos
+ if pos >= len goto done
+ $I0 = ord tcl_code, pos
+ $I0 = exists chars[$I0]
+ if $I0 == 1 goto done
+ $I0 = is_whitespace tcl_code, pos
+ if $I0 == 1 goto eat_space
+
+ if pos >= len goto done
+
+ .local pmc dispatch
+ dispatch = new Hash
+ dispatch[ 34] = "get_quote" # "
+ dispatch[123] = "get_brace" # {
+
+parse_word:
+ .local int char
+ char = ord tcl_code, pos
+
+ $I0 = exists dispatch[char]
+ if $I0 == 1 goto dispatch_sub
+
+default:
+ .local int start
+ start = pos
+ $I0 = find_type "TclWord"
+ word = new $I0
+ dec pos
+loop:
+ inc pos
+ if pos >= len goto have_word
+ $I0 = is_whitespace tcl_code, pos
+ if $I0 == 1 goto have_word
+
+ $I0 = ord tcl_code, pos
+ if $I0 == 92 goto backslash # \
+ if $I0 == 36 goto variable # $
+ if $I0 == 91 goto subcommand # [
+ $I0 = exists chars[$I0]
+ if $I0 goto have_word
+ goto loop
+backslash:
+ inc pos
+ goto loop
+variable:
+ $I0 = pos - start
+ if $I0 == 0 goto variable2
+ $S0 = substr tcl_code, start, $I0
+ $I0 = find_type "TclConst"
+ $P0 = new $I0
+ $P0 = $S0
+ push word, $P0
+
+variable2:
+ ($P0, pos) = parse_variable(tcl_code, pos)
+ push word, $P0
+ dec pos
+ start = pos + 1
+ goto loop
+subcommand:
+ $I0 = pos - start
+ if $I0 == 0 goto subcommand2
+ $S0 = substr tcl_code, start, $I0
+ $I0 = find_type "TclConst"
+ $P0 = new $I0
+ $P0 = $S0
+ push word, $P0
+
+subcommand2:
+ ($P0, pos) = get_subcommand(tcl_code, pos)
+ push word, $P0
+
+ start = pos + 1
+ goto loop
+
+have_word:
+ $I0 = pos - start
+ if $I0 == 0 goto done
+ $S0 = substr tcl_code, start, $I0
+ $I0 = find_type "TclConst"
+ $P0 = new $I0
+ $P0 = $S0
+ push word, $P0
+ goto done
+
+done:
+ isnull word, really_done
+ $I0 = word
+ if $I0 != 1 goto really_done
+ word = word[0]
+ goto really_done
+
+dispatch_sub:
+ $S0 = dispatch[char]
+ $P0 = find_name $S0
+ (word, pos) = $P0(tcl_code, pos)
+ inc pos
+
+really_done:
+ .return(word, pos)
+.end
+
+.sub get_quote
+ .param string tcl_code
+ .param int pos
+
+ .local int start
+ start = pos + 1
+ .local int len
+ len = length tcl_code
+
+ .local pmc word
+ $I0 = find_type "TclWord"
+ word = new $I0
+
+loop:
+ inc pos
+ if pos >= len goto missing_quote
+
+ $I0 = ord tcl_code, pos
+ if $I0 == 92 goto backslash # \
+ if $I0 == 36 goto variable # $
+ if $I0 == 91 goto subcommand # [
+ if $I0 == 34 goto done # "
+ goto loop
+backslash:
+ inc pos
+ goto loop
+variable:
+ $I0 = pos - start
+ if $I0 == 0 goto variable2
+ $S0 = substr tcl_code, start, $I0
+ $I0 = find_type "TclConst"
+ $P0 = new $I0
+ $P0 = $S0
+ push word, $P0
+
+variable2:
+ ($P0, pos) = parse_variable(tcl_code, pos)
+ push word, $P0
+ dec pos
+ start = pos + 1
+ goto loop
+subcommand:
+ $I0 = pos - start
+ if $I0 == 0 goto subcommand2
+ $S0 = substr tcl_code, start, $I0
+ $I0 = find_type "TclConst"
+ $P0 = new $I0
+ $P0 = $S0
+ push word, $P0
+
+subcommand2:
+ ($P0, pos) = get_subcommand(tcl_code, pos)
+ push word, $P0
+
+ start = pos + 1
+ goto loop
+
+missing_quote:
+ $P0 = new Exception
+ $P0["_message"] = "missing quote"
+ throw $P0
+
+done:
+ $I0 = pos - start
+ $S0 = substr tcl_code, start, $I0
+ $I0 = find_type "TclConst"
+ $P0 = new $I0
+ $P0 = $S0
+ push word, $P0
+
+ .return(word, pos)
+.end
+
+.sub get_brace
+ .param string tcl_code
+ .param int pos
+
+ .local int start, len
+ start = pos + 1
+ len = length tcl_code
+
+ .local int depth
+ depth = 1
+loop:
+ inc pos
+ if pos >= len goto missing_close_brace
+
+ $I0 = ord tcl_code, pos
+ if $I0 == 92 goto backslash # \
+ if $I0 == 123 goto left # {
+ if $I0 == 125 goto right # }
+ goto loop
+backslash:
+ inc pos
+ goto loop
+left:
+ inc depth
+ goto loop
+right:
+ dec depth
+ if depth == 0 goto done
+ goto loop
+
+missing_close_brace:
+ $P0 = new Exception
+ $P0["_message"] = "missing close-brace"
+ throw $P0
+
+done:
+ $I0 = pos - start
+
+ $S0 = substr tcl_code, start, $I0
+ $P0 = new String
+ $P0 = $S0
+ $P0.replace("\\","\\\\")
+ $S0 = $P0
+ $I0 = find_type "TclConst"
+ $P0 = new $I0
+ $P0 = $S0
+
+ .return($P0, pos)
+.end
+
+.sub get_subcommand
+ .param string tcl_code
+ .param int pos
+ inc pos
+
+ .local pmc chars
+ chars = new Hash
+ chars[93] = 1 # ]
+
+ ($P0, $I0) = get_command(tcl_code, chars, pos)
+ dec $I0
+
+ .return($P0, $I0)
+.end
+
+.sub parse_variable
+ .param string tcl_code
+ .param int pos
+ inc pos
+
+ .local int start
+ .local int len
+ len = length tcl_code
+
+ if pos >= len goto failed
+ $I0 = ord tcl_code, pos
+ if $I0 == 123 goto braces # {
+
+name:
+ start = pos
+ dec pos
+char:
+ inc pos
+ if pos >= len goto check_length
+ $I0 = is_wordchar tcl_code, pos
+ if $I0 goto char
+ $I0 = ord tcl_code, pos
+ if $I0 == 58 goto colon # :
+ if $I0 == 40 goto index #
+ # goto check_length
+
+check_length:
+ len = pos - start
+ if len == 0 goto failed
+ goto done
+
+colon:
+ inc pos
+ $I0 = ord tcl_code, pos
+ if $I0 == 58 goto char
+ dec pos
+ goto check_length
+
+index:
+ pos = index tcl_code, ")", pos
+ if pos == -1 goto missing_paren
+ inc pos
+ goto check_length
+
+failed:
+ $I0 = find_type "TclConst"
+ $P0 = new $I0
+ $P0 = "$"
+ .return($P0, start)
+
+missing_paren:
+ $P0 = new Exception
+ $P0["_message"] = "missing paren"
+ throw $P0
+
+missing_close_brace:
+ $P0 = new Exception
+ $P0["_message"] = "missing close-brace for variable name"
+ throw $P0
+
+braces:
+ inc pos
+ start = pos
+ pos = index tcl_code, "}", start
+ if pos == -1 goto missing_close_brace
+ len = pos - start
+ inc pos
+ # got done
+
+done:
+ $S0 = substr tcl_code, start, len
+ $I0 = find_type "TclVar"
+ $P0 = new $I0
+ $P0 = $S0
+ .return($P0, pos)
+.end
Modified: trunk/languages/tcl/lib/string_to_list.pir
==============================================================================
--- trunk/languages/tcl/lib/string_to_list.pir (original)
+++ trunk/languages/tcl/lib/string_to_list.pir Mon Aug 1 21:24:40 2005
@@ -1,5 +1,3 @@
-# XXX move into a PMC vtable
-
.namespace [ "_Tcl" ]
.sub __stringToList
@@ -10,32 +8,118 @@
.local pmc retval
retval = new TclList
-
- .local pmc parsed_str
- .local pmc parser
- parser = find_global "_Tcl", "parser"
+ .local int pos, len
+ # we're going to increment before we use it, so set it to 0-1
+ pos = -1
+ len = length str
+
+eat_space:
+ inc pos
+ $I0 = is_whitespace str, pos
+ if $I0 == 1 goto eat_space
+
+loop:
+ if pos >= len goto done
- push_eh parse_error
- parsed_str = parser."parse"(str,0,1)
- clear_eh
- register parsed_str
+ # check if the first char is a {
+ $I0 = ord str, pos
+ if $I0 == 123 goto list
+ if $I0 == 34 goto quote
+
+not_list:
+ $I0 = find_whitespace str, pos
+ if $I0 == -1 goto loop_done
- $I0 = parsed_str
- if $I0 == 0 goto done
-
- retval = shift parsed_str
-
- # XXX If there is more than one entry in the parsed_str array, then
- # there's probably an error condition we need to raise.
+ # extract the element
+ $I1 = $I0 - pos
+ $S0 = substr str, pos, $I1
+
+ # add it to the list
+ $P0 = new String
+ $P0 = $S0
+ push retval, $P0
+ # find the next pos
+ pos = $I0
+ goto eat_space
+
+loop_done:
+ # grab the rest of the string
+ $I1 = len - pos
+ $S0 = substr str, pos, $I1
+ $P0 = new String
+ $P0 = $S0
+ push retval, $P0
goto done
+
+ # find the closing '"'
+quote:
+ inc pos
+ $I1 = pos
+quote_loop:
+ $I0 = ord str, $I1
+ if $I0 == 92 goto quote_backslash
+ if $I0 == 34 goto found_quote
+ inc $I1
+ goto quote_loop
+quote_backslash:
+ $I1 += 2
+ goto quote_loop
+found_quote:
+ $I0 = $I1 - pos
+ $S0 = substr str, pos, $I0
+
+ $P0 = new String
+ $P0 = $S0
+ push retval, $P0
+
+ pos = $I1
+ inc pos
+ goto loop
+
+list:
+ .local int depth
+ depth = 1
+ $I1 = pos
+find_close_bracket:
+ inc $I1
+ if $I1 >= len goto unmatched_open_brace
+ $I0 = ord str, $I1
+ if $I0 == 123 goto left_bracket
+ if $I0 == 125 goto right_bracket
+ if $I0 == 92 goto backslash
+ goto find_close_bracket
+backslash:
+ inc $I1
+ goto find_close_bracket
+left_bracket:
+ inc depth
+ goto find_close_bracket
+right_bracket:
+ dec depth
+ if depth == 0 goto found_close_bracket
+ goto find_close_bracket
+
+found_close_bracket:
+ # length -- if we have "{ }", pos and $I0 should both be 1
+ $I0 = $I1 - pos
+ $I0 -= 1
+ inc pos
+ $S0 = substr str, pos, $I0
+ pos += $I0
+ pos += 2
-parse_error:
+ $P0 = new String
+ $P0 = $S0
+ push retval, $P0
+
+ goto loop
+
+unmatched_open_brace:
return_type = TCL_ERROR
- $S0 = P5["_message"]
retval = new String
- retval = $S0
+ retval = "unmatched open brace in list"
# goto done
done:
Added: trunk/languages/tcl/lib/tclcommand.pir
==============================================================================
--- (empty file)
+++ trunk/languages/tcl/lib/tclcommand.pir Mon Aug 1 21:24:40 2005
@@ -0,0 +1,106 @@
+.namespace [ "TclCommand" ]
+
+.HLL "Tcl", "tcl_group"
+
+# return codes
+ .const int TCL_OK = 0
+ .const int TCL_ERROR = 1
+ .const int TCL_RETURN = 2
+ .const int TCL_BREAK = 3
+ .const int TCL_CONTINUE = 4
+
+=head2 __class_init
+
+Define the attributes required for the class.
+
+=cut
+
+.sub __class_init @LOAD
+ $P0 = getclass "TclList"
+ $P1 = subclass $P0, "TclCommand"
+ addattribute $P1, "name"
+.end
+
+=head2 __init
+
+Initialize the attributes for an instance of the class
+
+=cut
+
+.sub __init method
+ $P0 = new TclString
+ setattribute self, "TclCommand\x00name", $P0
+.end
+
+=head2 interpret
+
+Execute the command.
+
+=cut
+
+.sub interpret method
+ .local pmc retval
+ .local int return_type
+ return_type = TCL_OK
+
+ .local string name
+ $P0 = getattribute self, "TclCommand\x00name"
+ (return_type, retval) = $P0.interpret()
+ if return_type != TCL_OK goto done
+ name = retval
+
+ .local int elems, i
+ elems = self
+ i = 0
+
+ .local pmc cmd
+ push_eh no_command
+ $S0 = "&" . name
+ cmd = find_global "Tcl", $S0
+ clear_eh
+
+ # we can't delete commands, so we store deleted commands
+ # as null PMCs
+ isnull cmd, no_command
+
+execute:
+ .local pmc args
+ args = new TclList
+ .local pmc word
+loop:
+ if i == elems goto loop_done
+
+ word = self[i]
+ (return_type, retval) = word.interpret()
+ if return_type != TCL_OK goto done
+
+ push args, retval
+ inc i
+ goto loop
+
+loop_done:
+ (return_type, retval) = cmd(args :flat)
+
+done:
+ .return(return_type, retval)
+
+no_command:
+ $P1 = find_global "Tcl", "$tcl_interactive"
+ unless $P1 goto no_command_non_interactive
+
+ # XXX Should probably make sure this wasn't redefined on us.
+ cmd = find_global "Tcl", "&unknown"
+
+ # Add the command into the unknown handler, and fix our bookkeeping
+ unshift self, name
+ inc elems
+ goto execute
+
+no_command_non_interactive:
+ return_type = TCL_ERROR
+ $S0 = "invalid command name \""
+ $S0 .= name
+ $S0 .= "\""
+ retval = $S0
+ goto done
+.end
Added: trunk/languages/tcl/lib/tclconst.pir
==============================================================================
--- (empty file)
+++ trunk/languages/tcl/lib/tclconst.pir Mon Aug 1 21:24:40 2005
@@ -0,0 +1,87 @@
+.namespace [ "TclConst" ]
+
+.HLL "Tcl", "tcl_group"
+
+# return codes
+ .const int TCL_OK = 0
+ .const int TCL_ERROR = 1
+ .const int TCL_RETURN = 2
+ .const int TCL_BREAK = 3
+ .const int TCL_CONTINUE = 4
+
+=head2 __class_init
+
+Define the attributes required for the class.
+
+=cut
+
+.sub __class_init @LOAD
+ $P0 = getclass "TclString"
+ $P1 = subclass $P0, "TclConst"
+
+ $P0 = new Hash
+ $P0[ 97] = "\a"
+ $P0[ 98] = "\x8" # \b
+ $P0[102] = "\f"
+ $P0[110] = "\n"
+ $P0[114] = "\r"
+ $P0[116] = "\t"
+ $P0[118] = "\v"
+
+ store_global "_Tcl", "backslashes", $P0
+.end
+
+.sub __clone method
+ .local pmc obj
+ $I0 = typeof self
+ obj = new $I0
+ obj = self
+ .return(obj)
+.end
+
+.sub __set_string_native method
+ .param string value
+
+ .local pmc backslashes
+ find_global backslashes, "_Tcl", "backslashes"
+
+ .local int pos
+ pos = 0
+loop:
+ pos = index value, "\\", pos
+ if pos == -1 goto done
+
+ $I0 = pos + 1
+ $I0 = ord value, $I0
+ if $I0 == 111 goto octal # \o
+ $I1 = exists backslashes[$I0]
+ if $I1 goto special
+
+ substr value, pos, 1, ""
+ inc pos
+ goto loop
+
+octal:
+ goto loop
+
+special:
+ $S0 = backslashes[$I0]
+ substr value, pos, 2, $S0
+ inc pos
+ goto loop
+
+done:
+ $I0 = classoffset self, "TclConst"
+ $P0 = getattribute self, $I0
+ $P0 = value
+.end
+
+=head2 interpret
+
+Get the value of the const.
+
+=cut
+
+.sub interpret method
+ .return(TCL_OK, self)
+.end
\ No newline at end of file
Added: trunk/languages/tcl/lib/tclvar.pir
==============================================================================
--- (empty file)
+++ trunk/languages/tcl/lib/tclvar.pir Mon Aug 1 21:24:40 2005
@@ -0,0 +1,34 @@
+.namespace [ "TclVar" ]
+
+.HLL "Tcl", "tcl_group"
+
+# return codes
+ .const int TCL_OK = 0
+ .const int TCL_ERROR = 1
+ .const int TCL_RETURN = 2
+ .const int TCL_BREAK = 3
+ .const int TCL_CONTINUE = 4
+
+=head2 __class_init
+
+Define the attributes required for the class.
+
+=cut
+
+.sub __class_init @LOAD
+ $P0 = getclass "TclConst"
+ $P1 = subclass $P0, "TclVar"
+.end
+
+=head2 interpret
+
+Get the value of the variable.
+
+=cut
+
+.sub interpret method
+ .local pmc read
+ read = find_global "_Tcl", "__read"
+ $S0 = self
+ .return read($S0)
+.end
\ No newline at end of file
Modified: trunk/languages/tcl/lib/tclword.pir
==============================================================================
--- trunk/languages/tcl/lib/tclword.pir (original)
+++ trunk/languages/tcl/lib/tclword.pir Mon Aug 1 21:24:40 2005
@@ -1,47 +1,18 @@
=head1 TclWord
-This object holds the result of parsing a tcl command. Internally,
-It represents a word as discrete chunks, which are either finalized
-or require interpolation. Each chunk is marked as such. When the
-word is I<used> (at interpretation or at execution time), the required
-interpolation occurs (either variable or command)
-
-=head1 Attributes
-
-Each TclWord has the following attributes:
-
-=head2 chunks
-
-an array of pairs of (type, content), where type/content is
-
-=over 4
-
-=item CONST
-
-a string
-
-=item VARIABLE
-
-an array suitable for passing to C<_Tcl::_get_var>
-
-=item COMMAND
-
-the result of a the parse step for a [] command, i.e.
-a TclList of TclWords.
-
-=back
-
-=head2 constant
-
-An Integer PMC flag representing whether or not the value we hold is
-constant. I<Used as a hint at compile time.>
-
=cut
.namespace [ "TclWord" ]
.HLL "Tcl", "tcl_group"
+# return codes
+ .const int TCL_OK = 0
+ .const int TCL_ERROR = 1
+ .const int TCL_RETURN = 2
+ .const int TCL_BREAK = 3
+ .const int TCL_CONTINUE = 4
+
=head1 Methods
TclWord defines the following methods:
@@ -53,506 +24,45 @@ Define the attributes required for the c
=cut
.sub __class_init @LOAD
- newclass $P1, "TclWord"
- addattribute $P1, "chunks"
- addattribute $P1, "constant"
+ $P0 = getclass "TclList"
+ $P1 = subclass $P0, "TclWord"
.end
-=head2 __init
+=head2 interpret
-Initialize the attributes for an instance of the class
+Return a PMC that contains the value of our word, concatenating
+the string values of the elements.
=cut
-.sub __init method
- .local pmc emptyArray
- .local pmc constant
-
- emptyArray = new TclList
-
- setattribute self, "TclWord\x00chunks", emptyArray
- constant = new Integer
- constant = 1
- setattribute self, "TclWord\x00constant", constant
-.end
-
-=head2 clone
-
-Clone a TclWord object.
-
-=cut
-
-.sub __clone method
- .local pmc chunks
- .local pmc constant
-
- chunks = getattribute self, "TclWord\x00chunks"
- constant = getattribute self, "TclWord\x00constant"
-
- chunks = clone chunks
- constant = clone constant
+.sub interpret method
+ .local pmc retval
+ .local int return_type
+ return_type = TCL_OK
- .local pmc value
- $I0 = typeof self
- value = new $I0
- setattribute value, "TclWord\x00chunks", chunks
- setattribute value, "TclWord\x00constant", constant
+ .local int i, len
+ i = 0
+ len = self
- .return(value)
-.end
-
-=head2 concat_words
-
-Given an array of words, append the chunks of a given word to the existing
word
-
-=cut
-
-.sub concat_words method
- .param pmc words
-
- .local pmc word
- .local pmc chunk
-
- .local pmc these_chunks,this_constant
- these_chunks = getattribute self, "TclWord\x00chunks"
- this_constant = getattribute self, "TclWord\x00constant"
-
- .local pmc those_chunks,that_constant
-
- .local int num_words
- .local int word_num
-
- .local int num_chunks
- .local int chunk_num
-
- num_words = words
- word_num = 0
-outer_loop:
- if word_num == num_words goto outer_loop_done
-
- word = words[word_num]
- those_chunks = getattribute word, "TclWord\x00chunks"
- that_constant = getattribute word, "TclWord\x00constant"
-
- num_chunks = those_chunks
- chunk_num = 0
-
- if that_constant goto inner_loop
- this_constant = 0
-
-inner_loop:
- if chunk_num == num_chunks goto inner_loop_done
-
- chunk = those_chunks[chunk_num]
- push these_chunks, chunk
- inc chunk_num
-
- goto inner_loop
-
-inner_loop_done:
- inc word_num
-
-outer_loop_done:
+ .local string word
+ word = ""
+loop:
+ if i == len goto loop_done
-
-.end
-
-=head2 concat_char
-
-Add a constant character to a TclWord
-
-=cut
-
-.sub concat_char method
- .param int arg
-
- .local pmc chunk
- .local pmc chunks
- .local string str
+ $P0 = self[i]
+ (return_type, retval) = $P0.interpret()
+ if return_type != TCL_OK goto done
+ $S0 = retval
+ word .= $S0
- str = chr arg
-
- chunk = new FixedPMCArray
- chunk = 2
- chunk[0] = 0
- chunk[1] = str
-
- chunks = getattribute self, "TclWord\x00chunks"
- push chunks, chunk
-.end
-
-=head2 concat_const
-
-Add a constant string to a TclWord
-
-=cut
-
-.sub concat_const method
- .param string arg
-
- .local pmc chunk
- .local pmc chunks
-
- if arg == "" goto end
- chunk = new FixedPMCArray
- chunk = 2
- chunk[0] = 0
- chunk[1] = arg
-
- chunks = getattribute self, "TclWord\x00chunks"
- push chunks, chunk
-end:
-.end
-
-
-=head2 concat_variable
-
-Add the name of a variable to be interpolated to a TclWord. Takes the name
-of the var, and an optional index for array variables.
-
-=cut
-
-.sub concat_variable method
- .param string var
- .param string idx
-
- .local pmc chunk
- .local pmc chunks
- .local pmc constant
-
- chunk = new ResizablePMCArray
- chunk[0] = 1
- chunk[1] = var
-
- # I2 == # string params.
- if I2 == 1 goto no_index
- chunk[2] = idx
-
-no_index:
- chunks = getattribute self, "TclWord\x00chunks"
- constant = getattribute self, "TclWord\x00constant"
- constant = 0
- push chunks, chunk
-.end
-
-=head2 concat_command
-
-Add a command to be interpolated to a TclWord. Takes the
-text of the command, and stores the parsed version for
-later interpretation.
-
-=cut
-
-.sub concat_command method
- .param string cmd
-
- .local pmc chunk,chunks,parsed_cmd,constant
-
- .local pmc parser
- parser = find_global "_Tcl", "parser"
- parsed_cmd = parser."parse"(cmd,0,0)
- register parsed_cmd
-
- chunk = new FixedPMCArray
- chunk = 2
- chunk[0] = 2
- chunk[1] = parsed_cmd
-
- chunks = getattribute self, "TclWord\x00chunks"
- constant = getattribute self, "TclWord\x00constant"
- constant = 0
- push chunks, chunk
-.end
-
-=head2 __get_pmc
-
-Return a PMC that contains the value of our word. If we're just a command,
-evaluate the command and return the resulting PMC. If we're just a variable,
-return the PMC associated with that variable. In any other case, concat
-the results and return a Stringy PMC.
-
-=cut
-
-.sub __get_pmc method
-
- .local pmc chunks
- chunks = getattribute self, "TclWord\x00chunks"
-
- .local int count
- count = chunks
-
- if count == 1 goto justpmc
- ($I0,$S0) = self.__get_string()
- $P0 = new String
- $P0 = $S0
- .return($I0,$P0)
-
-justpmc:
- .local pmc chunk
- chunk = chunks[0]
- .local int chunk_type
- chunk_type = chunk[0]
- .local pmc chunk_value
- chunk_value = chunk[1]
-
- if chunk_type == 0 goto constant
- if chunk_type == 1 goto variable
-
-command:
- .local pmc interpret
- interpret = find_global "_Tcl", "__interpret"
- ($I0,$P0) = interpret(chunk_value)
- .return($I0,$P0)
-
-constant:
- # 0 == TCL_OK
- .return(0,chunk_value)
-
-variable:
- .local pmc read
- read = find_global "_Tcl", "__read"
- .local pmc get_var
- get_var = find_global "_Tcl", "__get_var"
- .local int return_type
- $S1 = chunk_value
- $S2 = chunk[2]
- if $S2 == "" goto get_variable
- .return get_var($S1,$S2)
-get_variable:
- .return read($S1)
-.end
-
-=head2 __get_string
-
-Stringify - In our case, we take the individual chunks of the words and
-evaluate them - so if we have a TclWord that came from a string like:
-
- "$a + $b = [expr $a + $b]"
-
-We have split it up internally to look like:
-
- VAR: a
- CONST: " + "
- VAR: b
- CONST: " = "
- COMMAND:
- WORD:
- CONST: "expr"
- WORD:
- VAR: a
- WORD:
- CONST: "+"
- WORD:
- VAR: b
-
-And, when we ask for the string representation, the two variable interpolations
-are performed, and the command containing "expr" is also evaluated. The
-resulting string, (assuming values of 1 and 2 for a and b, respectively) is
-
- "1 + 2 = 3"
-
-NB: This isn't quite the normal C<__get_string> method, and should probably be
-renamed - it is returning a tcl exit code in addition to the normal string
-result.
-
-=cut
-
-.sub __get_string method
-
- .local int return_type
-
- return_type = 0
-
- .local pmc chunks
- chunks = getattribute self, "TclWord\x00chunks"
-
- .local pmc interpret
- .local pmc get_var
-
- interpret = find_global "_Tcl", "__interpret"
- get_var = find_global "_Tcl", "__get_var"
-
- .local string retval
- retval = ""
-
- $I1 = chunks
- $P11 = new Integer
- $P11 = 0 # XXX If we don't use a PMC, this value is discarded because of
- # a method call below.
-loop:
- $I0 = $P11
- if $I0 == $I1 goto loop_done
- $P0 = chunks[$I0]
- $I2 = $P0[0]
-
- if $I2 == 0 goto constant
- if $I2 == 1 goto variable
- if $I2 == 2 goto command
-
-command:
- $P1 = $P0[1]
- $S1 = typeof $P1
- ($I0, $P9) = interpret( $P1 )
- $S0 = $P9
- if $I0 == 0 goto loop_next
- # else, an exception value was returned. abort.
- return_type = $I0
- goto loop_done
-
-variable:
- $S1 = $P0[1]
- $S2 = $P0[2]
- if $S2 == "" goto get_variable
- ($I2,$P9) = get_var($S1,$S2)
- goto got_variable
-
-get_variable:
- ($I2,$P9) = get_var($S1)
- $S0 = $P9
-
-got_variable:
- if $I2 == 0 goto loop_next
- return_type = $I2
- retval = $S0
- goto loop_done
-
-constant:
- $S0 = $P0[1]
- # goto loop_next
-
-loop_next:
- retval .= $S0
- $P11 = $P11 + 1
- goto loop
-
-loop_done:
- .return(return_type,retval)
-.end
-
-=head2 __dump
-
-Allow us to be rendered by Data::Dumper
-
-Not tested, uses pmcPerlArray dumper method because of the way Dumper is
written.
-Shouldn't have to.
-
-=cut
-
-.sub __dump method
- .param pmc dumper
- .param string name
-
- .local string subindent
- .local string indent
- (subindent, indent) = dumper."newIndent"()
-
- .local pmc chunks
- chunks = getattribute self, "TclWord\x00chunks"
-
- .local int num_chunks
- num_chunks = chunks
- .local int chunk_num
- chunk_num = 0
-
- print "(size:"
- print num_chunks
- print ") {\n"
-
-loop:
- if chunk_num >= num_chunks goto loop_done
- if chunk_num == 0 goto skip
- print ",\n"
-skip:
-
- $P0 = chunks[chunk_num]
- $I0 = $P0[0]
-
- print subindent
-
- if $I0 == 2 goto command
- if $I0 == 1 goto var
-
- $S0 = $P0[1]
- print "\""
- print $S0
- print "\""
- goto loop_next
-
-command:
- $P1 = $P0[1]
- # XXX This will need to change.
- dumper.pmcPerlArray($P1)
- goto loop_next
-
-var:
- $S0 = $P0[1]
- $S1 = $P0[2]
- if $S1 != "" goto array_var
- print "[ set "
- print $S0
- print " ]"
- goto loop_next
-
-array_var:
- print "[ set "
- print $S0
- print " ("
- print $S1
- print ") ]"
-
-loop_next:
- inc chunk_num
+ inc i
goto loop
loop_done:
- print "\n"
-
- print indent
- print "}"
-
- dumper."deleteIndent"()
-.end
-
-=head2 __get_integer
-
-Return the number of chunks in this tclword.
-
-=cut
-
-.sub __get_integer method
-
- .local pmc chunks
- chunks = getattribute self, "TclWord\x00chunks"
- .local int size
- size = chunks
-
- .return(size)
-.end
-
-=head2 XXX __freeze
-
-Not implemented yet, pending delegation of C<freeze> to objects.
-(Necessary anymore?)
-
-=head2 XXX __thaw
-
-Not implemented yet, pending delegation of C<thaw> to objects.
-(Necessary anymore?)
-
-=cut
-
-=head2 __is_const
-
-Returns an integer, C<1> if this word is constant, C<0> if it requires
-interpolation.
-
-=cut
+ retval = new TclString
+ retval = word
-.sub __is_const method
- .local pmc constant
- constant = getattribute self, "TclWord\x00constant"
- .local int result
- result = constant
- .return(result)
+done:
+ .return(return_type, retval)
.end
Modified: trunk/languages/tcl/t/tcl_command_subst.t
==============================================================================
--- trunk/languages/tcl/t/tcl_command_subst.t (original)
+++ trunk/languages/tcl/t/tcl_command_subst.t Mon Aug 1 21:24:40 2005
@@ -4,7 +4,6 @@ use strict;
use lib qw(tcl/t t . ../lib ../../lib ../../../lib);
use Parrot::Test tests => 10;
use Test::More;
-use vars qw($TODO);
language_output_is("tcl",<<'TCL', <<'OUT',"all");
set a 5
@@ -68,13 +67,9 @@ TCL
2
OUT
-TODO: {
-$TODO = "bugs";
-
language_output_is("tcl",<<'TCL',<<'OUT',"] in \"\"s");
puts [set a "]"]
TCL
]
OUT
-}
Modified: trunk/languages/tcl/tcl.pir
==============================================================================
--- trunk/languages/tcl/tcl.pir (original)
+++ trunk/languages/tcl/tcl.pir Mon Aug 1 21:24:40 2005
@@ -36,8 +36,8 @@
STDIN = getstdin
STDOUT = getstdout
- .local pmc parser,interpret
- parser = find_global "_Tcl", "parser"
+ .local pmc parse,interpret
+ parse = find_global "_Tcl", "parse"
interpret = find_global "_Tcl", "__interpret"
input_loop:
@@ -45,7 +45,7 @@ input_loop:
STDOUT."flush"()
input_line = readline STDIN
unless STDIN goto done
- $P1 = parser."parse"(input_line,0,0)
+ $P1 = parse(input_line)
register $P1
(retcode,retval) = interpret($P1)
# print out the result of the evaluation.
Modified: trunk/languages/tcl/tcl.pir_template
==============================================================================
--- trunk/languages/tcl/tcl.pir_template (original)
+++ trunk/languages/tcl/tcl.pir_template Mon Aug 1 21:24:40 2005
@@ -83,6 +83,9 @@ providing a compreg-compatible method.
.sub __prepare_lib @LOAD,@ANON
# Load any dependant libraries.
+ load_bytecode "languages/tcl/lib/tclcommand.pbc"
+ load_bytecode "languages/tcl/lib/tclconst.pbc"
+ load_bytecode "languages/tcl/lib/tclvar.pbc"
load_bytecode "languages/tcl/lib/tclword.pbc"
load_bytecode "library/Data/Escape.pbc"
load_bytecode "library/PGE.pbc"
@@ -157,12 +160,6 @@ providing a compreg-compatible method.
store_global "_Tcl", "functions", math_funcs
store_global "_Tcl", "precedence", precedence
- # Grab a (for now) global instance of TclParser
- .local pmc parser
- parser = new TclParser
-
- store_global "_Tcl", "parser", parser
-
# Eventually, we'll need to register MMD for the various Tcl PMCs
# (Presuming we don't do this from the .pmc definitions.)
@@ -242,8 +239,10 @@ providing a compreg-compatible method.
pir_code .= " @ANON\n.local string code\ncode = \""
tcl_code = escaper(tcl_code,"\"")
pir_code .= tcl_code
- pir_code .= "\"\n.local pmc parser\n.local pmc tcl_interpret\nparser = new
TclParser"
- pir_code .= "\ntcl_interpret = find_global \"_Tcl\", \"__interpret\"\n$P1 =
parser.\"parse\"(code,0,0)\n.return tcl_interpret($P1)\n.end\n"
+ pir_code .= "\"\n.local pmc tcl_interpret\n.local pmc parse\n"
+ pir_code .= "tcl_interpret = find_global \"_Tcl\", \"__interpret\"\n"
+ pir_code .= "parse = find_global \"_Tcl\", \"parse\"\n"
+ pir_code .= "$P1 = parse(code)\n.return tcl_interpret($P1)\n.end\n"
$P1 = compile pir_compiler, pir_code
.return ($P1)
Modified: trunk/languages/tcl/tcl.pl
==============================================================================
--- trunk/languages/tcl/tcl.pl (original)
+++ trunk/languages/tcl/tcl.pl Mon Aug 1 21:24:40 2005
@@ -33,7 +33,7 @@ my @commands = grep {s/\.pir$//} @cmd_fi
my $lib_dir = "lib";
opendir(LIBDIR,$lib_dir) or die;
-my @libs = map {"$lib_dir/$_"} grep {m/\.pir$/} grep {!
m/^tcl(lib|word).pir$/} readdir(LIBDIR);
+my @libs = map {"$lib_dir/$_"} grep {m/\.pir$/} grep {!
m/^tcl(lib|command|const|var|word).pir$/} readdir(LIBDIR);
closedir(LIBDIR);
my $includes;