it's alive, muahhahah

This commit is contained in:
Kyle Maxwell 2008-12-26 15:43:33 -08:00
parent 33c6a2f654
commit 091b7d1fda
10 changed files with 638 additions and 201 deletions

306
dexter.c
View File

@ -68,15 +68,6 @@ xmlDocPtr dex_parse_doc(dexPtr dex, xmlDocPtr doc) {
return xsltApplyStylesheet(dex->stylesheet, doc, NULL);
}
static contextPtr clone_context(contextPtr context) {
contextPtr other;
other = __dex_alloc(sizeof(dex_context));
other->name = astrdup(context->name);
other->group_key = astrdup(context->group_key);
other->full_group_key = astrdup(context->full_group_key);
return other;
}
dexPtr dex_compile(char* dex_str, char* incl) {
dexPtr dex = (dexPtr) calloc(sizeof(compiled_dex), 1);
@ -118,21 +109,16 @@ dexPtr dex_compile(char* dex_str, char* incl) {
sprintbuf(buf, "%s\n", incl);
sprintbuf(buf, "<xsl:template match=\"/\">\n");
sprintbuf(buf, "<dexter:root>\n");
contextPtr context = new_context(json, buf);
__dex_recurse(context);
contextPtr context = __dex_alloc(sizeof(dex_context));
context->name = "root";
context->full_group_key = "";
context->group_key = "";
xslt_keys = "";
__dex_recurse(json, buf, context);
json_object_put(json); // frees json
dex->error = last_dex_error;
sprintbuf(buf, "</dexter:root>\n");
sprintbuf(buf, "</xsl:template>\n");
printf("hi: %s\n", xslt_keys);
sprintbuf(buf, xslt_keys);
sprintbuf(buf, context->key_buf->buf);
sprintbuf(buf, "</xsl:stylesheet>\n");
if(dex->error == NULL) {
@ -147,6 +133,54 @@ dexPtr dex_compile(char* dex_str, char* incl) {
return dex;
}
contextPtr new_context(struct json_object * json, struct printbuf *buf) {
contextPtr c = __dex_alloc(sizeof(dex_context));
c->key_buf = printbuf_new();
sprintbuf(c->key_buf, "");
c->name = "root";
c->tag = "root";
c->full_expr = "/";
c->expr = NULL;
c->magic = NULL;
c->filter = NULL;
c->buf = buf;
c->json = json;
c->parent = NULL;
c->array = 0;
c->string = 0;
c->keys = NULL;
return c;
}
contextPtr deeper_context(contextPtr context, char* key, struct json_object * val) {
contextPtr c = __dex_alloc(sizeof(dex_context));
c->key_buf = context->key_buf;
c->keys = context->keys;
c->tag = __tag(key);
c->array = json_object_is_type(val, json_type_array);
c->json = c->array ? json_object_array_get_idx(val, 0) : val;
c->string = json_object_is_type(c->json, json_type_string);
c->filter = __filter(key);
c->name = astrcat3(context->name, ".", c->tag);
c->magic = ((c->filter == NULL) && c->array && !(c->string)) ? c->name : context->magic;
c->buf = context->buf;
c->expr = c->string ? myparse(astrdup(json_object_get_string(c->json))) : NULL;
c->full_expr = full_expr(context, c->filter);
c->full_expr = full_expr(c, c->expr);
c->expr = filter_intersection(c->magic, c->expr);
c->filter = filter_intersection(c->magic, c->filter);
c->parent = context;
return c;
}
static char* filter_intersection(char* key, char* expr) {
if(key != NULL && expr != NULL) {
return astrcat7("set:intersection(key('", key, "__key', $", key, "__index), ", expr, ")");
} else {
return expr;
}
}
void dex_free(dexPtr ptr) {
if(ptr->error != NULL) free(ptr->error);
if(ptr->stylesheet != NULL) xsltFreeStylesheet(ptr->stylesheet);
@ -157,93 +191,126 @@ void * __dex_alloc(int size) {
return obstack_alloc(&dex_obstack, size);
}
void __dex_recurse_object(struct json_object * json, struct printbuf* buf, contextPtr context) {
json_object_object_foreach(json, key, val) {
__dex_recurse_foreach(json, key, val, buf, context);
}
void yyerror(const char * s) {
struct printbuf *buf = printbuf_new();
if(last_dex_error !=NULL) sprintbuf(buf, "%s\n", last_dex_error);
sprintbuf(buf, "%s in key: %s", s, dex_parsing_context->name);
last_dex_error = strdup(buf->buf);
printbuf_free(buf);
}
static contextPtr deeper_context(contextPtr context, char* tag) {
contextPtr deeper = clone_context(context);
deeper->name = astrcat3(context->name, ".", tag);
return deeper;
}
void __dex_recurse_foreach(struct json_object * json, char* key, struct json_object * val, struct printbuf* buf, contextPtr context) {
char *tag = astrdup(key);;
char* __tag(char* key) {
char *tag = astrdup(key);
char *ptr = tag;
char *expr = astrdup(key);;
while(*ptr++ != '\0'){
if(*ptr == '(') {
*ptr = 0;
return tag;
}
}
return tag;
}
char* __filter(char* key) {
char *expr = astrdup(key);
char *ptr = expr;
int offset = 0;
bool has_expr = false;
struct json_object * inner;
while(*ptr++ != '\0'){
offset++;
if(*ptr == '(') {
*ptr = 0;
has_expr = true;
break;
}
}
expr += offset;
sprintbuf(buf, "<%s>\n", tag);
switch(json_object_get_type(val)) {
case json_type_array:
// printf("arr");
inner = json_object_array_get_idx(val, 0);
switch(json_object_get_type(inner)) {
case json_type_string:
if(has_expr) {
printf("parsing: %s\n", expr);
sprintbuf(buf, "<dexter:groups><xsl:for-each select=\"%s\"><dexter:group>\n", myparse(expr));
printf("error: %s\n", last_dex_error);
__dex_recurse(inner, buf, deeper_context(context, tag));
} else {
printf("parsing: %s\n", json_object_get_string(inner));
sprintbuf(buf, "<dexter:groups><xsl:for-each select=\"%s\"><dexter:group>\n", myparse(json_object_get_string(inner)));
printf("error: %s\n", last_dex_error);
struct json_object * dot = json_object_new_string(".");
__dex_recurse(dot, buf, deeper_context(context, tag));
}
sprintbuf(buf, "</dexter:group></xsl:for-each></dexter:groups>\n");
break;
case json_type_object:
if(has_expr) {
printf("parsing: %s\n", expr);
sprintbuf(buf, "<dexter:groups><xsl:for-each select=\"%s\"><dexter:group>\n", myparse(expr));
printf("error: %s\n", last_dex_error);
__dex_recurse(inner, buf, deeper_context(context, tag));
sprintbuf(buf, "</dexter:group></xsl:for-each></dexter:groups>\n");
} else {
char* inner_expr = inner_key_of(inner);
if(inner_expr == NULL) { // boring, no singleton keys, just maintain structure
sprintbuf(buf, "<dexter:groups><dexter:group>\n");
__dex_recurse(inner, buf, deeper_context(context, tag));
sprintbuf(buf, "</dexter:group></dexter:groups>\n");
} else {
char* group_key = myparse(inner_expr);
contextPtr new_context = deeper_context(context, tag);
new_context->full_group_key = astrcat3(new_context->full_group_key, "//", group_key);
sprintbuf(buf, "<dexter:groups><xsl:for-each select=\"%s\"><dexter:group>\n", group_key);
sprintbuf(buf,
"<xsl:variable name=\"%s_index\" select=\"count(set:intersection(following::*, %s))\"/>\n",
new_context->name, new_context->full_group_key);
__dex_recurse(inner, buf, new_context);
sprintbuf(buf, "</dexter:group></xsl:for-each></dexter:groups>\n");
}
}
break;
}
break;
case json_type_string:
case json_type_object:
__dex_recurse(val, buf, deeper_context(context, tag));
};
sprintbuf(buf, "</%s>\n", tag);
if(!has_expr) return NULL;
expr += offset + 1; // clip "("
int l = strlen(expr);
if(l <= 1) return NULL;
*(expr + l - 1) = 0; // clip ")"
return myparse(expr);
}
char* inner_key_of(struct json_object * json) {
void __dex_recurse(contextPtr context) {
char* tmp;
struct printbuf * buf;
keyPtr keys;
contextPtr c;
json_object_object_foreach(context->json, key, val) {
c = deeper_context(context, key, val);
sprintbuf(c->buf, "<%s>\n", c->tag);
if(c->string) {
if(c->array) {
sprintbuf(c->buf, "<dexter:groups><xsl:for-each select=\"%s\"><dexter:group>\n", c->expr);
sprintbuf(c->buf, "<xsl:value-of select=\".\" />\n");
sprintbuf(c->buf, "</dexter:group></xsl:for-each></dexter:groups>\n");
} else {
sprintbuf(c->buf, "<xsl:value-of select=\"%s\" />\n", c->expr);
}
} else { // if c->object !string
if(c->array) { // scoped
if(c->filter != NULL) {
sprintbuf(c->buf, "<dexter:groups><xsl:for-each select=\"%s\"><dexter:group>\n", c->filter);
__dex_recurse(c);
sprintbuf(c->buf, "</dexter:group></xsl:for-each></dexter:groups>\n");
} else { // magic
sprintbuf(c->buf, "<xsl:variable name=\"%s__context\" select=\".\"/>\n", c->name);
tmp = myparse(astrdup(inner_key_of(c->json)));
sprintbuf(c->buf, "<dexter:groups><xsl:for-each select=\"%s\">\n", filter_intersection(context->magic, tmp));
// keys
keys = __dex_alloc(sizeof(key_node));
keys->name = c->name;
keys->use = full_expr(c, tmp);
keys->next = c->keys;
c->keys = keys;
buf = printbuf_new();
sprintbuf(buf, "concat(");
while(keys != NULL){
sprintbuf(buf, "count(set:intersection(following::*, %s)), '-',", keys->use);
keys = keys->next;
}
sprintbuf(buf, "'')");
tmp = astrdup(buf->buf);
printbuf_free(buf);
sprintbuf(c->key_buf, "<xsl:key name=\"%s__key\" match=\"%s\" use=\"%s\"/>\n", c->name,
full_expr(c, "./descendant-or-self::*"),
tmp
);
sprintbuf(c->buf, "<xsl:variable name=\"%s__index\" select=\"%s\"/>\n", c->name, tmp);
sprintbuf(c->buf, "<xsl:for-each select=\"$%s__context\"><dexter:group>\n", c->name);
__dex_recurse(c);
sprintbuf(c->buf, "</dexter:group></xsl:for-each></xsl:for-each></dexter:groups>\n");
}
} else {
if(c->filter == NULL) {
__dex_recurse(c);
} else {
sprintbuf(c->buf, "<xsl:for-each select=\"%s\"><xsl:if test=\"position() = 1\">\n", c->filter);
__dex_recurse(c);
sprintbuf(c->buf, "</xsl:if></xsl:for-each>\n");
}
}
}
sprintbuf(c->buf, "</%s>\n", c->tag);
}
}
static char* full_expr(contextPtr context, char* expr) {
if(expr == NULL) return context->full_expr;
char* merged = arepl(expr, ".", context->full_expr);
return arepl(merged, "///", "//");
}
static char* inner_key_of(struct json_object * json) {
switch(json_object_get_type(json)) {
case json_type_string:
return json_object_get_string(json);
@ -254,65 +321,10 @@ char* inner_key_of(struct json_object * json) {
}
}
char* inner_key_each(struct json_object * json) {
static char* inner_key_each(struct json_object * json) {
json_object_object_foreach(json, key, val) {
char* inner = inner_key_of(val);
if(inner != NULL) return inner;
}
return NULL;
}
void __dex_recurse_array(struct json_object * json, struct printbuf* buf, contextPtr context) {
printf("WTF!!!!!!!\n");
}
void __dex_recurse_string(struct json_object * json, struct printbuf* buf, contextPtr context) {
char* a = astrdup(json_object_get_string(json));
char* ptr = context->name;
char* last_name = context->name;
char* expr;
while(*ptr++){
if(*ptr == '.') last_name = ptr + 1;
}
dex_parsing_context = context;
expr = myparse(a);
xslt_keys = astrcat8(xslt_keys, "<xsl:key name=\"key-",
context->name,
"\" match=\"",
expr,
"\" use=\"count(set:intersection(following::*, ",
context->full_group_key,
"))\" />");
sprintbuf(buf, "<xsl:variable name=\"%s\" select=\"%s\" />\n", context->name, expr);
sprintbuf(buf, "<xsl:variable name=\"%s\" select=\"$%s\" />\n", last_name, context->name);
sprintbuf(buf, "<xsl:value-of select=\"$%s\" />\n", context->name);
}
void yyerror(const char * s) {
struct printbuf *buf = printbuf_new();
if(last_dex_error !=NULL) sprintbuf(buf, "%s\n", last_dex_error);
sprintbuf(buf, "%s in key: %s", s, dex_parsing_context->name);
last_dex_error = strdup(buf->buf);
printbuf_free(buf);
}
void __dex_recurse(struct json_object * json, struct printbuf* buf, contextPtr context) {
switch(json_object_get_type(json)){
case json_type_object:
__dex_recurse_object(json, buf, context);
break;
case json_type_array:
__dex_recurse_array(json, buf, context);
break;
case json_type_string:
__dex_recurse_string(json, buf, context);
break;
case json_type_boolean:
case json_type_double:
case json_type_int:
default:
fprintf(stderr, "Invalid type in json\n");
exit(1);
}
}

View File

@ -24,20 +24,30 @@ typedef struct __compiled_dex {
char* error;
} compiled_dex;
typedef struct __dex_context {
typedef struct __key_node {
char* name;
char* group_key;
char* full_group_key;
char* use;
struct __key_node * next;
} key_node;
typedef key_node * keyPtr;
typedef struct __dex_context {
struct printbuf * buf;
struct printbuf * key_buf;
keyPtr keys;
struct json_object * json;
struct __dex_context * parent;
char* tag;
char* filter;
char* expr;
char* full_expr;
char* name;
char* magic;
int array;
int string;
} dex_context;
static char* xslt_keys;
// typedef struct __dex_context_node {
// char* key;
// dex_context_node* next;
// } dex_context_node;
//
// typedef dex_context_node * nodePtr;
typedef compiled_dex * dexPtr;
typedef dex_context * contextPtr;
@ -50,15 +60,28 @@ xmlDocPtr dex_parse_string(dexPtr, char*, size_t, boolean);
static xmlDocPtr dex_parse_doc(dexPtr, xmlDocPtr);
void print_variables(struct printbuf *, contextPtr, char*);
void* __dex_alloc(int);
static char* full_expr(contextPtr, char*);
static char* expr_join(char*, char*);
static char* inner_key_of(struct json_object *);
static char* inner_key_each(struct json_object *);
static void free_context(contextPtr);
static contextPtr init_context();
static contextPtr clone_context(contextPtr);
static contextPtr deeper_context(contextPtr, char*);
static void __dex_recurse(struct json_object *, struct printbuf*, contextPtr);
static void __dex_recurse_object(struct json_object *, struct printbuf*, contextPtr);
static void __dex_recurse_array(struct json_object *, struct printbuf*, contextPtr);
static void __dex_recurse_string(struct json_object *, struct printbuf*, contextPtr);
static void __dex_recurse_foreach(struct json_object *, char *, struct json_object *, struct printbuf *, contextPtr);
static contextPtr tagged_context(contextPtr, char*);
contextPtr new_context(struct json_object *, struct printbuf *);
contextPtr deeper_context(contextPtr, char*, struct json_object *);
static char* __tag(char* key);
static char* __filter(char* key);
static void __dex_recurse(contextPtr);
static void __dex_keys(contextPtr);
static char* filter_intersection(char*, char*);
static char* inner_key_of(struct json_object *);
static char* inner_key_each(struct json_object *);
#endif

View File

@ -11,5 +11,4 @@
}]
}]
}]
}
}

View File

@ -143,7 +143,7 @@
<xsl:key name="post-key" match="//*[@id='posts']//li/descendant-or-self::*"
use="concat(count(set:intersection(following::*, //h1)) , '-', count(set:intersection(following::*, //*[@id='posts']//li//h2)))" />
<xsl:key name="comment-key" match="//*[@id='posts']//li/descendant-or-self::*"
use="concat(count(set:intersection(following::*, //h1)), '-',
use="concat(count(set:intersection(following::*, 4)), '-',
count(set:intersection(following::*, //*[@id='posts']//li//h2)), '-',
count(set:intersection(following::*, //*[@id='posts']//li//*[@id='comments']//h3)))" />

11
fixtures/ga.html Normal file
View File

@ -0,0 +1,11 @@
<html>
<body>
<h4>a</h4>
<p>a1</p>
<p>a2</p>
<p>a3</p>
<h4>b</h4>
<p>b1</p>
<p>b2</p>
</body>
</html>

48
fixtures/ga.xslt Normal file
View File

@ -0,0 +1,48 @@
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:dexter="http://kylemaxwell.com/dexter" xmlns:str="http://exslt.org/strings" xmlns:set="http://exslt.org/sets" xmlns:math="http://exslt.org/math" xmlns:func="http://exslt.org/functions" xmlns:user="http://kylemaxwell.com/dexter/user-functions" xmlns:dyn="http://exslt.org/dynamic" xmlns:date="http://exslt.org/dates-and-times" xmlns:exsl="http://exslt.org/common" xmlns:saxon="http://icl.com/saxon" version="1.0" extension-element-prefixes="str math set func dyn exsl saxon user date">
<xsl:output method="xml" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/">
<dexter:root>
<day>
<dexter:groups>
<xsl:for-each select=".//b/h4">
<dexter:group>
<title><xsl:value-of select="key('hafter', last() - position())"/></title>
<entries>
<dexter:groups>
<xsl:for-each select="key('pafter', last() - position())">
<xsl:if test="position() &lt; 5">
<dexter:group><xsl:value-of select="."/></dexter:group>
</xsl:if>
</xsl:for-each>
</dexter:groups>
</entries>
<nest>
<dexter:groups>
<xsl:for-each select="//b">
<xsl:if test="position() &lt; 5">
<dexter:group><xsl:value-of select="."/></dexter:group>
</xsl:if>
</xsl:for-each>
</dexter:groups>
</nest>
</dexter:group>
</xsl:for-each>
</dexter:groups>
</day>
</dexter:root>
</xsl:template>
<xsl:key name="hafter" match="//b/h4" use="count(following::b/h4)" />
<xsl:key name="pafter" match="//p/a" use="count(following::b/h4)" />
<xsl:key name="bafter" match="//b" use="count(following::b/h4)" />
</xsl:stylesheet>

View File

@ -3,39 +3,14 @@
<xsl:output method="xml" indent="yes"/>
<xsl:strip-space elements="*"/>
<!--
{
"page": [{
"title": "h1",
"nav": ["ul#nav li"],
"post(#posts li)": [{
"title": "h2",
"paras": ["p"],
"comments": [{
"title": "#comments h3",
"paras": ["#comments p"]
}]
}]
}]
}
-->
<xsl:template match="node()">
<xsl:copy>
<xsl:attribute name="index"><xsl:value-of select="concat(count(set:intersection(following::*, //h1)), '-',
count(set:intersection(following::*, //*[@id='posts']//li//h2)), '-',
count(set:intersection(following::*, //*[@id='posts']//li//*[@id='comments']//h3)))" /></xsl:attribute>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
<xsl:copy>
<xsl:attribute name="index"><xsl:value-of select="concat(count(set:intersection(following::*, //h1)), '-','')" /></xsl:attribute>
<xsl:apply-templates select="@*|node()" />
</xsl:copy>
</xsl:template>
<xsl:template match="@*" mode="copy">
<xsl:copy-of select="."/>
</xsl:template>
<xsl:template match="@*">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
</xsl:stylesheet>

View File

@ -3,9 +3,27 @@
#include <stdio.h>
#include <stdarg.h>
#include "kstring.h"
#include "printbuf.h"
#include "obstack.h"
#include "dexter.h"
char* arepl(char* orig, char* old, char* new) {
char* ptr = astrdup(orig);
int nlen = strlen(new);
int olen = strlen(old);
char* i;
struct printbuf * buf = printbuf_new();
while((i = strstr(ptr, old)) != NULL) {
printbuf_memappend(buf, ptr, i - ptr);
printbuf_memappend(buf, new, nlen);
ptr = i + olen;
}
printbuf_memappend(buf, ptr, strlen(ptr));
ptr = astrdup(buf->buf);
printbuf_free(buf);
return ptr;
}
char* astrdup(char* c) {
if(c == NULL) return NULL;
return astrcat(c, "");

View File

@ -1,5 +1,6 @@
#ifndef KSTRING_INCLUDED
#define KSTRING_INCLUDED
extern char* arepl(char*, char*, char*);
extern char* astrdup(char*);
extern char* astrcat(char*, char*);
extern char* astrcat3(char*, char*, char*);

350
legacy.txt Normal file
View File

@ -0,0 +1,350 @@
#include <stdio.h>
#include <stdlib.h>
#include <argp.h>
#include <json/json.h>
#include "kstring.h"
#include "obstack.h"
#include "dexter.h"
#include "y.tab.h"
#include "printbuf.h"
#include <string.h>
#include <errno.h>
#include <ctype.h>
#include <stdbool.h>
#include <libxslt/xslt.h>
#include <libxslt/xsltInternals.h>
#include <libxslt/transform.h>
#include <libxml/parser.h>
#include <libxml/HTMLparser.h>
#include <libxml/HTMLtree.h>
#include <libxml/xmlwriter.h>
#include <libexslt/exslt.h>
int yywrap(void){
return 1;
}
xmlDocPtr dex_parse_file(dexPtr dex, char* file, boolean html) {
if(html) {
htmlParserCtxtPtr htmlCtxt = htmlNewParserCtxt();
htmlDocPtr html = htmlCtxtReadFile(htmlCtxt, file, "UTF-8", 3);
if(html == NULL) {
asprintf(&dex->error, "Couldn't parse file: %s\n", file);
return NULL;
}
return dex_parse_doc(dex, html);
} else {
xmlParserCtxtPtr ctxt = xmlNewParserCtxt();
xmlDocPtr xml = xmlCtxtReadFile(ctxt, file, "UTF-8", 3);
if(xml == NULL) {
asprintf(&dex->error, "Couldn't parse file: %s\n", file);
return NULL;
}
return dex_parse_doc(dex, xml);
}
}
xmlDocPtr dex_parse_string(dexPtr dex, char* string, size_t size, boolean html) {
if(html) {
htmlParserCtxtPtr htmlCtxt = htmlNewParserCtxt();
htmlDocPtr html = htmlCtxtReadMemory(htmlCtxt, string, size, "http://foo", "UTF-8", 3);
if(html == NULL) {
asprintf(&dex->error, "Couldn't parse string\n");
return NULL;
}
return dex_parse_doc(dex, html);
} else {
xmlParserCtxtPtr ctxt = xmlNewParserCtxt();
xmlDocPtr xml = xmlCtxtReadMemory(ctxt, string, size, "http://foo", "UTF-8", 3);
if(xml == NULL) {
asprintf(&dex->error, "Couldn't parse string\n");
return NULL;
}
return dex_parse_doc(dex, xml);
}
}
xmlDocPtr dex_parse_doc(dexPtr dex, xmlDocPtr doc) {
return xsltApplyStylesheet(dex->stylesheet, doc, NULL);
}
static contextPtr clone_context(contextPtr context) {
contextPtr other;
other = __dex_alloc(sizeof(dex_context));
other->name = astrdup(context->name);
other->expr = astrdup(context->expr);
other->keys = clone_list(context->keys);
return other;
}
static contextPtr tagged_context(contextPtr context, char* tag) {
contextPtr other = clone_context(context);
other->name = astrcat3(context->name, ".", tag);
return other;
}
static contextPtr init_context() {
contextPtr other;
other = __dex_alloc(sizeof(dex_context));
other->name = "root";
other->expr = "/";
other->keys = NULL;
return other;
}
static char* inner_key_of(struct json_object * json) {
switch(json_object_get_type(json)) {
case json_type_string:
return json_object_get_string(json);
case json_type_array:
return NULL;
case json_type_object:
return inner_key_each(json);
}
}
static char* inner_key_each(struct json_object * json) {
json_object_object_foreach(json, key, val) {
char* inner = inner_key_of(val);
if(inner != NULL) return inner;
}
return NULL;
}
static strsPtr clone_list(strsPtr list) {
if(list == NULL) return NULL;
strsPtr other = __dex_alloc(sizeof(strs));
other->direction = list->direction;
other->name = astrdup(list->name);
other->expr = astrdup(list->expr);
other->next = clone_list(list->next);
return other;
}
dexPtr dex_compile(char* dex_str, char* incl) {
dexPtr dex = (dexPtr) calloc(sizeof(compiled_dex), 1);
if(last_dex_error != NULL) {
free(last_dex_error);
last_dex_error = NULL;
}
if(!dex_exslt_registered) {
exsltRegisterAll();
dex_exslt_registered = true;
}
obstack_init(&dex_obstack);
struct json_object *json = json_tokener_parse(dex_str);
if(is_error(json)) {
dex->error = strdup("Your dex is not valid json.");
return dex;
}
struct printbuf* buf = printbuf_new();
sprintbuf(buf, "<xsl:stylesheet version=\"1.0\" xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\"");
sprintbuf(buf, " xmlns:dexter=\"http://kylemaxwell.com/dexter\"");
sprintbuf(buf, " xmlns:str=\"http://exslt.org/strings\"");
sprintbuf(buf, " xmlns:set=\"http://exslt.org/sets\"");
sprintbuf(buf, " xmlns:math=\"http://exslt.org/math\"");
sprintbuf(buf, " xmlns:func=\"http://exslt.org/functions\"");
sprintbuf(buf, " xmlns:user=\"http://kylemaxwell.com/dexter/user-functions\"");
sprintbuf(buf, " xmlns:dyn=\"http://exslt.org/dynamic\"");
sprintbuf(buf, " xmlns:date=\"http://exslt.org/dates-and-times\"");
sprintbuf(buf, " xmlns:exsl=\"http://exslt.org/common\"");
sprintbuf(buf, " xmlns:saxon=\"http://icl.com/saxon\"");
sprintbuf(buf, " extension-element-prefixes=\"str math set func dyn exsl saxon user date\"");
sprintbuf(buf, ">\n");
sprintbuf(buf, "<xsl:output method=\"xml\" indent=\"yes\"/>\n");
sprintbuf(buf, "<xsl:strip-space elements=\"*\"/>\n");
sprintbuf(buf, "%s\n", incl);
sprintbuf(buf, "<xsl:template match=\"/\">\n");
sprintbuf(buf, "<dexter:root>\n");
contextPtr context = init_context();
xslt_keys = "<!-- keys -->";
next_context = 0;
__dex_simple_single_object(json, buf, context);
json_object_put(json); // frees json
dex->error = last_dex_error;
sprintbuf(buf, "</dexter:root>\n");
sprintbuf(buf, "</xsl:template>\n");
sprintbuf(buf, xslt_keys);
sprintbuf(buf, "</xsl:stylesheet>\n");
if(dex->error == NULL) {
xmlParserCtxtPtr ctxt = xmlNewParserCtxt();
xmlDocPtr doc = xmlCtxtReadMemory(ctxt, buf->buf, buf->size, "http://kylemaxwell.com/some-dex", "UTF-8", 3);
dex->stylesheet = xsltParseStylesheetDoc(doc);
}
printbuf_free(buf);
obstack_free(&dex_obstack, NULL);
return dex;
}
void dex_free(dexPtr ptr) {
if(ptr->error != NULL) free(ptr->error);
if(ptr->stylesheet != NULL) xsltFreeStylesheet(ptr->stylesheet);
free(ptr);
}
void * __dex_alloc(int size) {
return obstack_alloc(&dex_obstack, size);
}
void yyerror(const char * s) {
struct printbuf *buf = printbuf_new();
if(last_dex_error !=NULL) sprintbuf(buf, "%s\n", last_dex_error);
sprintbuf(buf, "%s in key: %s", s, dex_parsing_context->name);
last_dex_error = strdup(buf->buf);
printbuf_free(buf);
}
char* __tag(char* key) {
char *tag = astrdup(key);
char *ptr = tag;
while(*ptr++ != '\0'){
if(*ptr == '(') {
*ptr = 0;
return tag;
}
}
return tag;
}
char* __filter(char* key) {
char *expr = astrdup(key);
char *ptr = expr;
int offset = 0;
bool has_expr = false;
while(*ptr++ != '\0'){
offset++;
if(*ptr == '(') {
has_expr = true;
break;
}
}
if(!has_expr) return NULL;
expr += offset + 1; // clip "("
int l = strlen(expr);
if(l <= 1) return NULL;
*(expr + l - 1) = 0; // clip ")"
return myparse(expr);
}
void __dex_simple_single_object(struct json_object * json, struct printbuf* buf, contextPtr orig_context) {
char* tag;
char* filter;
struct json_object * inner;
int contains_object;
contextPtr context;
json_object_object_foreach(json, key, val) {
// printf("a\n");
tag = __tag(key);
filter = __filter(key);
sprintbuf(buf, "<%s>\n", tag);
// printf("b\n");
context = tagged_context(orig_context, tag);
switch(json_object_get_type(val)){
case json_type_object:
if(filter) {
// printf("c\n");
printf("WTF!\n");
} else {
// printf("d\n");
__dex_simple_single_object(val, buf, context);
}
break;
case json_type_string:
if(filter != NULL) {
printf("WTF!!!!!!!\n");
} else {
// printf("e\n");
__dex_simple_single_string(val, buf, context);
}
break;
case json_type_array:
// printf("q: %s\n", filter);
inner = json_object_array_get_idx(val, 0);
contains_object = json_object_is_type(inner, json_type_object);
if(filter){
if(contains_object) {
// printf("f\n");
__dex_filter_array_object(inner, buf, context, filter);
} else {
printf("WTF!!!!!!!\n");
}
} else {
if(contains_object) {
// printf("g\n");
__dex_magic_array_object(inner, buf, context);
} else {
// printf("h\n");
__dex_simple_array_string(inner, buf, context);
}
}
break;
case json_type_boolean:
case json_type_double:
case json_type_int:
default:
fprintf(stderr, "Invalid type in json\n");
exit(1);
}
sprintbuf(buf, "</%s>\n", tag);
}
}
static void __dex_simple_single_string(struct json_object * json, struct printbuf * buf, contextPtr context){
char* expr = myparse(astrdup(json_object_get_string(json)));
sprintbuf(buf, "<xsl:variable name=\"%s\" select=\"%s\" />\n", context->name, expr);
sprintbuf(buf, "<xsl:variable name=\"%s\" select=\"$%s\" />\n", __tag(context->name), context->name);
sprintbuf(buf, "<xsl:value-of select=\"$%s\" />\n", context->name);
}
static void __dex_filter_array_object(struct json_object * json, struct printbuf * buf, contextPtr context, char* filter){
sprintbuf(buf, "<dexter:groups><xsl:for-each select=\"%s\"><dexter:group>\n", filter);
__dex_simple_single_object(json, buf, context);
sprintbuf(buf, "</dexter:group></xsl:for-each></dexter:groups>\n");
}
static void __dex_magic_array_object(struct json_object * json, struct printbuf * buf, contextPtr context){
char* expr = myparse(astrdup(inner_key_of(json)));
sprintbuf(buf, "<dexter:groups><xsl:for-each select=\"%s\"><dexter:group>\n", expr);
sprintbuf(buf, "<xsl:variable name=\"%s__index\" select=\"count(set:intersection(following::*, .|.|.|%s))\" />", context->name, expr);
// <title><xsl:value-of select="key('page-key', $page_index)/h1" /></title>
__dex_simple_single_object(json, buf, context);
sprintbuf(buf, "</dexter:group></xsl:for-each></dexter:groups>\n");
}
static void __dex_simple_array_string(struct json_object * json, struct printbuf * buf, contextPtr context){
char* expr = myparse(astrdup(json_object_get_string(json)));
sprintbuf(buf, "<xsl:variable name=\"%s\" select=\"%s\" />\n", context->name, expr);
sprintbuf(buf, "<xsl:variable name=\"%s\" select=\"$%s\" />\n", __tag(context->name), context->name);
sprintbuf(buf, "<dexter:groups><xsl:for-each select=\"$%s\"><dexter:group>\n", context->name);
sprintbuf(buf, "<xsl:value-of select=\".\" />\n", context->name);
sprintbuf(buf, "</dexter:group></xsl:for-each></dexter:groups>\n");
}
static char* full_expr(contextPtr context, char* expr){
return expr_join(context->expr, expr);
}
static char* expr_join(char* base, char* expr) {
return astrcat3(base, " | ", expr);
}