def parse(self, css=None, clamp=True, stretch=1000, filename=None, static_tags={}, dynamic_tags=set()): """ Parses MapCSS given as string """ basepath = os.curdir if filename: basepath = os.path.dirname(filename) if not css: css = open(filename).read() if not self.style_loaded: self.choosers = [] log = logging.getLogger('mapcss.parser') previous = oNONE # what was the previous CSS word? sc = StyleChooser(self.scalepair) # currently being assembled stck = [] # filename, original, remained stck.append([filename, css, css]) try: while (len(stck) > 0): css = stck[-1][1].lstrip() # remained wasBroken = False while (css): # Class - :motorway, :builtup, :hover if CLASS.match(css): if previous == oDECLARATION: self.choosers.append(sc) sc = StyleChooser(self.scalepair) cond = CLASS.match(css).groups()[0] log.debug("class found: %s" % (cond)) css = CLASS.sub("", css, 1) sc.addCondition(Condition('eq', ("::class", cond))) previous = oCONDITION # Not class - !.motorway, !.builtup, !:hover elif NOT_CLASS.match(css): if (previous == oDECLARATION): self.choosers.append(sc) sc = StyleChooser(self.scalepair) cond = NOT_CLASS.match(css).groups()[0] log.debug("not_class found: %s" % (cond)) css = NOT_CLASS.sub("", css, 1) sc.addCondition(Condition('ne', ("::class", cond))) previous = oCONDITION # Zoom elif ZOOM.match(css): if (previous != oOBJECT & previous != oCONDITION): sc.newObject() cond = ZOOM.match(css).groups()[0] log.debug("zoom found: %s" % (cond)) css = ZOOM.sub("", css, 1) sc.addZoom(self.parseZoom(cond)) previous = oZOOM # Grouping - just a comma elif GROUP.match(css): css = GROUP.sub("", css, 1) sc.newGroup() had_main_tag = False previous = oGROUP # Condition - [highway=primary] or [population>1000] elif CONDITION.match(css): if (previous == oDECLARATION): self.choosers.append(sc) sc = StyleChooser(self.scalepair) had_main_tag = False if (previous != oOBJECT) and (previous != oZOOM) and ( previous != oCONDITION) and ( previous != oSELECTORS_OPERATOR): sc.newObject() had_main_tag = False cond = CONDITION.match(css).groups()[0] c = parseCondition(cond) tag = c.extract_tag() #tag_type = static_tags.get(tag, None) if True: #tag == "*":# or tag_type is not None: # if tag_type and had_main_tag: # if '!' in cond: # condType = 'ne' # cond = cond.replace('!', '') # else: # condType = 'eq' # sc.addRuntimeCondition(Condition(condType, ('extra_tag', cond))) # else: sc.addCondition(c) # if tag_type: # had_main_tag = True # elif tag in dynamic_tags: # sc.addRuntimeCondition(c) # else: # raise Exception("Unknown tag '" + tag + "' in condition " + cond) css = CONDITION.sub("", css, 1) previous = oCONDITION # Selectors operator, way[...] > node[...] elif SELECTORS_OPERATOR.match(css): if (previous != oOBJECT) and (previous != oZOOM) and ( previous != oCONDITION): raise Exception( "Selector Operator without selector") op = SELECTORS_OPERATOR.match(css).groups()[0] sc.addSelectorsOperator(op) css = SELECTORS_OPERATOR.sub("", css, 1) previous = oSELECTORS_OPERATOR # Object - way, node, relation elif OBJECT.match(css): if (previous == oDECLARATION): self.choosers.append(sc) sc = StyleChooser(self.scalepair) obj = OBJECT.match(css).groups()[0] log.debug("object found: %s" % (obj)) css = OBJECT.sub("", css, 1) if (previous != oSELECTORS_OPERATOR): sc.newObject(obj) had_main_tag = False previous = oOBJECT # Declaration - {...} elif DECLARATION.match(css): if previous == oDECLARATION or previous == oNONE: raise Exception("Declaration without conditions") decl = DECLARATION.match(css).groups()[0] log.debug("declaration found: %s" % (decl)) sc.addStyles( self.subst_variables(parseDeclaration(decl))) css = DECLARATION.sub("", css, 1) previous = oDECLARATION # CSS comment elif COMMENT.match(css): log.debug("comment found") css = COMMENT.sub("", css, 1) # @import("filename.css"); elif IMPORT.match(css): log.debug("import found") import_filename = os.path.join( basepath, IMPORT.match(css).groups()[0]) try: css = IMPORT.sub("", css, 1) import_text = open(import_filename, "r").read() stck[-1][1] = css # store remained part stck.append( [import_filename, import_text, import_text]) wasBroken = True break except IOError as e: raise Exception("Cannot import file " + import_filename + "\n" + str(e)) # Variables elif VARIABLE_SET.match(css): name = VARIABLE_SET.match(css).groups()[0] log.debug("variable set found: %s" % name) self.variables[name] = VARIABLE_SET.match( css).groups()[1] css = VARIABLE_SET.sub("", css, 1) previous = oVARIABLE_SET # Unknown pattern elif UNKNOWN.match(css): raise Exception("Unknown construction: " + UNKNOWN.match(css).group()) # Must be unreacheable else: raise Exception("Unexpected construction: " + css) stck[-1][1] = css # store remained part if not wasBroken: stck.pop() if (previous == oDECLARATION): self.choosers.append(sc) sc = StyleChooser(self.scalepair) except Exception as e: filename = stck[-1][0] # filename css_orig = stck[-1][2] # original css = stck[-1][1] # remained line = css_orig[:-len(css)].count("\n") + 1 msg = str(e) + "\nFile: " + filename + "\nLine: " + str(line) raise Exception(msg) try: if clamp: "clamp z-indexes, so they're tightly following integers" zindex = set() for chooser in self.choosers: for stylez in chooser.styles: zindex.add(float(stylez.get('z-index', 0))) zindex = list(zindex) zindex.sort() zoffset = len([x for x in zindex if x < 0]) for chooser in self.choosers: for stylez in chooser.styles: if 'z-index' in stylez: res = zindex.index(float(stylez.get('z-index', 0))) - zoffset if stretch: stylez['z-index'] = 1. * res / len( zindex) * stretch else: stylez['z-index'] = res except TypeError: pass for chooser in self.choosers: for t in chooser.compatible_types: if t not in self.choosers_by_type: self.choosers_by_type[t] = [chooser] else: self.choosers_by_type[t].append(chooser)