summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGerman M. Bravo <german.mb@deipi.com>2011-12-24 05:31:24 -0600
committerGerman M. Bravo <german.mb@deipi.com>2011-12-24 05:31:24 -0600
commit5d30d48dfb6c6c7535e46d2fd7852753d3452fe2 (patch)
treef0ed6c03af09f65b4935092884b38f3c56e66cc4
parent7153bb433bffacbb0a651e8ed26a504b40d83e06 (diff)
downloadpyscss-5d30d48dfb6c6c7535e46d2fd7852753d3452fe2.tar.gz
Added CTypes version (but it's slower)...
-rw-r--r--scss/src/_scss.c262
-rw-r--r--scss/src/_scss_c/__init__.py144
-rw-r--r--scss/src/_scss_c/__init__.pycbin0 -> 5281 bytes
-rw-r--r--scss/src/_scss_c/_scss_c.c528
-rwxr-xr-xscss/src/_scss_c/_scss_c.sobin0 -> 13688 bytes
-rwxr-xr-xscss/src/_scss_c/build.py76
-rw-r--r--scss/src/scanner.py60
7 files changed, 951 insertions, 119 deletions
diff --git a/scss/src/_scss.c b/scss/src/_scss.c
index 1639dfe..85b42dd 100644
--- a/scss/src/_scss.c
+++ b/scss/src/_scss.c
@@ -11,7 +11,7 @@
#include <Python.h>
/* Counter type */
-staticforward PyTypeObject scss_LocateBlocksType;
+staticforward PyTypeObject scss_BlockLocatorType;
#undef DEBUG
@@ -44,11 +44,21 @@ void repr(char *str, char *str2) {
}
typedef struct {
+ int error;
+ int lineno;
+ char *selprop;
+ int selprop_sz;
+ char *codestr;
+ int codestr_sz;
+} scss_Block;
+
+typedef struct {
PyObject_HEAD
+ char *exc;
+ char *_codestr;
char *codestr;
char *codestr_ptr;
int codestr_sz;
- char *exc;
int lineno;
int par;
char instr;
@@ -60,17 +70,8 @@ typedef struct {
char *lose;
char *start;
char *end;
-} scss_LocateBlocks;
-
-
-typedef struct {
- int valid;
- int lineno;
- char *selprop;
- int selprop_sz;
- char *codestr;
- int codestr_sz;
-} scss_Block;
+ scss_Block block;
+} scss_BlockLocator;
int _strip(char *begin, char *end, int *lineno) {
@@ -140,10 +141,10 @@ int _strip(char *begin, char *end, int *lineno) {
}
-typedef void scss_Callback(scss_LocateBlocks*, scss_Block*);
+typedef void scss_Callback(scss_BlockLocator*);
-void _start_string(scss_LocateBlocks *self, scss_Block *b) {
+void _start_string(scss_BlockLocator *self) {
#ifdef DEBUG
PySys_WriteStderr("_start_string\n");
#endif
@@ -151,7 +152,7 @@ void _start_string(scss_LocateBlocks *self, scss_Block *b) {
self->instr = *(self->codestr_ptr);
}
-void _end_string(scss_LocateBlocks *self, scss_Block *b) {
+void _end_string(scss_BlockLocator *self) {
#ifdef DEBUG
PySys_WriteStderr("_end_string\n");
#endif
@@ -159,7 +160,7 @@ void _end_string(scss_LocateBlocks *self, scss_Block *b) {
self->instr = 0;
}
-void _start_parenthesis(scss_LocateBlocks *self, scss_Block *b) {
+void _start_parenthesis(scss_BlockLocator *self) {
#ifdef DEBUG
PySys_WriteStderr("_start_parenthesis\n");
#endif
@@ -169,14 +170,14 @@ void _start_parenthesis(scss_LocateBlocks *self, scss_Block *b) {
self->safe = self->codestr_ptr + 1;
}
-void _end_parenthesis(scss_LocateBlocks *self, scss_Block *b) {
+void _end_parenthesis(scss_BlockLocator *self) {
#ifdef DEBUG
PySys_WriteStderr("_end_parenthesis\n");
#endif
self->par--;
}
-void _flush_properties(scss_LocateBlocks *self, scss_Block *b) {
+void _flush_properties(scss_BlockLocator *self) {
#ifdef DEBUG
PySys_WriteStderr("_flush_properties\n");
#endif
@@ -189,18 +190,18 @@ void _flush_properties(scss_LocateBlocks *self, scss_Block *b) {
self->lineno = lineno;
}
- b->selprop = self->lose;
- b->selprop_sz = len;
- b->codestr = NULL;
- b->codestr_sz = 0;
- b->lineno = self->lineno;
- b->valid = 1;
+ self->block.selprop = self->lose;
+ self->block.selprop_sz = len;
+ self->block.codestr = NULL;
+ self->block.codestr_sz = 0;
+ self->block.lineno = self->lineno;
+ self->block.error = -1;
}
self->lose = self->init;
}
}
-void _start_block1(scss_LocateBlocks *self, scss_Block *b) {
+void _start_block1(scss_BlockLocator *self) {
#ifdef DEBUG
PySys_WriteStderr("_start_block1\n");
#endif
@@ -212,13 +213,13 @@ void _start_block1(scss_LocateBlocks *self, scss_Block *b) {
if (self->thin != NULL && _strip(self->thin, self->codestr_ptr, NULL)) {
self->init = self->thin;
}
- _flush_properties(self, b);
+ _flush_properties(self);
self->thin = NULL;
}
self->depth++;
}
-void _start_block(scss_LocateBlocks *self, scss_Block *b) {
+void _start_block(scss_BlockLocator *self) {
#ifdef DEBUG
PySys_WriteStderr("_start_block\n");
#endif
@@ -226,7 +227,7 @@ void _start_block(scss_LocateBlocks *self, scss_Block *b) {
self->depth++;
}
-void _end_block1(scss_LocateBlocks *self, scss_Block *b) {
+void _end_block1(scss_BlockLocator *self) {
#ifdef DEBUG
PySys_WriteStderr("_end_block1\n");
#endif
@@ -240,12 +241,12 @@ void _end_block1(scss_LocateBlocks *self, scss_Block *b) {
self->lineno = lineno;
}
- b->selprop = self->init;
- b->selprop_sz = len;
- b->codestr = (self->start + 1);
- b->codestr_sz = (int)(self->end - (self->start + 1));
- b->lineno = self->lineno;
- b->valid = 1;
+ self->block.selprop = self->init;
+ self->block.selprop_sz = len;
+ self->block.codestr = (self->start + 1);
+ self->block.codestr_sz = (int)(self->end - (self->start + 1));
+ self->block.lineno = self->lineno;
+ self->block.error = -1;
self->init = self->safe = self->lose = self->end + 1;
self->thin = NULL;
@@ -253,7 +254,7 @@ void _end_block1(scss_LocateBlocks *self, scss_Block *b) {
self->skip = 0;
}
-void _end_block(scss_LocateBlocks *self, scss_Block *b) {
+void _end_block(scss_BlockLocator *self) {
#ifdef DEBUG
PySys_WriteStderr("_end_block\n");
#endif
@@ -261,7 +262,7 @@ void _end_block(scss_LocateBlocks *self, scss_Block *b) {
self->depth--;
}
-void _end_property(scss_LocateBlocks *self, scss_Block *b) {
+void _end_property(scss_BlockLocator *self) {
#ifdef DEBUG
PySys_WriteStderr("_end_property\n");
#endif
@@ -275,19 +276,19 @@ void _end_property(scss_LocateBlocks *self, scss_Block *b) {
self->lineno = lineno;
}
- b->selprop = self->lose;
- b->selprop_sz = len;
- b->codestr = NULL;
- b->codestr_sz = 0;
- b->lineno = self->lineno;
- b->valid = 1;
+ self->block.selprop = self->lose;
+ self->block.selprop_sz = len;
+ self->block.codestr = NULL;
+ self->block.codestr_sz = 0;
+ self->block.lineno = self->lineno;
+ self->block.error = -1;
}
self->init = self->safe = self->lose = self->codestr_ptr + 1;
}
self->thin = NULL;
}
-void _mark_safe(scss_LocateBlocks *self, scss_Block *b) {
+void _mark_safe(scss_BlockLocator *self) {
#ifdef DEBUG
PySys_WriteStderr("_mark_safe\n");
#endif
@@ -299,7 +300,7 @@ void _mark_safe(scss_LocateBlocks *self, scss_Block *b) {
self->safe = self->codestr_ptr + 1;
}
-void _mark_thin(scss_LocateBlocks *self, scss_Block *b) {
+void _mark_thin(scss_BlockLocator *self) {
#ifdef DEBUG
PySys_WriteStderr("_mark_thin\n");
#endif
@@ -386,57 +387,98 @@ void init_function_map(void) {
/* constructor */
static PyObject *
-scss_LocateBlocks_new(char *codestr, int codestr_sz)
+scss_BlockLocator_new(char *codestr, int codestr_sz)
{
- scss_LocateBlocks *object;
- object = PyObject_New(scss_LocateBlocks, &scss_LocateBlocksType);
-
- if (object) {
- object->codestr = (char *)PyMem_Malloc(codestr_sz);
- memcpy(object->codestr, codestr, codestr_sz);
- object->codestr_ptr = object->codestr;
- object->codestr_sz = codestr_sz;
- object->exc = NULL;
- object->lineno = 0;
- object->par = 0;
- object->instr = 0;
- object->depth = 0;
- object->skip = 0;
- object->thin = object->codestr;
- object->init = object->codestr;
- object->safe = object->codestr;
- object->lose = object->codestr;
- object->start = NULL;
- object->end = NULL;
+ scss_BlockLocator *self;
+
+ init_function_map();
+
+ self = PyObject_New(scss_BlockLocator, &scss_BlockLocatorType);;
+ if (self) {
+ self->_codestr = (char *)malloc(codestr_sz);
+ memcpy(self->_codestr, codestr, codestr_sz);
+ self->codestr_sz = codestr_sz;
+ self->codestr = (char *)malloc(self->codestr_sz);
+ memcpy(self->codestr, self->_codestr, self->codestr_sz);
+ self->codestr_ptr = self->codestr;
+ self->lineno = 0;
+ self->par = 0;
+ self->instr = 0;
+ self->depth = 0;
+ self->skip = 0;
+ self->thin = self->codestr;
+ self->init = self->codestr;
+ self->safe = self->codestr;
+ self->lose = self->codestr;
+ self->start = NULL;
+ self->end = NULL;
+ self->exc = NULL;
+
+ #ifdef DEBUG
+ PySys_WriteStderr("Scss BlockLocator object initialized! (%lu)\n", sizeof(scss_BlockLocator));
+ #endif
}
- return (PyObject *)object;
+ return (PyObject *)self;
}
static void
-scss_LocateBlocks_dealloc(scss_LocateBlocks *self)
+scss_BlockLocator_rewind(scss_BlockLocator *self)
{
- PyMem_Free(self->codestr);
+ free(self->codestr);
+ self->codestr = (char *)malloc(self->codestr_sz);
+ memcpy(self->codestr, self->_codestr, self->codestr_sz);
+ self->codestr_ptr = self->codestr;
+ self->lineno = 0;
+ self->par = 0;
+ self->instr = 0;
+ self->depth = 0;
+ self->skip = 0;
+ self->thin = self->codestr;
+ self->init = self->codestr;
+ self->safe = self->codestr;
+ self->lose = self->codestr;
+ self->start = NULL;
+ self->end = NULL;
+ self->exc = NULL;
+
+ #ifdef DEBUG
+ PySys_WriteStderr("Scss BlockLocator object rewound!\n");
+ #endif
+}
+
+static void
+scss_BlockLocator_dealloc(scss_BlockLocator *self)
+{
+ free(self->codestr);
+ free(self->_codestr);
+
self->ob_type->tp_free((PyObject*)self);
+
+ #ifdef DEBUG
+ PySys_WriteStderr("Scss BlockLocator object destroyed!\n");
+ #endif
}
/*****/
-scss_LocateBlocks*
-scss_LocateBlocks_iter(scss_LocateBlocks *self)
+scss_BlockLocator*
+scss_BlockLocator_iter(scss_BlockLocator *self)
{
Py_INCREF(self);
return self;
}
PyObject*
-scss_LocateBlocks_iternext(scss_LocateBlocks *self)
+scss_BlockLocator_iternext(scss_BlockLocator *self)
{
scss_Callback *fn;
char c = 0;
- scss_Block b;
char *codestr_end = self->codestr + self->codestr_sz;
+
+ memset(&self->block, 0, sizeof(scss_Block));
+
while (self->codestr_ptr < codestr_end) {
c = *(self->codestr_ptr);
if (!c) {
@@ -445,6 +487,7 @@ scss_LocateBlocks_iternext(scss_LocateBlocks *self)
}
repeat:
+
fn = scss_function_map[
(int)c +
256 * self->instr +
@@ -452,10 +495,8 @@ scss_LocateBlocks_iternext(scss_LocateBlocks *self)
256 * 256 * 2 * (int)(self->depth > 1 ? 2 : self->depth)
];
- b.valid = 0;
-
if (fn != NULL) {
- fn(self, &b);
+ fn(self);
}
self->codestr_ptr++;
@@ -463,23 +504,48 @@ scss_LocateBlocks_iternext(scss_LocateBlocks *self)
self->codestr_ptr = codestr_end;
}
- if (b.valid) {
+ if (self->block.error) {
+ #ifdef DEBUG
+ if (self->block.error < 0) {
+ PySys_WriteStderr("Block found!\n");
+ } else {
+ PySys_WriteStderr("Exception!\n");
+ }
+ #endif
return Py_BuildValue(
"is#s#",
- b.lineno,
- b.selprop,
- b.selprop_sz,
- b.codestr,
- b.codestr_sz
+ self->block.lineno,
+ self->block.selprop,
+ self->block.selprop_sz,
+ self->block.codestr,
+ self->block.codestr_sz
);
}
}
if (self->par > 0) {
- if (self->exc == NULL) self->exc = "Missing closing parenthesis somewhere in block";
+ if (self->block.error <= 0) {
+ self->block.error = 1;
+ self->exc = "Missing closing parenthesis somewhere in block";
+ #ifdef DEBUG
+ PySys_WriteStderr("%s\n", self->exc);
+ #endif
+ }
} else if (self->instr != 0) {
- if (self->exc == NULL) self->exc = "Missing closing string somewhere in block";
+ if (self->block.error <= 0) {
+ self->block.error = 2;
+ self->exc = "Missing closing string somewhere in block";
+ #ifdef DEBUG
+ PySys_WriteStderr("%s\n", self->exc);
+ #endif
+ }
} else if (self->depth > 0) {
- if (self->exc == NULL) self->exc = "Block never closed";
+ if (self->block.error <= 0) {
+ self->block.error = 3;
+ self->exc = "Missing closing string somewhere in block";
+ #ifdef DEBUG
+ PySys_WriteStderr("%s\n", self->exc);
+ #endif
+ }
if (self->init < codestr_end) {
c = '}';
goto repeat;
@@ -491,6 +557,8 @@ scss_LocateBlocks_iternext(scss_LocateBlocks *self)
goto repeat;
}
+ scss_BlockLocator_rewind(self);
+
if (self->exc) {
PyErr_SetString(PyExc_Exception, self->exc);
return NULL;
@@ -504,13 +572,13 @@ scss_LocateBlocks_iternext(scss_LocateBlocks *self)
/* Type definition */
-static PyTypeObject scss_LocateBlocksType = {
+static PyTypeObject scss_BlockLocatorType = {
PyObject_HEAD_INIT(NULL)
0, /* ob_size */
- "scss._LocateBlocks", /* tp_name */
- sizeof(scss_LocateBlocks), /* tp_basicsize */
+ "scss._BlockLocator", /* tp_name */
+ sizeof(scss_BlockLocator), /* tp_basicsize */
0, /* tp_itemsize */
- (destructor)scss_LocateBlocks_dealloc, /* tp_dealloc */
+ (destructor)scss_BlockLocator_dealloc, /* tp_dealloc */
0, /* tp_print */
0, /* tp_getattr */
0, /* tp_setattr */
@@ -526,13 +594,13 @@ static PyTypeObject scss_LocateBlocksType = {
0, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_ITER, /* tp_flags */
- "Internal LocateBlocks iterator object.", /* tp_doc */
+ "Internal BlockLocator iterator object.", /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
- (getiterfunc)scss_LocateBlocks_iter, /* tp_iter: __iter__() method */
- (iternextfunc)scss_LocateBlocks_iternext, /* tp_iternext: next() method */
+ (getiterfunc)scss_BlockLocator_iter, /* tp_iter: __iter__() method */
+ (iternextfunc)scss_BlockLocator_iternext, /* tp_iternext: next() method */
};
@@ -547,7 +615,7 @@ scss_locate_blocks(PyObject *self, PyObject *args)
int codestr_sz;
if (PyArg_ParseTuple(args, "s#", &codestr, &codestr_sz)) {
- result = scss_LocateBlocks_new(codestr, codestr_sz);
+ result = scss_BlockLocator_new(codestr, codestr_sz);
}
return result;
@@ -569,14 +637,14 @@ init_scss(void)
{
PyObject* m;
- scss_LocateBlocksType.tp_new = PyType_GenericNew;
- if (PyType_Ready(&scss_LocateBlocksType) < 0)
+ scss_BlockLocatorType.tp_new = PyType_GenericNew;
+ if (PyType_Ready(&scss_BlockLocatorType) < 0)
return;
m = Py_InitModule("_scss", scssMethods);
init_function_map();
- Py_INCREF(&scss_LocateBlocksType);
- PyModule_AddObject(m, "_LocateBlocks", (PyObject *)&scss_LocateBlocksType);
+ Py_INCREF(&scss_BlockLocatorType);
+ PyModule_AddObject(m, "_BlockLocator", (PyObject *)&scss_BlockLocatorType);
}
diff --git a/scss/src/_scss_c/__init__.py b/scss/src/_scss_c/__init__.py
new file mode 100644
index 0000000..6812b8b
--- /dev/null
+++ b/scss/src/_scss_c/__init__.py
@@ -0,0 +1,144 @@
+# -*- coding: utf-8 -*-
+
+import sys
+from ctypes import *
+from os.path import join, dirname
+
+if sys.platform == 'win32':
+ ext = 'dll'
+else:
+ ext = 'so'
+
+_scss = cdll.LoadLibrary(join(dirname(__file__), '_scss_c.%s' % ext))
+
+
+########################################
+# the Block struct
+########################################
+
+class Block(Structure):
+ _fields_ = [
+ ('_error', c_int),
+ ('_lineno', c_int),
+ ('_selprop', POINTER(c_char)),
+ ('_selprop_sz', c_int),
+ ('_codestr', POINTER(c_char)),
+ ('_codestr_sz', c_int),
+ ]
+
+ def lineno_get(self):
+ return self._lineno
+
+ def lineno_set(self, value):
+ raise AttributeError('lineno attribute is read only')
+ lineno = property(lineno_get, lineno_set)
+
+ def selprop_get(self):
+ try:
+ if self._selprop_sz:
+ return string_at(self._selprop, self._selprop_sz)
+ return ''
+ except:
+ raise
+
+ def selprop_set(self, value):
+ raise AttributeError('selprop attribute is read only')
+ selprop = property(selprop_get, selprop_set)
+
+ def codestr_get(self):
+ try:
+ if self._codestr_sz:
+ return string_at(self._codestr, self._codestr_sz)
+ return ''
+ except:
+ raise
+
+ def codestr_set(self, value):
+ raise AttributeError('codestr attribute is read only')
+ codestr = property(codestr_get, codestr_set)
+
+ def __nonzero__(self):
+ return self._error != 0
+
+ def __repr__(self):
+ return '<Block %d %s>' % (self.lineno, self.selprop.__repr__())
+
+ def __unicode__(self):
+ return self.selprop
+
+
+########################################
+# Init function prototypes
+########################################
+
+_scss.block_locator_create.argtypes = [c_char_p, c_int]
+_scss.block_locator_create.restype = c_void_p
+
+_scss.block_locator_rewind.argtypes = [c_void_p]
+_scss.block_locator_rewind.restype = None
+
+_scss.block_locator_destroy.argtypes = [c_void_p]
+_scss.block_locator_destroy.restype = None
+
+_scss.block_locator_next_block.argtypes = [c_void_p]
+_scss.block_locator_next_block.restype = POINTER(Block)
+
+
+########################################
+# Python API
+########################################
+
+class BlockLocator(object):
+ def __init__(self, codestr):
+ """
+ Create a BlockLocator instance to segment codestr.
+ """
+ self._unicode = False
+ self._destroyed = False
+ if isinstance(codestr, unicode):
+ codestr = codestr.encode('utf8')
+ self._unicode = True
+ self._locator = _scss.block_locator_create(codestr, len(codestr))
+
+ def __iter__(self):
+ """
+ Iterate through all blocks. Note the iteration has
+ side-effect: an BlockLocator object can only be iterated
+ once.
+ """
+ while True:
+ block = self.next_block()
+ if block is None:
+ raise StopIteration
+ if self._unicode:
+ yield block.lineno, block.selprop.decode('utf8'), block.codestr.decode('utf8')
+ else:
+ yield block.lineno, block.selprop, block.codestr
+
+ def next_block(self):
+ """
+ Get next block. When no block is available, return None.
+ """
+ if self._destroyed:
+ return None
+
+ block = _scss.block_locator_next_block(self._locator)
+ block = block.contents
+ if block._error >= 0:
+ _scss.block_locator_rewind(self._locator)
+ if block._error > 0:
+ raise Exception({
+ 1: "Missing closing parenthesis somewhere in block",
+ 2: "Missing closing string somewhere in block",
+ 3: "Block never closed",
+ }.get(block._error), block._error)
+ return None
+ else:
+ return block
+
+ def __del__(self):
+ if not self._destroyed:
+ _scss.block_locator_destroy(self._locator)
+ self._destroyed = True
+
+locate_blocks = BlockLocator
diff --git a/scss/src/_scss_c/__init__.pyc b/scss/src/_scss_c/__init__.pyc
new file mode 100644
index 0000000..79c8cc9
--- /dev/null
+++ b/scss/src/_scss_c/__init__.pyc
Binary files differ
diff --git a/scss/src/_scss_c/_scss_c.c b/scss/src/_scss_c/_scss_c.c
new file mode 100644
index 0000000..4b282df
--- /dev/null
+++ b/scss/src/_scss_c/_scss_c.c
@@ -0,0 +1,528 @@
+/*
+* pyScss, a Scss compiler for Python
+* SCSS blocks scanner.
+*
+* German M. Bravo (Kronuz) <german.mb@gmail.com>
+* https://github.com/Kronuz/pyScss
+*
+* MIT license (http://www.opensource.org/licenses/mit-license.php)
+* Copyright (c) 2011 German M. Bravo (Kronuz), All rights reserved.
+*/
+#import <stdio.h>
+#import <stdlib.h>
+#import <string.h>
+
+#if defined(_MSC_VER) // Microsoft compiler
+# define DLLEXPORT __declspec(dllexport)
+#elif defined(__GNUC__) // GNU compiler
+# define DLLEXPORT
+#else
+# error Unknown compiler, donot know how to process dllexport
+#endif
+
+#undef DEBUG
+// #define DEBUG 1
+
+typedef struct {
+ int error;
+ int lineno;
+ char *selprop;
+ int selprop_sz;
+ char *codestr;
+ int codestr_sz;
+} scss_Block;
+
+typedef struct {
+ char *exc;
+ char *_codestr;
+ char *codestr;
+ char *codestr_ptr;
+ int codestr_sz;
+ int lineno;
+ int par;
+ char instr;
+ int depth;
+ int skip;
+ char *thin;
+ char *init;
+ char *safe;
+ char *lose;
+ char *start;
+ char *end;
+ scss_Block block;
+} scss_BlockLocator;
+
+
+int _strip(char *begin, char *end, int *lineno) {
+ // " 1\0 some, \n 2\0 aca "
+ int _cnt,
+ cnt = 0,
+ pass = 1,
+ addnl = 0;
+ char c,
+ *line = NULL,
+ *first = begin,
+ *last = begin,
+ *write = lineno ? begin : NULL;
+ while (begin < end) {
+ c = *begin;
+ if (c == '\0') {
+ if (line == NULL) {
+ line = first;
+ if (lineno) {
+ sscanf(line, "%d", lineno);
+ }
+ }
+ first = last = begin + 1;
+ pass = 1;
+ } else if (c == '\n') {
+ _cnt = (int)(last - first);
+ if (_cnt > 0) {
+ cnt += _cnt + addnl;
+ if (write != NULL) {
+ if (addnl) {
+ *write++ = '\n';
+ }
+ while (first < last) {
+ *write++ = *first++;
+ }
+ *write = '\0';
+ addnl = 1;
+ }
+ }
+ first = last = begin + 1;
+ pass = 1;
+ } else if (c == ' ' || c == '\t') {
+ if (pass) {
+ first = last = begin + 1;
+ }
+ } else {
+ last = begin + 1;
+ pass = 0;
+ }
+ begin++;
+ }
+ _cnt = (int)(last - first);
+ if (_cnt > 0) {
+ cnt += _cnt + addnl;
+ if (write != NULL) {
+ if (addnl) {
+ *write++ = '\n';
+ }
+ while (first < last) {
+ *write++ = *first++;
+ }
+ *write = '\0';
+ }
+ }
+
+ return cnt;
+}
+
+
+typedef void scss_Callback(scss_BlockLocator*);
+
+
+void _start_string(scss_BlockLocator *self) {
+ #ifdef DEBUG
+ fprintf(stderr, "_start_string\n");
+ #endif
+ // A string starts
+ self->instr = *(self->codestr_ptr);
+}
+
+void _end_string(scss_BlockLocator *self) {
+ #ifdef DEBUG
+ fprintf(stderr, "_end_string\n");
+ #endif
+ // A string ends (FIXME: needs to accept escaped characters)
+ self->instr = 0;
+}
+
+void _start_parenthesis(scss_BlockLocator *self) {
+ #ifdef DEBUG
+ fprintf(stderr, "_start_parenthesis\n");
+ #endif
+ // parenthesis begins:
+ self->par++;
+ self->thin = NULL;
+ self->safe = self->codestr_ptr + 1;
+}
+
+void _end_parenthesis(scss_BlockLocator *self) {
+ #ifdef DEBUG
+ fprintf(stderr, "_end_parenthesis\n");
+ #endif
+ self->par--;
+}
+
+void _flush_properties(scss_BlockLocator *self) {
+ #ifdef DEBUG
+ fprintf(stderr, "_flush_properties\n");
+ #endif
+ // Flush properties
+ int len, lineno = -1;
+ if (self->lose <= self->init) {
+ len = _strip(self->lose, self->init, &lineno);
+ if (len) {
+ if (lineno != -1) {
+ self->lineno = lineno;
+ }
+
+ self->block.selprop = self->lose;
+ self->block.selprop_sz = len;
+ self->block.codestr = NULL;
+ self->block.codestr_sz = 0;
+ self->block.lineno = self->lineno;
+ self->block.error = -1;
+ }
+ self->lose = self->init;
+ }
+}
+
+void _start_block1(scss_BlockLocator *self) {
+ #ifdef DEBUG
+ fprintf(stderr, "_start_block1\n");
+ #endif
+ // Start block:
+ if (self->codestr_ptr > self->codestr && *(self->codestr_ptr - 1) == '#') {
+ self->skip = 1;
+ } else {
+ self->start = self->codestr_ptr;
+ if (self->thin != NULL && _strip(self->thin, self->codestr_ptr, NULL)) {
+ self->init = self->thin;
+ }
+ _flush_properties(self);
+ self->thin = NULL;
+ }
+ self->depth++;
+}
+
+void _start_block(scss_BlockLocator *self) {
+ #ifdef DEBUG
+ fprintf(stderr, "_start_block\n");
+ #endif
+ // Start block:
+ self->depth++;
+}
+
+void _end_block1(scss_BlockLocator *self) {
+ #ifdef DEBUG
+ fprintf(stderr, "_end_block1\n");
+ #endif
+ // Block ends:
+ int len, lineno = -1;
+ self->depth--;
+ if (!self->skip) {
+ self->end = self->codestr_ptr;
+ len = _strip(self->init, self->start, &lineno);
+ if (lineno != -1) {
+ self->lineno = lineno;
+ }
+
+ self->block.selprop = self->init;
+ self->block.selprop_sz = len;
+ self->block.codestr = (self->start + 1);
+ self->block.codestr_sz = (int)(self->end - (self->start + 1));
+ self->block.lineno = self->lineno;
+ self->block.error = -1;
+
+ self->init = self->safe = self->lose = self->end + 1;
+ self->thin = NULL;
+ }
+ self->skip = 0;
+}
+
+void _end_block(scss_BlockLocator *self) {
+ #ifdef DEBUG
+ fprintf(stderr, "_end_block\n");
+ #endif
+ // Block ends:
+ self->depth--;
+}
+
+void _end_property(scss_BlockLocator *self) {
+ #ifdef DEBUG
+ fprintf(stderr, "_end_property\n");
+ #endif
+ // End of property (or block):
+ int len, lineno = -1;
+ self->init = self->codestr_ptr;
+ if (self->lose <= self->init) {
+ len = _strip(self->lose, self->init, &lineno);
+ if (len) {
+ if (lineno != -1) {
+ self->lineno = lineno;
+ }
+
+ self->block.selprop = self->lose;
+ self->block.selprop_sz = len;
+ self->block.codestr = NULL;
+ self->block.codestr_sz = 0;
+ self->block.lineno = self->lineno;
+ self->block.error = -1;
+ }
+ self->init = self->safe = self->lose = self->codestr_ptr + 1;
+ }
+ self->thin = NULL;
+}
+
+void _mark_safe(scss_BlockLocator *self) {
+ #ifdef DEBUG
+ fprintf(stderr, "_mark_safe\n");
+ #endif
+ // We are on a safe zone
+ if (self->thin != NULL && _strip(self->thin, self->codestr_ptr, NULL)) {
+ self->init = self->thin;
+ }
+ self->thin = NULL;
+ self->safe = self->codestr_ptr + 1;
+}
+
+void _mark_thin(scss_BlockLocator *self) {
+ #ifdef DEBUG
+ fprintf(stderr, "_mark_thin\n");
+ #endif
+ // Step on thin ice, if it breaks, it breaks here
+ if (self->thin != NULL && _strip(self->thin, self->codestr_ptr, NULL)) {
+ self->init = self->thin;
+ self->thin = self->codestr_ptr + 1;
+ } else if (self->thin == NULL && _strip(self->safe, self->codestr_ptr, NULL)) {
+ self->thin = self->codestr_ptr + 1;
+ }
+}
+
+int scss_function_map_initialized = 0;
+scss_Callback* scss_function_map[256 * 256 * 2 * 3]; // (c, instr, par, depth)
+void init_function_map(void) {
+ int i;
+
+ if (scss_function_map_initialized)
+ return;
+ scss_function_map_initialized = 1;
+
+ for (i = 0; i < 256 * 256 * 2 * 3; i++) {
+ scss_function_map[i] = NULL;
+ }
+ scss_function_map[(int)'\"' + 256*0 + 256*256*0 + 256*256*2*0] = _start_string;
+ scss_function_map[(int)'\'' + 256*0 + 256*256*0 + 256*256*2*0] = _start_string;
+ scss_function_map[(int)'\"' + 256*0 + 256*256*1 + 256*256*2*0] = _start_string;
+ scss_function_map[(int)'\'' + 256*0 + 256*256*1 + 256*256*2*0] = _start_string;
+ scss_function_map[(int)'\"' + 256*0 + 256*256*0 + 256*256*2*1] = _start_string;
+ scss_function_map[(int)'\'' + 256*0 + 256*256*0 + 256*256*2*1] = _start_string;
+ scss_function_map[(int)'\"' + 256*0 + 256*256*1 + 256*256*2*1] = _start_string;
+ scss_function_map[(int)'\'' + 256*0 + 256*256*1 + 256*256*2*1] = _start_string;
+ scss_function_map[(int)'\"' + 256*0 + 256*256*0 + 256*256*2*2] = _start_string;
+ scss_function_map[(int)'\'' + 256*0 + 256*256*0 + 256*256*2*2] = _start_string;
+ scss_function_map[(int)'\"' + 256*0 + 256*256*1 + 256*256*2*2] = _start_string;
+ scss_function_map[(int)'\'' + 256*0 + 256*256*1 + 256*256*2*2] = _start_string;
+
+ scss_function_map[(int)'\"' + 256*(int)'\"' + 256*256*0 + 256*256*2*0] = _end_string;
+ scss_function_map[(int)'\'' + 256*(int)'\'' + 256*256*0 + 256*256*2*0] = _end_string;
+ scss_function_map[(int)'\"' + 256*(int)'\"' + 256*256*1 + 256*256*2*0] = _end_string;
+ scss_function_map[(int)'\'' + 256*(int)'\'' + 256*256*1 + 256*256*2*0] = _end_string;
+ scss_function_map[(int)'\"' + 256*(int)'\"' + 256*256*0 + 256*256*2*1] = _end_string;
+ scss_function_map[(int)'\'' + 256*(int)'\'' + 256*256*0 + 256*256*2*1] = _end_string;
+ scss_function_map[(int)'\"' + 256*(int)'\"' + 256*256*1 + 256*256*2*1] = _end_string;
+ scss_function_map[(int)'\'' + 256*(int)'\'' + 256*256*1 + 256*256*2*1] = _end_string;
+ scss_function_map[(int)'\"' + 256*(int)'\"' + 256*256*0 + 256*256*2*2] = _end_string;
+ scss_function_map[(int)'\'' + 256*(int)'\'' + 256*256*0 + 256*256*2*2] = _end_string;
+ scss_function_map[(int)'\"' + 256*(int)'\"' + 256*256*1 + 256*256*2*2] = _end_string;
+ scss_function_map[(int)'\'' + 256*(int)'\'' + 256*256*1 + 256*256*2*2] = _end_string;
+
+ scss_function_map[(int)'(' + 256*0 + 256*256*0 + 256*256*2*0] = _start_parenthesis;
+ scss_function_map[(int)'(' + 256*0 + 256*256*1 + 256*256*2*0] = _start_parenthesis;
+ scss_function_map[(int)'(' + 256*0 + 256*256*0 + 256*256*2*1] = _start_parenthesis;
+ scss_function_map[(int)'(' + 256*0 + 256*256*1 + 256*256*2*1] = _start_parenthesis;
+ scss_function_map[(int)'(' + 256*0 + 256*256*0 + 256*256*2*2] = _start_parenthesis;
+ scss_function_map[(int)'(' + 256*0 + 256*256*1 + 256*256*2*2] = _start_parenthesis;
+
+ scss_function_map[(int)')' + 256*0 + 256*256*1 + 256*256*2*0] = _end_parenthesis;
+ scss_function_map[(int)')' + 256*0 + 256*256*1 + 256*256*2*1] = _end_parenthesis;
+ scss_function_map[(int)')' + 256*0 + 256*256*1 + 256*256*2*2] = _end_parenthesis;
+
+ scss_function_map[(int)'{' + 256*0 + 256*256*0 + 256*256*2*0] = _start_block1;
+ scss_function_map[(int)'{' + 256*0 + 256*256*0 + 256*256*2*1] = _start_block;
+ scss_function_map[(int)'{' + 256*0 + 256*256*0 + 256*256*2*2] = _start_block;
+
+ scss_function_map[(int)'}' + 256*0 + 256*256*0 + 256*256*2*1] = _end_block1;
+ scss_function_map[(int)'}' + 256*0 + 256*256*0 + 256*256*2*2] = _end_block;
+
+ scss_function_map[(int)';' + 256*0 + 256*256*0 + 256*256*2*0] = _end_property;
+
+ scss_function_map[(int)',' + 256*0 + 256*256*0 + 256*256*2*0] = _mark_safe;
+
+ scss_function_map[(int)'\n' + 256*0 + 256*256*0 + 256*256*2*0] = _mark_thin;
+
+ scss_function_map[0 + 256*0 + 256*256*0 + 256*256*2*0] = _flush_properties;
+ scss_function_map[0 + 256*0 + 256*256*0 + 256*256*2*1] = _flush_properties;
+ scss_function_map[0 + 256*0 + 256*256*0 + 256*256*2*2] = _flush_properties;
+ #ifdef DEBUG
+ fprintf(stderr, "Scss function maps initialized!\n");
+ #endif
+}
+
+
+/* constructor */
+
+DLLEXPORT
+scss_BlockLocator *block_locator_create(const char *codestr, int codestr_sz)
+{
+ scss_BlockLocator *self;
+
+ init_function_map();
+
+ self = (scss_BlockLocator *)calloc(1, sizeof(scss_BlockLocator));
+ if (self) {
+ self->_codestr = (char *)malloc(codestr_sz);
+ memcpy(self->_codestr, codestr, codestr_sz);
+ self->codestr_sz = codestr_sz;
+ self->codestr = (char *)malloc(self->codestr_sz);
+ memcpy(self->codestr, self->_codestr, self->codestr_sz);
+ self->codestr_ptr = self->codestr;
+ self->lineno = 0;
+ self->par = 0;
+ self->instr = 0;
+ self->depth = 0;
+ self->skip = 0;
+ self->thin = self->codestr;
+ self->init = self->codestr;
+ self->safe = self->codestr;
+ self->lose = self->codestr;
+ self->start = NULL;
+ self->end = NULL;
+ self->exc = NULL;
+
+ #ifdef DEBUG
+ fprintf(stderr, "Scss BlockLocator object initialized! (%lu)\n", sizeof(scss_BlockLocator));
+ #endif
+ }
+
+ return self;
+}
+
+DLLEXPORT
+void block_locator_rewind(scss_BlockLocator *self)
+{
+ free(self->codestr);
+ self->codestr = (char *)malloc(self->codestr_sz);
+ memcpy(self->codestr, self->_codestr, self->codestr_sz);
+ self->codestr_ptr = self->codestr;
+ self->lineno = 0;
+ self->par = 0;
+ self->instr = 0;
+ self->depth = 0;
+ self->skip = 0;
+ self->thin = self->codestr;
+ self->init = self->codestr;
+ self->safe = self->codestr;
+ self->lose = self->codestr;
+ self->start = NULL;
+ self->end = NULL;
+ self->exc = NULL;
+
+ #ifdef DEBUG
+ fprintf(stderr, "Scss BlockLocator object rewound!\n");
+ #endif
+}
+
+DLLEXPORT
+void block_locator_destroy(scss_BlockLocator *self)
+{
+ free(self->codestr);
+ free(self->_codestr);
+
+ free(self);
+
+ #ifdef DEBUG
+ fprintf(stderr, "Scss BlockLocator object destroyed!\n");
+ #endif
+}
+
+
+/*****/
+
+DLLEXPORT
+scss_Block* block_locator_next_block(scss_BlockLocator *self)
+{
+ scss_Callback *fn;
+ char c = 0;
+ char *codestr_end = self->codestr + self->codestr_sz;
+
+ memset(&self->block, 0, sizeof(scss_Block));
+
+ while (self->codestr_ptr < codestr_end) {
+ c = *(self->codestr_ptr);
+ if (!c) {
+ self->codestr_ptr++;
+ continue;
+ }
+
+ repeat:
+
+ fn = scss_function_map[
+ (int)c +
+ 256 * self->instr +
+ 256 * 256 * (int)(self->par != 0) +
+ 256 * 256 * 2 * (int)(self->depth > 1 ? 2 : self->depth)
+ ];
+
+ if (fn != NULL) {
+ fn(self);
+ }
+
+ self->codestr_ptr++;
+ if (self->codestr_ptr > codestr_end) {
+ self->codestr_ptr = codestr_end;
+ }
+
+ if (self->block.error) {
+ #ifdef DEBUG
+ if (self->block.error < 0) {
+ fprintf(stderr, "Block found!\n");
+ } else {
+ fprintf(stderr, "Exception!\n");
+ }
+ #endif
+ return &self->block;
+ }
+ }
+ if (self->par > 0) {
+ if (self->block.error <= 0) {
+ self->block.error = 1;
+ self->exc = "Missing closing parenthesis somewhere in block";
+ #ifdef DEBUG
+ fprintf(stderr, "%s\n", self->exc);
+ #endif
+ }
+ } else if (self->instr != 0) {
+ if (self->block.error <= 0) {
+ self->block.error = 2;
+ self->exc = "Missing closing string somewhere in block";
+ #ifdef DEBUG
+ fprintf(stderr, "%s\n", self->exc);
+ #endif
+ }
+ } else if (self->depth > 0) {
+ if (self->block.error <= 0) {
+ self->block.error = 3;
+ self->exc = "Missing closing string somewhere in block";
+ #ifdef DEBUG
+ fprintf(stderr, "%s\n", self->exc);
+ #endif
+ }
+ if (self->init < codestr_end) {
+ c = '}';
+ goto repeat;
+ }
+ }
+ if (self->init < codestr_end) {
+ self->init = codestr_end;
+ c = 0;
+ goto repeat;
+ }
+
+ block_locator_rewind(self);
+
+ return &self->block;
+}
diff --git a/scss/src/_scss_c/_scss_c.so b/scss/src/_scss_c/_scss_c.so
new file mode 100755
index 0000000..5d7bff1
--- /dev/null
+++ b/scss/src/_scss_c/_scss_c.so
Binary files differ
diff --git a/scss/src/_scss_c/build.py b/scss/src/_scss_c/build.py
new file mode 100755
index 0000000..1e74606
--- /dev/null
+++ b/scss/src/_scss_c/build.py
@@ -0,0 +1,76 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+import sys
+import re
+from os.path import exists
+from os import stat, system
+from glob import glob
+
+########################################
+# Platform dependent configuration
+########################################
+
+config = {
+ 'ld': 'gcc',
+ 'ld_flags': '-shared',
+ 'shared_ext': 'so',
+ 'shared_oflag': '-o ',
+ 'obj_ext': 'o',
+ 'cc': 'gcc',
+ 'cc_flags': '-fPIC -O3 -c',
+}
+
+if sys.platform == 'win32':
+ # use Microsoft compiler
+ config['ld'] = 'link'
+ config['ld_flags'] = '/DLL /NOLOGO /OPT:REF /OPT:ICF /LTCG /DYNAMICBASE /NXCOMPAT'
+ config['shared_ext'] = 'dll'
+ config['shared_oflag'] = '/OUT:'
+ config['obj_ext'] = 'obj'
+ config['cc'] = 'cl'
+ config['cc_flags'] = '/O3 /Oi /GL /EHsc /Gy /W3 /nologo /c'
+
+
+def need_update(obj, src):
+ if not exists(obj):
+ return True
+ tobj = stat(obj).st_mtime
+ tsrc = stat(src).st_mtime
+ if tobj < tsrc:
+ return True
+ return False
+
+
+def do_cmd(cmd):
+ print cmd
+ system(cmd)
+
+
+def compile_obj(name):
+ obj = '%s.%s' % (name, config['obj_ext'])
+ src = '%s.c' % name
+
+ if need_update(obj, src):
+ do_cmd('%s %s %s' % (config['cc'], config['cc_flags'], src))
+
+
+def link(name, objs):
+ so = '%s.%s' % (name, config['shared_ext'])
+ for obj in objs:
+ if need_update(so, obj):
+ do_cmd('%s %s %s%s %s' %
+ (config['ld'],
+ config['ld_flags'],
+ config['shared_oflag'],
+ so,
+ ' '.join(objs)),
+ )
+ break
+
+if __name__ == '__main__':
+ srcs = glob('*.c')
+ names = [re.sub(r'\.c$', '', name) for name in srcs]
+
+ for name in names:
+ compile_obj(name)
+ link('_scss_c', ['%s.%s' % (name, config['obj_ext']) for name in names])
diff --git a/scss/src/scanner.py b/scss/src/scanner.py
index 2c753b6..fb2659a 100644
--- a/scss/src/scanner.py
+++ b/scss/src/scanner.py
@@ -461,13 +461,26 @@ def _locate_blocks_b(codestr):
################################################################################
# Algorithm implemented in C:
+
try:
from _scss import locate_blocks as _locate_blocks_c
except ImportError:
+ _locate_blocks_c = None
print >>sys.stderr, "Scanning acceleration disabled (_scss not found)!"
################################################################################
+# Algorithm implemented in C with CTypes:
+
+
+try:
+ from _scss_c import locate_blocks as _locate_blocks_d
+except ImportError:
+ _locate_blocks_d = None
+ print >>sys.stderr, "Scanning CTypes acceleration disabled (_scss_c not found)!"
+
+
+################################################################################
codestr = """
@@ -504,40 +517,43 @@ however this is a selector (
"""
verify = '\t----------------------------------------------------------------------\n\t>[1] \'simple\'\n\t----------------------------------------------------------------------\n\t>\t[3] \'block\'\n\t----------------------------------------------------------------------\n\t>[5] \'#{ignored}\'\n\t----------------------------------------------------------------------\n\t>[6] \'some,\\nselectors,\\nand multi-lined,\\nselectors\'\n\t----------------------------------------------------------------------\n\t>[10] \'with more\'\n\t----------------------------------------------------------------------\n\t>\t[12] \'the block in here\'\n\t----------------------------------------------------------------------\n\t>\t[13] \'can have, nested, selectors\'\n\t----------------------------------------------------------------------\n\t>\t\t[14] \'and properties in nested blocks\'\n\t----------------------------------------------------------------------\n\t>\t\t[15] \'and stuff with #{ ignored blocks }\'\n\t----------------------------------------------------------------------\n\t>\t[17] \'properties-can: "have strings with stuff like this: }"\'\n\t----------------------------------------------------------------------\n\t>[19] \'and other,\\nselectors\\ncan be turned into "lose"\\nproperties\'\n\t----------------------------------------------------------------------\n\t>[23] \'if no commas are found\\nhowever this is a selector (\\nas well as these things,\\nwhich are parameters\\nand can expand\\nany number of\\nlines)\'\n\t----------------------------------------------------------------------\n\t>\t[30] \'and this is its block\'\n'
-locate_blocks = _locate_blocks_a
-
-def process_block(codestr, level=0, dump=False):
+def process_block(locate_blocks, codestr, level=0, dump=False):
ret = '' if dump else None
for lineno, selprop, block in locate_blocks(codestr):
if dump:
ret += '\t%s\n\t>%s[%s] %s\n' % ('-' * 70, '\t' * level, lineno, repr(selprop))
if block:
- _ret = process_block(block, level + 1, dump)
+ _ret = process_block(locate_blocks, block, level + 1, dump)
if dump:
ret += _ret
return ret
-@profile
-def profile_process_block(codestr):
- for q in xrange(10000):
- process_block(codestr)
-
+def process_blocks(locate_blocks, codestr):
+ for q in xrange(50000):
+ process_block(locate_blocks, codestr)
+profiled_process_blocks = profile(process_blocks)
if __name__ == "__main__":
codestr = load_string(codestr)
- ret = process_block(codestr, dump=True)
- print "This is what `%s()` returned:" % locate_blocks.__name__
- # print repr(ret)
- print ret
- assert ret == verify, 'It should be:\n%s' % verify
-
- start = datetime.now()
- print "Timing: %s()..." % locate_blocks.__name__
- profile_process_block(codestr)
- elap = datetime.now() - start
-
- elapms = elap.seconds * 1000.0 + elap.microseconds / 1000.0
- print "Done! took %06.3fms" % elapms
+ for locate_blocks, desc in (
+ (_locate_blocks_a, "Pure Python, Full algorithm (_locate_blocks_a))"),
+ (_locate_blocks_b, "Pure Python, Condensed algorithm (_locate_blocks_b))"),
+ (_locate_blocks_c, "Builtin C Function, Full algorithm (_locate_blocks_c))"),
+ (_locate_blocks_d, "CTypes C Function, Full algorithm (_locate_blocks_d))")):
+ if locate_blocks:
+ ret = process_block(locate_blocks, codestr, dump=True)
+ # print "This is what `%s()` returned:" % locate_blocks
+ # print ret
+ # print repr(ret)
+ assert ret == verify, 'It should be:\n%s' % verify
+
+ start = datetime.now()
+ print >>sys.stderr, "Timing: %s..." % desc,
+ process_blocks(locate_blocks, codestr)
+ elap = datetime.now() - start
+
+ elapms = elap.seconds * 1000.0 + elap.microseconds / 1000.0
+ print >>sys.stderr, "Done! took %06.3fms" % elapms