changeset 3:0fa786e03744

XSLScript: some preliminary work on conversion. The aproach seems to be wrong though, it looks like the only correct way is to build a tree, and then process the tree. Major changes expected.
author Maxim Dounin <mdounin@mdounin.ru>
date Thu, 20 Feb 2014 19:16:42 +0400
parents bcd96c403898
children eb959dce273b
files xsls.pl
diffstat 1 files changed, 108 insertions(+), 14 deletions(-) [+]
line wrap: on
line diff
--- a/xsls.pl
+++ b/xsls.pl
@@ -36,15 +36,18 @@ my $grammar = <<'EOF';
 # XSLTScript grammar, reconstructed
 
 startrule	: item(s) eofile
-		{ $return = $item[1] }
+	{ $return = $item[1]; 1 }
 
 item		: "<!--" <commit> comment
-		| "!!" <commit> double_exclam
+		| "!!" <commit> exclam_double
 		| "!{" <commit> exclam_xpath
 		| "!" name <commit> exclam_name
 		| "<%" <commit> instruction "%>"
+	{ $return = $item{instruction}; 1 }
 		| "<" name attrs ">" <commit> item(s?) "</" name ">"
+	{ $return = ::format_tag($item{name}, $item{attrs}, $item[6]); 1 }
 		| "<" <commit> name attrs "/" ">"
+	{ $return = ::format_tag($item{name}, $item{attrs}); 1 }
 		| "X:variable" <commit> xvariable
 		| "X:var" <commit> xvariable
 		| "X:template" <commit> xtemplate
@@ -57,6 +60,9 @@ item		: "<!--" <commit> comment
 		| "X:output" <commit> xoutput
 		| "X:copy-of" <commit> xcopyof
 		| instruction <commit> attrs body
+	{ $return = ::format_instruction(
+		$item{instruction}, $item{attrs}, $item{body});
+	1 }
 		| text
 		| <error>
 
@@ -91,27 +97,28 @@ instruction	: "X:stylesheet"
 # likely an artifact of our dump process
 
 comment		: /((?!-->).)*/ms "-->"
-		{ $return = ""; 1; }
+	{ $return = "<!-- " . $item[1] . "-->"; 1; }
 
 # special chars: ', ", {, }, \
 # if used in text, they needs to be escaped with backslash
 
 text		: quoted | unreserved | "'" | "\"" | "{"
 quoted		: "\\" special
-		{ $return = $item{special}; 1; }
+	{ $return = $item{special}; 1; }
 special		: "'" | "\"" | "\\" | "{" | "}"
 unreserved	: /[^'"\\{}]/
 
 # shortcuts:
 #
+# !! for X:apply-templates
 # !{xpath-expression} for X:value-of select="xpath-expression";
-# !! for X:apply-templates
 # !foo() for X:call-template name="foo"
 
 # !root (path = { !{ substring($DIRNAME, 2) } })
 # !root (path = "substring-after($path, '/')")
 
-double_exclam	: value(?) params attrs ";"
+exclam_double	: value(?) params(?) attrs ";"
+	{ $return = ::format_apply($item{value}, $item{params}, $item{attrs}); 1 }
 
 exclam_xpath	: xpath(s?) "}"
 xpath		: /[^}'"]+/
@@ -131,8 +138,8 @@ value		: /"[^"]*"/
 # template parameters
 # ( bar="init", baz={markup} )
 
-params		: "(" param ("," param)(s?) ")"
-		| ""
+params		: "(" param(s /,/) ")" 
+	{ $return = $item[2]; 1 }
 param		: name "=" value
 		| name "=" <commit> "{" item(s) "}"
 		| name
@@ -141,7 +148,9 @@ param		: name "=" value
 # ";" for empty body, "{ ... }" otherwise
 
 body		: ";"
+	{ $return = ""; }
 		| "{" <commit> item(s?) "}"
+	{ $return = join("\n", @{$item[3]}); 1 }
 
 # special handling of some instructions
 # X:if attribute is test=
@@ -153,7 +162,7 @@ xif		: value(?) attrs body "else" <commi
 # X:template name(params) = "match" {
 # X:template name( bar="init", baz={markup} ) = "match" mode="some" {
 
-xtemplate	: name(?) params ( "=" value )(?)
+xtemplate	: name(?) params(?) ( "=" value )(?)
 		  attrs body
 
 # X:var LINK = "/article/@link";
@@ -173,32 +182,48 @@ xparam		: name ("=" value)(?) attrs body
 # X:for-each "link", X:sort "@id" {
 
 xforeach	: value attrs body
+	{ $return = ::format_instruction_value(
+		"X:for-each", "select", $item{value}, $item{attrs}, $item{body});
+	1 }
 		| value attrs "," "X:sort" <commit> value attrs body
 
 # X:sort select
 # X:sort "@id"
 
 xsort		: value attrs body
+	{ $return = ::format_instruction_value(
+		"X:sort", "select", $item{value}, $item{attrs}, $item{body});
+	1 }
 
 # X:when "position() = 1" { ... }
 
 xwhen		: value attrs body
+	{ $return = ::format_instruction_value(
+		"X:when", "test", $item{value}, $item{attrs}, $item{body});
+	1 }
 
 # X:attribute "href" { ... }
 
 xattribute	: value attrs body
+	{ $return = ::format_instruction_value(
+		"X:attribute", "name", $item{value}, $item{attrs}, $item{body});
+	1 }
 
 # X:output
 # semicolon is optional
 
-xoutput		: attrs body
-		| attrs
+xoutput		: attrs body(?)
+	{ $return = ::format_instruction(
+		"X:output", $item{attrs}, $item{body});
+	1 }
 
 # "X:copy-of"
 # semicolon is optional
 
-xcopyof		: value attrs body
-		| value
+xcopyof		: value attrs body(?)
+	{ $return = ::format_instruction_value(
+		"X:copy-of", "select", $item{value}, $item{attrs}, $item{body});
+	1 }
 
 # eof
 
@@ -208,6 +233,74 @@ EOF
 
 ###############################################################################
 
+# helper formatting functions, used by grammar
+
+sub format_instruction {
+	my ($instruction, $attrs, $body) = @_;
+	my $s = "<";
+
+	$instruction =~ s/^X:/xsl:/;
+
+	$s .= join(" ", $instruction, @{$attrs});
+
+	if ($body) {
+		$s .= ">\n" . $body . "\n</" . $instruction . ">\n";
+	} else {
+		$s .= "/>\n";
+	}
+
+	return $s;
+}
+
+sub format_instruction_value {
+	my ($instruction, $name, $value, $attrs, $body) = @_;
+	my $s = "<";
+
+	if ($value) {
+		push(@{$attrs}, "$name=$value");
+	}
+
+	return format_instruction($instruction, $attrs, $body);
+}
+
+sub format_tag {
+	my ($tag, $attrs, $body) = @_;
+	my $s = "\n<";
+
+	$s .= join(" ", $tag, @{$attrs});
+
+	$body = join("\n", @{$body});
+
+	if ($body) {
+		$s .= ">" . $body . "\n</" . $tag . ">\n";
+	} else {
+		$s .= "/>\n";
+	}
+
+	return $s;
+}
+
+sub format_apply {
+	my ($select, $params, $attrs) = @_;
+	my $s = "\n<";
+	my $tag = "xsl:apply-templates";
+
+	if ($select) {
+		unshift "select=$select", @{$attrs};
+	}
+
+	$s .= join(" ", $tag, @{$attrs});
+
+	if ($params) {
+		$params = join("\n", @{$params});
+		$s .= ">\n" . $params . "\n</" . $tag . ">\n";
+	} else {
+		$s .= "/>\n";
+	}
+}
+
+###############################################################################
+
 my $parser = Parse::RecDescent->new($grammar)
 	or die "Failed to create parser.\n";
 
@@ -221,7 +314,8 @@ my $lines;
 my $tree = $parser->startrule($lines)
 	or die "Failed to parse $ARGV.\n";
 
-print Dumper($tree);
+#print Dumper($tree);
+#print join("\n", @{$tree});
 
 ###############################################################################
 ###############################################################################