diff options
author | German M. Bravo <german.mb@deipi.com> | 2011-12-24 05:31:24 -0600 |
---|---|---|
committer | German M. Bravo <german.mb@deipi.com> | 2011-12-24 05:31:24 -0600 |
commit | 5d30d48dfb6c6c7535e46d2fd7852753d3452fe2 (patch) | |
tree | f0ed6c03af09f65b4935092884b38f3c56e66cc4 | |
parent | 7153bb433bffacbb0a651e8ed26a504b40d83e06 (diff) | |
download | pyscss-5d30d48dfb6c6c7535e46d2fd7852753d3452fe2.tar.gz |
Added CTypes version (but it's slower)...
-rw-r--r-- | scss/src/_scss.c | 262 | ||||
-rw-r--r-- | scss/src/_scss_c/__init__.py | 144 | ||||
-rw-r--r-- | scss/src/_scss_c/__init__.pyc | bin | 0 -> 5281 bytes | |||
-rw-r--r-- | scss/src/_scss_c/_scss_c.c | 528 | ||||
-rwxr-xr-x | scss/src/_scss_c/_scss_c.so | bin | 0 -> 13688 bytes | |||
-rwxr-xr-x | scss/src/_scss_c/build.py | 76 | ||||
-rw-r--r-- | scss/src/scanner.py | 60 |
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 Binary files differnew file mode 100644 index 0000000..79c8cc9 --- /dev/null +++ b/scss/src/_scss_c/__init__.pyc 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 Binary files differnew file mode 100755 index 0000000..5d7bff1 --- /dev/null +++ b/scss/src/_scss_c/_scss_c.so 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 |