├── .gitignore ├── .travis.yml ├── CHANGELOG.rst ├── LICENSE ├── MANIFEST.in ├── README.rst ├── docs ├── .gitignore ├── Makefile ├── _static │ ├── fish-text-black.png │ ├── github-logo.png │ └── logo.png ├── api.rst ├── conf.py ├── index.rst └── make.bat ├── release.sh ├── requirements.txt ├── setup.py ├── srcgen ├── __init__.py ├── base.py ├── c.py ├── html.py ├── js.py ├── python.py └── version.py └── tests ├── test_c.py ├── test_html.py └── test_python.py /.gitignore: -------------------------------------------------------------------------------- 1 | *.py[cod] 2 | 3 | # C extensions 4 | *.so 5 | 6 | # Packages 7 | *.egg 8 | *.egg-info 9 | dist 10 | build 11 | eggs 12 | parts 13 | bin 14 | var 15 | sdist 16 | develop-eggs 17 | .installed.cfg 18 | lib 19 | lib64 20 | 21 | # Installer logs 22 | pip-log.txt 23 | 24 | # Unit test / coverage reports 25 | .coverage 26 | .tox 27 | nosetests.xml 28 | 29 | # Translations 30 | *.mo 31 | 32 | # Mr Developer 33 | .mr.developer.cfg 34 | .project 35 | .pydevproject 36 | .settings/ 37 | 38 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: python 2 | 3 | python: 4 | - "2.6" 5 | - "2.7" 6 | - "3.2" 7 | - "3.3" 8 | 9 | install: 10 | - pip install six 11 | 12 | script: nosetests -vv 13 | 14 | notifications: 15 | email: 16 | on_success: change 17 | on_failure: change 18 | -------------------------------------------------------------------------------- /CHANGELOG.rst: -------------------------------------------------------------------------------- 1 | 1.0.0 2 | ===== 3 | First public release 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013 Tomer Filiba (tomerfiliba@gmail.com) 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include LICENSE 2 | include README.rst 3 | 4 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | srcgen 2 | ====== 3 | 4 | Srcgen is a **semantic** code generation framework. Being semantic means that the code generator and the 5 | generated code bear similar structure, as well ; for instance, the body of an ``if`` statement is indented both in 6 | the generating and generated code. Here's a short example:: 7 | 8 | >>> from srcgen.python import PythonModule 9 | >>> 10 | >>> m = PythonModule("foo") 11 | >>> m.import_("sys") 12 | >>> m.import_("os") 13 | >>> m.sep() 14 | >>> m.stmt("x = 5") 15 | >>> with m.if_("x > 8"): 16 | ... m.stmt("print 'oh no'") 17 | ... 18 | >>> with m.else_(): 19 | ... m.stmt("print 'oh yes'") 20 | ... 21 | >>> print m 22 | import sys 23 | import os 24 | 25 | x = 5 26 | if x > 8: 27 | print 'oh no' 28 | else: 29 | print 'oh yes' 30 | 31 | You can nest deeper, of course, as well as extract common pieces of code into functions:: 32 | 33 | m = PythonModule("foo") 34 | with m.class_("MyClass"): 35 | with m.method("__init__", " 36 | 37 | 38 | 39 | 40 | Languages 41 | ========= 42 | At the moment Srcgen supports: 43 | 44 | * C 45 | * Python 46 | * Cython 47 | * HTML/XML 48 | 49 | More languages will be added per public demand (you're welcome to join the effort!) 50 | 51 | 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /docs/.gitignore: -------------------------------------------------------------------------------- 1 | _build 2 | 3 | -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line. 5 | SPHINXOPTS = 6 | SPHINXBUILD = sphinx-build 7 | PAPER = 8 | BUILDDIR = _build 9 | 10 | # Internal variables. 11 | PAPEROPT_a4 = -D latex_paper_size=a4 12 | PAPEROPT_letter = -D latex_paper_size=letter 13 | ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . 14 | # the i18n builder cannot share the environment and doctrees with the others 15 | I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . 16 | 17 | .PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext 18 | 19 | help: 20 | @echo "Please use \`make ' where is one of" 21 | @echo " html to make standalone HTML files" 22 | @echo " dirhtml to make HTML files named index.html in directories" 23 | @echo " singlehtml to make a single large HTML file" 24 | @echo " pickle to make pickle files" 25 | @echo " json to make JSON files" 26 | @echo " htmlhelp to make HTML files and a HTML help project" 27 | @echo " qthelp to make HTML files and a qthelp project" 28 | @echo " devhelp to make HTML files and a Devhelp project" 29 | @echo " epub to make an epub" 30 | @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" 31 | @echo " latexpdf to make LaTeX files and run them through pdflatex" 32 | @echo " text to make text files" 33 | @echo " man to make manual pages" 34 | @echo " texinfo to make Texinfo files" 35 | @echo " info to make Texinfo files and run them through makeinfo" 36 | @echo " gettext to make PO message catalogs" 37 | @echo " changes to make an overview of all changed/added/deprecated items" 38 | @echo " linkcheck to check all external links for integrity" 39 | @echo " doctest to run all doctests embedded in the documentation (if enabled)" 40 | 41 | clean: 42 | -rm -rf $(BUILDDIR)/* 43 | 44 | html: 45 | $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html 46 | @echo 47 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." 48 | 49 | dirhtml: 50 | $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml 51 | @echo 52 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." 53 | 54 | singlehtml: 55 | $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml 56 | @echo 57 | @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." 58 | 59 | pickle: 60 | $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle 61 | @echo 62 | @echo "Build finished; now you can process the pickle files." 63 | 64 | json: 65 | $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json 66 | @echo 67 | @echo "Build finished; now you can process the JSON files." 68 | 69 | htmlhelp: 70 | $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp 71 | @echo 72 | @echo "Build finished; now you can run HTML Help Workshop with the" \ 73 | ".hhp project file in $(BUILDDIR)/htmlhelp." 74 | 75 | qthelp: 76 | $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp 77 | @echo 78 | @echo "Build finished; now you can run "qcollectiongenerator" with the" \ 79 | ".qhcp project file in $(BUILDDIR)/qthelp, like this:" 80 | @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/srcgen.qhcp" 81 | @echo "To view the help file:" 82 | @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/srcgen.qhc" 83 | 84 | devhelp: 85 | $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp 86 | @echo 87 | @echo "Build finished." 88 | @echo "To view the help file:" 89 | @echo "# mkdir -p $$HOME/.local/share/devhelp/srcgen" 90 | @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/srcgen" 91 | @echo "# devhelp" 92 | 93 | epub: 94 | $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub 95 | @echo 96 | @echo "Build finished. The epub file is in $(BUILDDIR)/epub." 97 | 98 | latex: 99 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 100 | @echo 101 | @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." 102 | @echo "Run \`make' in that directory to run these through (pdf)latex" \ 103 | "(use \`make latexpdf' here to do that automatically)." 104 | 105 | latexpdf: 106 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 107 | @echo "Running LaTeX files through pdflatex..." 108 | $(MAKE) -C $(BUILDDIR)/latex all-pdf 109 | @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." 110 | 111 | text: 112 | $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text 113 | @echo 114 | @echo "Build finished. The text files are in $(BUILDDIR)/text." 115 | 116 | man: 117 | $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man 118 | @echo 119 | @echo "Build finished. The manual pages are in $(BUILDDIR)/man." 120 | 121 | texinfo: 122 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo 123 | @echo 124 | @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." 125 | @echo "Run \`make' in that directory to run these through makeinfo" \ 126 | "(use \`make info' here to do that automatically)." 127 | 128 | info: 129 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo 130 | @echo "Running Texinfo files through makeinfo..." 131 | make -C $(BUILDDIR)/texinfo info 132 | @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." 133 | 134 | gettext: 135 | $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale 136 | @echo 137 | @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." 138 | 139 | changes: 140 | $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes 141 | @echo 142 | @echo "The overview file is in $(BUILDDIR)/changes." 143 | 144 | linkcheck: 145 | $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck 146 | @echo 147 | @echo "Link check complete; look for any errors in the above output " \ 148 | "or in $(BUILDDIR)/linkcheck/output.txt." 149 | 150 | doctest: 151 | $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest 152 | @echo "Testing of doctests in the sources finished, look at the " \ 153 | "results in $(BUILDDIR)/doctest/output.txt." 154 | -------------------------------------------------------------------------------- /docs/_static/fish-text-black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomerfiliba/srcgen/9178fbfbb0a45138787992ea65fdb3c594842387/docs/_static/fish-text-black.png -------------------------------------------------------------------------------- /docs/_static/github-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomerfiliba/srcgen/9178fbfbb0a45138787992ea65fdb3c594842387/docs/_static/github-logo.png -------------------------------------------------------------------------------- /docs/_static/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomerfiliba/srcgen/9178fbfbb0a45138787992ea65fdb3c594842387/docs/_static/logo.png -------------------------------------------------------------------------------- /docs/api.rst: -------------------------------------------------------------------------------- 1 | API Documentation 2 | ================= 3 | 4 | Python and Cython 5 | ----------------- 6 | .. automodule:: srcgen.python 7 | :members: 8 | 9 | C/H files 10 | --------- 11 | .. automodule:: srcgen.c 12 | :members: 13 | 14 | XML/HTML 15 | -------- 16 | .. automodule:: srcgen.hypertext 17 | :members: 18 | 19 | -------------------------------------------------------------------------------- /docs/conf.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # srcgen documentation build configuration file, created by 4 | # sphinx-quickstart on Mon May 27 11:34:44 2013. 5 | # 6 | # This file is execfile()d with the current directory set to its containing dir. 7 | # 8 | # Note that not all possible configuration values are present in this 9 | # autogenerated file. 10 | # 11 | # All configuration values have a default; values that are commented out 12 | # serve to show the default. 13 | 14 | import sys, os 15 | sys.path.insert(0, "..") 16 | 17 | # If extensions (or modules to document with autodoc) are in another directory, 18 | # add these directories to sys.path here. If the directory is relative to the 19 | # documentation root, use os.path.abspath to make it absolute, like shown here. 20 | #sys.path.insert(0, os.path.abspath('.')) 21 | 22 | # -- General configuration ----------------------------------------------------- 23 | 24 | # If your documentation needs a minimal Sphinx version, state it here. 25 | #needs_sphinx = '1.0' 26 | 27 | # Add any Sphinx extension module names here, as strings. They can be extensions 28 | # coming with Sphinx (named 'sphinx.ext.*') or your custom ones. 29 | extensions = ['sphinx.ext.autodoc', 'sphinx.ext.viewcode'] 30 | 31 | # Add any paths that contain templates here, relative to this directory. 32 | templates_path = ['_templates'] 33 | 34 | # The suffix of source filenames. 35 | source_suffix = '.rst' 36 | 37 | # The encoding of source files. 38 | #source_encoding = 'utf-8-sig' 39 | 40 | # The master toctree document. 41 | master_doc = 'index' 42 | 43 | # General information about the project. 44 | project = u'srcgen' 45 | copyright = u'2013, Tomer Filiba' 46 | 47 | # The version info for the project you're documenting, acts as replacement for 48 | # |version| and |release|, also used in various other places throughout the 49 | # built documents. 50 | # 51 | # The short X.Y version. 52 | from srcgen.version import version_string 53 | version = version_string 54 | # The full version, including alpha/beta/rc tags. 55 | release = version_string 56 | 57 | # The language for content autogenerated by Sphinx. Refer to documentation 58 | # for a list of supported languages. 59 | #language = None 60 | 61 | # There are two options for replacing |today|: either, you set today to some 62 | # non-false value, then it is used: 63 | #today = '' 64 | # Else, today_fmt is used as the format for a strftime call. 65 | #today_fmt = '%B %d, %Y' 66 | 67 | # List of patterns, relative to source directory, that match files and 68 | # directories to ignore when looking for source files. 69 | exclude_patterns = ['_build'] 70 | 71 | # The reST default role (used for this markup: `text`) to use for all documents. 72 | #default_role = None 73 | 74 | # If true, '()' will be appended to :func: etc. cross-reference text. 75 | #add_function_parentheses = True 76 | 77 | # If true, the current module name will be prepended to all description 78 | # unit titles (such as .. function::). 79 | #add_module_names = True 80 | 81 | # If true, sectionauthor and moduleauthor directives will be shown in the 82 | # output. They are ignored by default. 83 | #show_authors = False 84 | 85 | # The name of the Pygments (syntax highlighting) style to use. 86 | pygments_style = 'sphinx' 87 | 88 | # A list of ignored prefixes for module index sorting. 89 | #modindex_common_prefix = [] 90 | 91 | 92 | # -- Options for HTML output --------------------------------------------------- 93 | 94 | # The theme to use for HTML and HTML Help pages. See the documentation for 95 | # a list of builtin themes. 96 | html_theme = 'haiku' 97 | 98 | # Theme options are theme-specific and customize the look and feel of a theme 99 | # further. For a list of options available for each theme, see the 100 | # documentation. 101 | html_theme_options = {"full_logo" : True} 102 | 103 | # Add any paths that contain custom themes here, relative to this directory. 104 | #html_theme_path = [] 105 | 106 | # The name for this set of Sphinx documents. If None, it defaults to 107 | # " v documentation". 108 | html_title = "srcgen" 109 | 110 | # A shorter title for the navigation bar. Default is the same as html_title. 111 | #html_short_title = None 112 | 113 | # The name of an image file (relative to this directory) to place at the top 114 | # of the sidebar. 115 | html_logo = "_static/logo.png" 116 | 117 | # The name of an image file (within the static path) to use as favicon of the 118 | # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 119 | # pixels large. 120 | #html_favicon = None 121 | 122 | # Add any paths that contain custom static files (such as style sheets) here, 123 | # relative to this directory. They are copied after the builtin static files, 124 | # so a file named "default.css" will overwrite the builtin "default.css". 125 | html_static_path = ['_static'] 126 | 127 | # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, 128 | # using the given strftime format. 129 | #html_last_updated_fmt = '%b %d, %Y' 130 | 131 | # If true, SmartyPants will be used to convert quotes and dashes to 132 | # typographically correct entities. 133 | #html_use_smartypants = True 134 | 135 | # Custom sidebar templates, maps document names to template names. 136 | #html_sidebars = {} 137 | 138 | # Additional templates that should be rendered to pages, maps page names to 139 | # template names. 140 | #html_additional_pages = {} 141 | 142 | # If false, no module index is generated. 143 | #html_domain_indices = True 144 | 145 | # If false, no index is generated. 146 | #html_use_index = True 147 | 148 | # If true, the index is split into individual pages for each letter. 149 | #html_split_index = False 150 | 151 | # If true, links to the reST sources are added to the pages. 152 | #html_show_sourcelink = True 153 | 154 | # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. 155 | #html_show_sphinx = True 156 | 157 | # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. 158 | #html_show_copyright = True 159 | 160 | # If true, an OpenSearch description file will be output, and all pages will 161 | # contain a tag referring to it. The value of this option must be the 162 | # base URL from which the finished HTML is served. 163 | #html_use_opensearch = '' 164 | 165 | # This is the file name suffix for HTML files (e.g. ".xhtml"). 166 | #html_file_suffix = None 167 | 168 | # Output file base name for HTML help builder. 169 | htmlhelp_basename = 'srcgendoc' 170 | 171 | 172 | # -- Options for LaTeX output -------------------------------------------------- 173 | 174 | latex_elements = { 175 | # The paper size ('letterpaper' or 'a4paper'). 176 | #'papersize': 'letterpaper', 177 | 178 | # The font size ('10pt', '11pt' or '12pt'). 179 | #'pointsize': '10pt', 180 | 181 | # Additional stuff for the LaTeX preamble. 182 | #'preamble': '', 183 | } 184 | 185 | # Grouping the document tree into LaTeX files. List of tuples 186 | # (source start file, target name, title, author, documentclass [howto/manual]). 187 | latex_documents = [ 188 | ('index', 'srcgen.tex', u'srcgen Documentation', 189 | u'Tomer Filiba', 'manual'), 190 | ] 191 | 192 | # The name of an image file (relative to this directory) to place at the top of 193 | # the title page. 194 | #latex_logo = None 195 | 196 | # For "manual" documents, if this is true, then toplevel headings are parts, 197 | # not chapters. 198 | #latex_use_parts = False 199 | 200 | # If true, show page references after internal links. 201 | #latex_show_pagerefs = False 202 | 203 | # If true, show URL addresses after external links. 204 | #latex_show_urls = False 205 | 206 | # Documents to append as an appendix to all manuals. 207 | #latex_appendices = [] 208 | 209 | # If false, no module index is generated. 210 | #latex_domain_indices = True 211 | 212 | 213 | # -- Options for manual page output -------------------------------------------- 214 | 215 | # One entry per manual page. List of tuples 216 | # (source start file, name, description, authors, manual section). 217 | man_pages = [ 218 | ('index', 'srcgen', u'srcgen Documentation', 219 | [u'Tomer Filiba'], 1) 220 | ] 221 | 222 | # If true, show URL addresses after external links. 223 | #man_show_urls = False 224 | 225 | 226 | # -- Options for Texinfo output ------------------------------------------------ 227 | 228 | # Grouping the document tree into Texinfo files. List of tuples 229 | # (source start file, target name, title, author, 230 | # dir menu entry, description, category) 231 | texinfo_documents = [ 232 | ('index', 'srcgen', u'srcgen Documentation', 233 | u'Tomer Filiba', 'srcgen', 'One line description of project.', 234 | 'Miscellaneous'), 235 | ] 236 | 237 | # Documents to append as an appendix to all manuals. 238 | #texinfo_appendices = [] 239 | 240 | # If false, no module index is generated. 241 | #texinfo_domain_indices = True 242 | 243 | # How to display URL addresses: 'footnote', 'no', or 'inline'. 244 | #texinfo_show_urls = 'footnote' 245 | -------------------------------------------------------------------------------- /docs/index.rst: -------------------------------------------------------------------------------- 1 | .. raw:: html 2 | 3 |
5 | Quick Links
6 | 12 |
13 | 14 | 16 |
17 | 18 | 20 |
21 | 22 | 24 |
25 | 26 | Semantic Code Generation 27 | ======================== 28 | What is semantic code generation? 29 | 30 | Contents 31 | -------- 32 | 33 | .. toctree:: 34 | :maxdepth: 2 35 | 36 | api 37 | 38 | 39 | -------------------------------------------------------------------------------- /docs/make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | REM Command file for Sphinx documentation 4 | 5 | if "%SPHINXBUILD%" == "" ( 6 | set SPHINXBUILD=sphinx-build 7 | ) 8 | set BUILDDIR=_build 9 | set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% . 10 | set I18NSPHINXOPTS=%SPHINXOPTS% . 11 | if NOT "%PAPER%" == "" ( 12 | set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% 13 | set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS% 14 | ) 15 | 16 | if "%1" == "" goto help 17 | 18 | if "%1" == "help" ( 19 | :help 20 | echo.Please use `make ^` where ^ is one of 21 | echo. html to make standalone HTML files 22 | echo. dirhtml to make HTML files named index.html in directories 23 | echo. singlehtml to make a single large HTML file 24 | echo. pickle to make pickle files 25 | echo. json to make JSON files 26 | echo. htmlhelp to make HTML files and a HTML help project 27 | echo. qthelp to make HTML files and a qthelp project 28 | echo. devhelp to make HTML files and a Devhelp project 29 | echo. epub to make an epub 30 | echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter 31 | echo. text to make text files 32 | echo. man to make manual pages 33 | echo. texinfo to make Texinfo files 34 | echo. gettext to make PO message catalogs 35 | echo. changes to make an overview over all changed/added/deprecated items 36 | echo. linkcheck to check all external links for integrity 37 | echo. doctest to run all doctests embedded in the documentation if enabled 38 | goto end 39 | ) 40 | 41 | if "%1" == "clean" ( 42 | for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i 43 | del /q /s %BUILDDIR%\* 44 | goto end 45 | ) 46 | 47 | if "%1" == "html" ( 48 | %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html 49 | if errorlevel 1 exit /b 1 50 | echo. 51 | echo.Build finished. The HTML pages are in %BUILDDIR%/html. 52 | goto end 53 | ) 54 | 55 | if "%1" == "dirhtml" ( 56 | %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml 57 | if errorlevel 1 exit /b 1 58 | echo. 59 | echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. 60 | goto end 61 | ) 62 | 63 | if "%1" == "singlehtml" ( 64 | %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml 65 | if errorlevel 1 exit /b 1 66 | echo. 67 | echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. 68 | goto end 69 | ) 70 | 71 | if "%1" == "pickle" ( 72 | %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle 73 | if errorlevel 1 exit /b 1 74 | echo. 75 | echo.Build finished; now you can process the pickle files. 76 | goto end 77 | ) 78 | 79 | if "%1" == "json" ( 80 | %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json 81 | if errorlevel 1 exit /b 1 82 | echo. 83 | echo.Build finished; now you can process the JSON files. 84 | goto end 85 | ) 86 | 87 | if "%1" == "htmlhelp" ( 88 | %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp 89 | if errorlevel 1 exit /b 1 90 | echo. 91 | echo.Build finished; now you can run HTML Help Workshop with the ^ 92 | .hhp project file in %BUILDDIR%/htmlhelp. 93 | goto end 94 | ) 95 | 96 | if "%1" == "qthelp" ( 97 | %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp 98 | if errorlevel 1 exit /b 1 99 | echo. 100 | echo.Build finished; now you can run "qcollectiongenerator" with the ^ 101 | .qhcp project file in %BUILDDIR%/qthelp, like this: 102 | echo.^> qcollectiongenerator %BUILDDIR%\qthelp\srcgen.qhcp 103 | echo.To view the help file: 104 | echo.^> assistant -collectionFile %BUILDDIR%\qthelp\srcgen.ghc 105 | goto end 106 | ) 107 | 108 | if "%1" == "devhelp" ( 109 | %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp 110 | if errorlevel 1 exit /b 1 111 | echo. 112 | echo.Build finished. 113 | goto end 114 | ) 115 | 116 | if "%1" == "epub" ( 117 | %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub 118 | if errorlevel 1 exit /b 1 119 | echo. 120 | echo.Build finished. The epub file is in %BUILDDIR%/epub. 121 | goto end 122 | ) 123 | 124 | if "%1" == "latex" ( 125 | %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex 126 | if errorlevel 1 exit /b 1 127 | echo. 128 | echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. 129 | goto end 130 | ) 131 | 132 | if "%1" == "text" ( 133 | %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text 134 | if errorlevel 1 exit /b 1 135 | echo. 136 | echo.Build finished. The text files are in %BUILDDIR%/text. 137 | goto end 138 | ) 139 | 140 | if "%1" == "man" ( 141 | %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man 142 | if errorlevel 1 exit /b 1 143 | echo. 144 | echo.Build finished. The manual pages are in %BUILDDIR%/man. 145 | goto end 146 | ) 147 | 148 | if "%1" == "texinfo" ( 149 | %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo 150 | if errorlevel 1 exit /b 1 151 | echo. 152 | echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo. 153 | goto end 154 | ) 155 | 156 | if "%1" == "gettext" ( 157 | %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale 158 | if errorlevel 1 exit /b 1 159 | echo. 160 | echo.Build finished. The message catalogs are in %BUILDDIR%/locale. 161 | goto end 162 | ) 163 | 164 | if "%1" == "changes" ( 165 | %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes 166 | if errorlevel 1 exit /b 1 167 | echo. 168 | echo.The overview file is in %BUILDDIR%/changes. 169 | goto end 170 | ) 171 | 172 | if "%1" == "linkcheck" ( 173 | %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck 174 | if errorlevel 1 exit /b 1 175 | echo. 176 | echo.Link check complete; look for any errors in the above output ^ 177 | or in %BUILDDIR%/linkcheck/output.txt. 178 | goto end 179 | ) 180 | 181 | if "%1" == "doctest" ( 182 | %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest 183 | if errorlevel 1 exit /b 1 184 | echo. 185 | echo.Testing of doctests in the sources finished, look at the ^ 186 | results in %BUILDDIR%/doctest/output.txt. 187 | goto end 188 | ) 189 | 190 | :end 191 | -------------------------------------------------------------------------------- /release.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | rm -rf dist 3 | rm -rf build 4 | rm -rf *.egg-info 5 | python setup.py register 6 | python setup.py sdist --formats=zip,gztar bdist_wininst --plat-name=win32 upload 7 | rm -rf *.egg-info 8 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | six 2 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import os 3 | try: 4 | from setuptools import setup 5 | except ImportError: 6 | from distutils.core import setup 7 | 8 | HERE = os.path.dirname(__file__) 9 | exec(open(os.path.join(HERE, "srcgen", "version.py")).read()) 10 | 11 | setup(name = "srcgen", 12 | version = version_string, #@UndefinedVariable 13 | description = "srcgen: The semantic source code generation framework", 14 | author = "Tomer Filiba", 15 | author_email = "tomerfiliba@gmail.com", 16 | license = "MIT", 17 | url = "https://srcgen.readthedocs.org/", 18 | packages = ["srcgen"], 19 | provides = ["srcgen"], 20 | install_requires = ["six"], 21 | keywords = "source, code, generation, programmatic, semantic", 22 | long_description = open(os.path.join(HERE, "README.rst"), "r").read(), 23 | classifiers = [ 24 | "Development Status :: 5 - Production/Stable", 25 | "License :: OSI Approved :: MIT License", 26 | "Programming Language :: Python :: 2.5", 27 | "Programming Language :: Python :: 2.6", 28 | "Programming Language :: Python :: 2.7", 29 | "Programming Language :: Python :: 3", 30 | "Programming Language :: Python :: 3.0", 31 | "Programming Language :: Python :: 3.1", 32 | "Programming Language :: Python :: 3.2", 33 | "Programming Language :: Python :: 3.3", 34 | ], 35 | ) 36 | 37 | -------------------------------------------------------------------------------- /srcgen/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomerfiliba/srcgen/9178fbfbb0a45138787992ea65fdb3c594842387/srcgen/__init__.py -------------------------------------------------------------------------------- /srcgen/base.py: -------------------------------------------------------------------------------- 1 | from __future__ import with_statement 2 | 3 | 4 | class BaseModule(object): 5 | def __init__(self, name = None, line_width = 80, indentation = " "): 6 | self._indentation = indentation 7 | self._name = name 8 | self._line_width = line_width 9 | self._curr = [] 10 | self._sep_lines = 0 11 | def __str__(self): 12 | return self.render() 13 | 14 | @classmethod 15 | def _render(cls, curr, level, indentation): 16 | indent = indentation * level 17 | for elem in curr: 18 | if isinstance(elem, list): 19 | for line in cls._render(elem, level + 1, indentation): 20 | yield line 21 | else: 22 | line = str(elem) 23 | yield indent + line if line.strip() else "" 24 | def render(self): 25 | text = "\n".join(self._render(self._curr, 0, self._indentation)) 26 | if not text.endswith("\n"): 27 | text += "\n" 28 | return text 29 | 30 | def dump(self, filename_or_fileobj): 31 | """Renders the module and dumps it to the given file. ``file`` can be either a file name or 32 | a file object""" 33 | data = self.render() 34 | if hasattr(filename_or_fileobj, "write"): 35 | filename_or_fileobj.write(data) 36 | else: 37 | with open(filename_or_fileobj, "w") as f: 38 | f.write(data) 39 | 40 | def sep(self, count = 1): 41 | if self._sep_lines >= count: 42 | return 43 | self._curr.extend("" for _ in range(count)) 44 | self._sep_lines += count 45 | 46 | def _append(self, line): 47 | if line.strip(): 48 | self._curr.append(line) 49 | self._sep_lines = 0 50 | else: 51 | self._curr.append("") 52 | self._sep_lines += 1 53 | 54 | def R(*args, **kwargs): 55 | """repr""" 56 | if args and kwargs: 57 | raise TypeError("Either positional or keyword arguments may be given") 58 | elif args: 59 | if len(args) != 1: 60 | raise TypeError("Exactly one positional argument may be given") 61 | return repr(args[0]) 62 | elif kwargs: 63 | if len(kwargs) != 1: 64 | raise TypeError("Exactly one keyword argument may be given") 65 | return "%s = %r" % kwargs.popitem() 66 | else: 67 | raise TypeError("Either positional or keyword arguments must be given") 68 | 69 | 70 | class BaseE(object): 71 | """ 72 | Expression object 73 | """ 74 | __slots__ = ["_value"] 75 | def __init__(self, value): 76 | self._value = str(value) 77 | def __str__(self): 78 | return self._value 79 | def __repr__(self): 80 | return self._value 81 | 82 | def __add__(self, other): 83 | return self.__class__("(%r + %r)" % (self, other)) 84 | def __sub__(self, other): 85 | return self.__class__("(%r - %r)" % (self, other)) 86 | def __mul__(self, other): 87 | return self.__class__("(%r * %r)" % (self, other)) 88 | def __truediv__(self, other): 89 | return self.__class__("(%r / %r)" % (self, other)) 90 | __div__ = __truediv__ 91 | def __mod__(self, other): 92 | return self.__class__("(%r % %r)" % (self, other)) 93 | def __pow__(self, other): 94 | return self.__class__("(%r % %r)" % (self, other)) 95 | def __or__(self, other): 96 | return self.__class__("(%r | %r)" % (self, other)) 97 | def __and__(self, other): 98 | return self.__class__("(%r & %r)" % (self, other)) 99 | def __xor__(self, other): 100 | return self.__class__("(%r ^ %r)" % (self, other)) 101 | def __lshift__(self, other): 102 | return self.__class__("(%r << %r)" % (self, other)) 103 | def __rshift__(self, other): 104 | return self.__class__("(%r >> %r)" % (self, other)) 105 | 106 | def __radd__(self, other): 107 | return self.__class__("(%r + %r)" % (other, self)) 108 | def __rsub__(self, other): 109 | return self.__class__("(%r - %r)" % (other, self)) 110 | def __rmul__(self, other): 111 | return self.__class__("(%r * %r)" % (other, self)) 112 | def __rtruediv__(self, other): 113 | return self.__class__("(%r / %r)" % (other, self)) 114 | __rdiv__ = __rtruediv__ 115 | def __rmod__(self, other): 116 | return self.__class__("(%r % %r)" % (other, self)) 117 | def __rpow__(self, other): 118 | return self.__class__("(%r % %r)" % (other, self)) 119 | def __ror__(self, other): 120 | return self.__class__("(%r or %r)" % (other, self)) 121 | def __rand__(self, other): 122 | return self.__class__("(%r and %r)" % (other, self)) 123 | def __rxor__(self, other): 124 | return self.__class__("(%r ^ %r)" % (other, self)) 125 | def __rlshift__(self, other): 126 | return self.__class__("(%r << %r)" % (other, self)) 127 | def __rrshift__(self, other): 128 | return self.__class__("(%r >> %r)" % (other, self)) 129 | 130 | def __gt__(self, other): 131 | return self.__class__("(%r > %r)" % (self, other)) 132 | def __ge__(self, other): 133 | return self.__class__("(%r >= %r)" % (self, other)) 134 | def __lt__(self, other): 135 | return self.__class__("(%r < %r)" % (self, other)) 136 | def __le__(self, other): 137 | return self.__class__("(%r <= %r)" % (self, other)) 138 | def __eq__(self, other): 139 | return self.__class__("(%r == %r)" % (self, other)) 140 | def __ne__(self, other): 141 | return self.__class__("(%r != %r)" % (self, other)) 142 | 143 | def __neg__(self): 144 | return self.__class__("-%r" % (self,)) 145 | def __pos__(self): 146 | return self.__class__("+%r" % (self,)) 147 | def __inv__(self): 148 | return self.__class__("~%r" % (self,)) 149 | __invert__ = __inv__ 150 | 151 | def __getitem__(self, key): 152 | return self.__class__("%r[%r]" % (self, key)) 153 | def __getattr__(self, name): 154 | return self.__class__("%r.%s" % (self, name)) 155 | 156 | 157 | 158 | -------------------------------------------------------------------------------- /srcgen/c.py: -------------------------------------------------------------------------------- 1 | from __future__ import with_statement 2 | from srcgen.base import BaseModule, BaseE, R 3 | from contextlib import contextmanager 4 | 5 | 6 | class CModule(BaseModule): 7 | def comment(self, *lines, **kwargs): 8 | box = kwargs.pop("box", False) 9 | sep = kwargs.pop("sep", False) 10 | if sep and box: 11 | self._append("") 12 | self._append("/* " + "*" * (self._line_width-2)) 13 | elif sep: 14 | self._append("/*") 15 | elif box: 16 | self._append("/* " + "*" * (self._line_width-2)) 17 | self._curr.extend("/* %s" % (l.replace("*/", "* /"),) for l in "\n".join(lines).splitlines()) 18 | if sep and box: 19 | self._append("*" * (self._line_width - 2) + " */") 20 | self._append("") 21 | elif sep: 22 | self._append("*/") 23 | elif box: 24 | self._append("*" * (self._line_width - 2) + " */") 25 | else: 26 | self._curr[-1] += " */" 27 | 28 | # 29 | # Statements 30 | # 31 | def stmt(self, text, *args, **kwargs): 32 | text = str(text) 33 | semicolon = kwargs.pop("semicolon", True) 34 | if kwargs: 35 | raise TypeError("Invalid keyword argument %r" % (kwargs.keys(),)) 36 | if semicolon and text.strip()[0] != "#" and text[-1] not in ";:,{": 37 | text += ";" 38 | self._append(text.format(*args) if args else text) 39 | def break_(self): 40 | self.stmt("break") 41 | def continue_(self): 42 | self.stmt("continue") 43 | def return_(self, expr, *args): 44 | self.stmt("return %s" % (expr,), *args) 45 | def goto(self, name): 46 | self.stmt("goto %s" % (name,)) 47 | def label(self, name): 48 | self.stmt("%s:" % (name,)) 49 | 50 | def include(self, filename): 51 | filename = str(filename) 52 | if filename.startswith("<"): 53 | self.stmt("#include %s" % (filename,)) 54 | else: 55 | self.stmt('#include "%s"' % (filename,)) 56 | def define(self, name, value = None): 57 | if value: 58 | value = value.replace("\n", "\\\n") 59 | self.stmt("#define %s %s" % (name, value)) 60 | else: 61 | self.stmt("#define %s" % (name,)) 62 | 63 | # 64 | # Suites 65 | # 66 | @contextmanager 67 | def suite(self, headline, *args, **kwargs): 68 | headline = str(headline) 69 | terminator = kwargs.pop("terminator", None) 70 | if kwargs: 71 | raise TypeError("Invalid keyword argument %r" % (kwargs.keys(),)) 72 | if headline[-1] not in "{:": 73 | headline += " {" 74 | self._append(headline.format(*args) if args else headline) 75 | prev = self._curr 76 | self._curr = [] 77 | prev.append(self._curr) 78 | yield 79 | self._curr = prev 80 | if terminator is None: 81 | self._append("}") 82 | else: 83 | if terminator: 84 | self._append(terminator) 85 | 86 | def if_(self, cond, *args): 87 | return self.suite("if (%s)" % (cond,), *args) 88 | def elif_(self, cond, *args): 89 | return self.suite("else if (%s)" % (cond,), *args) 90 | def else_(self): 91 | return self.suite("else") 92 | def for_(self, init, cond, next): 93 | return self.suite("for (%s; %s; %s)" % (init, cond, next)) 94 | def while_(self, cond, *args): 95 | return self.suite("while %s:" % (cond,), *args) 96 | def do_while(self, cond, *args): 97 | return self.suite("do", terminator = "} while(%s);" % (cond,), *args) 98 | 99 | def switch(self, cond, *args): 100 | return self.suite("switch (%s)" % (cond,), *args) 101 | def case(self, val, *args): 102 | return self.suite("case %s:" % (val,), terminator = "", *args) 103 | def default(self): 104 | return self.suite("default:", terminator = "") 105 | 106 | @contextmanager 107 | def func(self, type, name, *args): 108 | with self.suite("%s %s(%s)" % (type, name, ", ".join(str(a) for a in args))): yield 109 | self.sep() 110 | 111 | @contextmanager 112 | def struct(self, name, varname = None): 113 | with self.suite("struct %s" % (name,), terminator = "} %s;" % (varname,) if varname else "};"): yield 114 | self.sep() 115 | @contextmanager 116 | def union(self, name, varname = None): 117 | with self.suite("union %s" % (name,), terminator = "} %s;" % (varname,) if varname else "};"): yield 118 | self.sep() 119 | @contextmanager 120 | def enum(self, name, varname = None): 121 | with self.suite("enum %s" % (name,), terminator = "} %s;" % (varname,) if varname else "};"): 122 | yield 123 | if self._curr[-1].endswith(","): 124 | self._curr[-1] = self._curr[-1][:-1] 125 | self.sep() 126 | def enum_member(self, name, value = None): 127 | self._append("%s = %s," % (name, value) if value is not None else "%s," % (name,)) 128 | 129 | @contextmanager 130 | def typedef(self, type, name): 131 | self.stmt("typedef %s %s" % (type, name)) 132 | @contextmanager 133 | def typedef_struct(self, name): 134 | with self.suite("typedef struct _%s" % (name,), terminator = "} %s;" % (name,)): yield 135 | self.sep() 136 | @contextmanager 137 | def typedef_union(self, name): 138 | with self.suite("typedef union _%s" % (name,), terminator = "} %s;" % (name,)): yield 139 | self.sep() 140 | @contextmanager 141 | def typedef_enum(self, name): 142 | with self.suite("typedef enum _%s" % (name,), terminator = "} %s;" % (name,)): yield 143 | self.sep() 144 | 145 | # preprocessor stuff 146 | @contextmanager 147 | def _if_suite(self, headline, merge_endif): 148 | if merge_endif and self._curr and self._curr[-1].startswith("#endif"): 149 | self._curr.pop(-1) 150 | self._append(headline) 151 | prev = self._curr 152 | self._curr = [] 153 | prev.append(self._curr) 154 | yield 155 | self._curr = prev 156 | self.stmt("#endif") 157 | 158 | def IF(self, cond): 159 | return self._if_suite("#if %s" % (cond,), False) 160 | def ELIF(self, cond): 161 | return self._if_suite("#elif %s" % (cond,), True) 162 | def ELSE(self, cond): 163 | return self._if_suite("#else %s" % (cond,), True) 164 | def IFDEF(self, name): 165 | return self._if_suite("#ifdef %s" % (name,), False) 166 | def IFNDEF(self, name): 167 | return self._if_suite("#ifndef %s" % (name,), False) 168 | 169 | class HModule(CModule): 170 | def __init__(self, guard_name): 171 | CModule.__init__(self) 172 | self._guard_name = guard_name 173 | def render(self): 174 | text = CModule.render(self) 175 | text = "#ifndef %s\n#define %s\n\n" % (self._guard_name, self._guard_name) + text 176 | text += "\n#endif /* %s */\n" % (self._guard_name,) 177 | return text 178 | 179 | def render_literal(obj): 180 | """ 181 | Render obj as a literal expression in C. 182 | """ 183 | if isinstance(obj, str): 184 | return '"%s"' % obj 185 | else: 186 | return repr(obj) 187 | 188 | class E(BaseE): 189 | def __call__(self, *args): 190 | return E("%r(%s)" % (self, ", ".join(render_literal(a) for a in args))) 191 | 192 | 193 | 194 | 195 | 196 | 197 | -------------------------------------------------------------------------------- /srcgen/html.py: -------------------------------------------------------------------------------- 1 | import weakref 2 | import six 3 | import itertools 4 | from contextlib import contextmanager 5 | from functools import partial 6 | 7 | 8 | _MAPPING = {"&" : "&", "'" : "'", '"' : """, "<" : "<", ">" : ">"} 9 | def xml_escape(text): 10 | if text is None: 11 | return "" 12 | return "".join(_MAPPING.get(ch, ch) for ch in str(text)) 13 | 14 | class Htmlable(object): 15 | __slots__ = [] 16 | 17 | def render_html(self): 18 | raise NotImplementedError() 19 | 20 | class HtmlElement(Htmlable): 21 | __slots__ = ["doc", "tag", "attrs", "elements"] 22 | MULTILINE = True 23 | 24 | def __init__(self, doc, tag, elems, attrs): 25 | self.doc = doc 26 | self.tag = tag 27 | self.attrs = attrs 28 | self.elements = elems 29 | 30 | def __enter__(self): 31 | self.doc._push(self) 32 | return self 33 | def __exit__(self, t, v, tb): 34 | self.doc._pop() 35 | 36 | def _format_attrs(self): 37 | attrs = [] 38 | for k, v in self.attrs.items(): 39 | if k.startswith("_") or v is None or v is False: 40 | continue 41 | k = k.rstrip("_").replace("_", "-") 42 | if v is True: 43 | attrs.append(xml_escape(k)) 44 | else: 45 | attrs.append('%s="%s"' % (xml_escape(k), xml_escape(v))) 46 | if attrs: 47 | attrs = " " + " ".join(attrs) 48 | else: 49 | attrs = "" 50 | return attrs 51 | 52 | def render_html(self): 53 | attrs = self._format_attrs() 54 | if self.elements: 55 | yield 0, self.MULTILINE, "<%s%s>" % (xml_escape(self.tag), attrs) 56 | for elem in self.elements: 57 | if elem is None: 58 | continue 59 | if isinstance(elem, Htmlable): 60 | for level, nl, line in elem.render_html(): 61 | yield level + 1, nl, line 62 | else: 63 | yield 1, False, xml_escape(elem) 64 | yield 0, self.MULTILINE, "" % (xml_escape(self.tag),) 65 | else: 66 | yield 0, self.MULTILINE, "<%s%s/>" % (xml_escape(self.tag), attrs) 67 | 68 | class InlineHtmlElement(HtmlElement): 69 | __slots__ = [] 70 | MULTILINE = False 71 | 72 | class Raw(Htmlable): 73 | __slots__ = ["text"] 74 | def __init__(self, text): 75 | self.text = str(text) 76 | def render_html(self): 77 | return [(-1, False, self.text)] 78 | 79 | nbsp = Raw(" ") 80 | copy = Raw("©") 81 | def escaped(val): 82 | if isinstance(val, six.string_types): 83 | val = ord(val[0]) 84 | return Raw("&#%04x;" % (val,)) 85 | 86 | class Comment(Htmlable): 87 | __slots__ = ["lines"] 88 | def __init__(self, lines): 89 | self.lines = lines 90 | def render_html(self): 91 | if not self.lines: 92 | return 93 | if len(self.lines) == 1: 94 | yield 0, True, "" % (xml_escape(self.lines[0]).replace("-->", "-- >")) 95 | else: 96 | yield 0, False, "", "-- >") 99 | yield 0, False, " -->" 100 | 101 | class Selector(object): 102 | __slots__ = ["parent", "names", "properties"] 103 | def __init__(self, parent, names): 104 | self.parent = parent 105 | self.names = names 106 | self.properties = {} 107 | def __setitem__(self, name, value): 108 | self.properties[name] = str(value) 109 | def render_html(self): 110 | nesting = [self.names] 111 | node = self.parent 112 | while node: 113 | nesting.append(node.names) 114 | node = node.parent 115 | for parts in itertools.product(*reversed(nesting)): 116 | parts = [(" " if p.strip()[0] not in "+.:>#[]()," else "") + p.strip() for p in parts] 117 | yield 0, True, "%s {" % ("".join(parts).strip(),) 118 | for key, val in self.properties.items(): 119 | yield 1, True, "%s: %s;" % (key.rstrip("_").replace("_", "-"), val) 120 | yield 0, True, "}" 121 | 122 | class CSS(Htmlable): 123 | __slots__ = ["_curr", "_selectors"] 124 | def __init__(self): 125 | self._curr = None 126 | self._selectors = [] 127 | @contextmanager 128 | def __call__(self, *selectors): 129 | sel = Selector(self._curr if self._curr else "", selectors) 130 | self._selectors.append(sel) 131 | prev = self._curr 132 | self._curr = sel 133 | try: 134 | yield sel 135 | finally: 136 | self._curr = prev 137 | def __setitem__(self, name, value): 138 | self._curr[name] = value 139 | def __bool__(self): 140 | return bool(self._selectors) 141 | __nonzero__ = __bool__ 142 | 143 | def render_html(self): 144 | for sel in self._selectors: 145 | for level, nl, line in sel.render_html(): 146 | yield level, nl, line 147 | 148 | 149 | class HtmlDocument(object): 150 | DOCTYPE = '' 151 | __slots__ = ["__weakref__", "_root", "_stack", "_head_css", "_head", "_body"] 152 | 153 | def __init__(self, xmlns = "http://www.w3.org/1999/xhtml"): 154 | self._root = HtmlElement(weakref.proxy(self), "html", [], attrs = {"xmlns" : xmlns}) 155 | self._stack = [self._root] 156 | self._head = None 157 | self._body = None 158 | self._head_css = None 159 | 160 | def __str__(self): 161 | return self.render() 162 | def render(self, tabulator = "\t"): 163 | lines = [] 164 | prev_nl = False 165 | for level, nl, line in self._root.render_html(): 166 | if not prev_nl and not nl: 167 | level = 0 168 | lines.append("%s%s%s" % ("\n" if nl or prev_nl else "", tabulator * level, line)) 169 | prev_nl = nl 170 | return self.DOCTYPE + "".join(lines) 171 | 172 | def _push(self, elem): 173 | self._stack.append(elem) 174 | def _pop(self): 175 | self._stack.pop(-1) 176 | def text(self, *texts): 177 | self._stack[-1].elements.extend(texts) 178 | def attrs(self, **attrs): 179 | self._stack[-1].attrs.update(attrs) 180 | def raw(self, text): 181 | self._stack[-1].elements.append(Raw(text)) 182 | def comment(self, *lines): 183 | self._stack[-1].elements.append(Comment(lines)) 184 | 185 | def subelem(self, tag, *elems, **attrs): 186 | elem = HtmlElement(weakref.proxy(self), tag, list(elems), attrs) 187 | self._stack[-1].elements.append(elem) 188 | return elem 189 | def inline_subelem(self, tag, *elems, **attrs): 190 | elem = InlineHtmlElement(weakref.proxy(self), tag, list(elems), attrs) 191 | self._stack[-1].elements.append(elem) 192 | return elem 193 | 194 | def head_css(self): 195 | if self._head_css is None: 196 | self._head_css = CSS() 197 | with self.head(): 198 | with self.style(): 199 | self._stack[-1].elements.append(self._head_css) 200 | return self._head_css 201 | 202 | def __getattr__(self, name): 203 | if name.startswith("_"): 204 | raise AttributeError(name) 205 | return partial(self.subelem, name) 206 | 207 | #=================================================================================================================== 208 | # Elements 209 | #=================================================================================================================== 210 | def head(self): 211 | if self._head is None: 212 | self._head = self.subelem("head") 213 | return self._head 214 | def body(self, *texts, **attrs): 215 | if self._body is None: 216 | self._body = self.subelem("body", *texts, **attrs) 217 | return self._body 218 | 219 | def meta(self, **attrs): 220 | return self.subelem("meta", **attrs) 221 | def title(self, *texts): 222 | return self.inline_subelem("title", *texts) 223 | def base(self, **attrs): 224 | return self.subelem("base", **attrs) 225 | def link(self, **attrs): 226 | return self.subelem("link", **attrs) 227 | def style(self, type_ = "text/css", **attrs): 228 | return self.subelem("style", type_ = type_, **attrs) 229 | def script(self, type_ = "text/javascript", **attrs): 230 | return self.subelem("script", None, type_ = type_, **attrs) 231 | def link_css(self, href): 232 | return self.link(href = href, type = "text/css", rel = "stylesheet") 233 | def script_src(self, src, type_ = "text/javascript"): 234 | return self.inline_subelem("script", None, type_ = type_, src = src) 235 | 236 | def div(self, *texts, **attrs): 237 | return self.subelem("div", *texts, **attrs) 238 | def blockquote(self, *texts, **attrs): 239 | return self.subelem("blockquote", *texts, **attrs) 240 | def dl(self, *texts, **attrs): 241 | return self.subelem("dl", *texts, **attrs) 242 | def dt(self, *texts, **attrs): 243 | return self.subelem("dt", *texts, **attrs) 244 | def dd(self, *texts, **attrs): 245 | return self.subelem("dd", *texts, **attrs) 246 | def li(self, *texts, **attrs): 247 | return self.subelem("li", *texts, **attrs) 248 | def ul(self, *texts, **attrs): 249 | return self.subelem("ul", *texts, **attrs) 250 | def ol(self, *texts, **attrs): 251 | return self.subelem("ol", *texts, **attrs) 252 | def form(self, *texts, **attrs): 253 | return self.subelem("form", *texts, **attrs) 254 | def input(self, *texts, **attrs): 255 | return self.subelem("input", *texts, **attrs) 256 | def button(self, *texts, **attrs): 257 | return self.subelem("button", *texts, **attrs) 258 | def select(self, *texts, **attrs): 259 | return self.subelem("select", *texts, **attrs) 260 | def label(self, *texts, **attrs): 261 | return self.subelem("label", *texts, **attrs) 262 | def optgroup(self, *texts, **attrs): 263 | return self.subelem("optgroup", *texts, **attrs) 264 | def option(self, *texts, **attrs): 265 | return self.subelem("option", *texts, **attrs) 266 | def textarea(self, *texts, **attrs): 267 | return self.subelem("textarea", *texts, **attrs) 268 | def legend(self, *texts, **attrs): 269 | return self.subelem("legend", *texts, **attrs) 270 | def table(self, *texts, **attrs): 271 | return self.subelem("table", *texts, **attrs) 272 | def tr(self, *texts, **attrs): 273 | return self.subelem("tr", *texts, **attrs) 274 | def th(self, *texts, **attrs): 275 | return self.subelem("th", *texts, **attrs) 276 | def td(self, *texts, **attrs): 277 | return self.subelem("td", *texts, **attrs) 278 | def colgroup(self, *texts, **attrs): 279 | return self.subelem("colgroup", *texts, **attrs) 280 | def thead(self, *texts, **attrs): 281 | return self.subelem("thead", *texts, **attrs) 282 | def tbody(self, *texts, **attrs): 283 | return self.subelem("tbody", *texts, **attrs) 284 | def tfoot(self, *texts, **attrs): 285 | return self.subelem("tfoot", *texts, **attrs) 286 | def frame(self, *texts, **attrs): 287 | return self.subelem("frame", *texts, **attrs) 288 | def iframe(self, *texts, **attrs): 289 | return self.subelem("iframe", *texts, **attrs) 290 | def noframe(self, *texts, **attrs): 291 | return self.subelem("noframe", *texts, **attrs) 292 | def frameset(self, *texts, **attrs): 293 | return self.subelem("frameset", *texts, **attrs) 294 | def p(self, *texts, **attrs): 295 | return self.subelem("p", *texts, **attrs) 296 | 297 | def img(self, *texts, **attrs): 298 | return self.inline_subelem("img", *texts, **attrs) 299 | def pre(self, *texts, **attrs): 300 | return self.inline_subelem("pre", *texts, **attrs) 301 | def code(self, *texts, **attrs): 302 | return self.inline_subelem("code", *texts, **attrs) 303 | def span(self, *texts, **attrs): 304 | return self.inline_subelem("span", *texts, **attrs) 305 | def a(self, *texts, **attrs): 306 | return self.inline_subelem("a", *texts, **attrs) 307 | def b(self, *texts, **attrs): 308 | return self.inline_subelem("b", *texts, **attrs) 309 | def br(self, *texts, **attrs): 310 | return self.inline_subelem("br", *texts, **attrs) 311 | def hr(self, *texts, **attrs): 312 | return self.inline_subelem("hr", *texts, **attrs) 313 | def em(self, *texts, **attrs): 314 | return self.inline_subelem("em", *texts, **attrs) 315 | def strong(self, *texts, **attrs): 316 | return self.inline_subelem("strong", *texts, **attrs) 317 | def cite(self, *texts, **attrs): 318 | return self.inline_subelem("cite", *texts, **attrs) 319 | def i(self, *texts, **attrs): 320 | return self.inline_subelem("i", *texts, **attrs) 321 | def u(self, *texts, **attrs): 322 | return self.inline_subelem("u", *texts, **attrs) 323 | def sub(self, *texts, **attrs): 324 | return self.inline_subelem("sub", *texts, **attrs) 325 | def sup(self, *texts, **attrs): 326 | return self.inline_subelem("sup", *texts, **attrs) 327 | def big(self, *texts, **attrs): 328 | return self.inline_subelem("big", *texts, **attrs) 329 | def small(self, *texts, **attrs): 330 | return self.inline_subelem("small", *texts, **attrs) 331 | def h1(self, *texts, **attrs): 332 | return self.inline_subelem("h1", *texts, **attrs) 333 | def h2(self, *texts, **attrs): 334 | return self.inline_subelem("h2", *texts, **attrs) 335 | def h3(self, *texts, **attrs): 336 | return self.inline_subelem("h3", *texts, **attrs) 337 | def h4(self, *texts, **attrs): 338 | return self.inline_subelem("h4", *texts, **attrs) 339 | def h5(self, *texts, **attrs): 340 | return self.inline_subelem("h5", *texts, **attrs) 341 | def h6(self, *texts, **attrs): 342 | return self.inline_subelem("h6", *texts, **attrs) 343 | 344 | 345 | 346 | 347 | 348 | 349 | 350 | 351 | 352 | -------------------------------------------------------------------------------- /srcgen/js.py: -------------------------------------------------------------------------------- 1 | import json 2 | from srcgen.base import BaseModule 3 | from contextlib import contextmanager 4 | from srcgen.html import Htmlable, xml_escape 5 | 6 | 7 | class JS(BaseModule, Htmlable): 8 | def comment(self, *lines, **kwargs): 9 | box = kwargs.pop("box", False) 10 | sep = kwargs.pop("sep", False) 11 | if sep and box: 12 | self._append("") 13 | self._append("/* " + "*" * (self._line_width-2)) 14 | elif sep: 15 | self._append("/*") 16 | elif box: 17 | self._append("/* " + "*" * (self._line_width-2)) 18 | self._curr.extend("/* %s" % (l.replace("*/", "* /"),) for l in "\n".join(lines).splitlines()) 19 | if sep and box: 20 | self._append("*" * (self._line_width - 2) + " */") 21 | self._append("") 22 | elif sep: 23 | self._append("*/") 24 | elif box: 25 | self._append("*" * (self._line_width - 2) + " */") 26 | else: 27 | self._curr[-1] += " */" 28 | 29 | def render_html(self): 30 | for line in xml_escape(self.render()).splitlines(): 31 | yield 0, True, line 32 | 33 | def stmt(self, text, *args, **kwargs): 34 | text = str(text) 35 | semicolon = kwargs.pop("semicolon", True) 36 | if kwargs: 37 | raise TypeError("Invalid keyword argument %r" % (kwargs.keys(),)) 38 | if semicolon and text.strip()[0] != "#" and text[-1] not in ";:,{": 39 | text += ";" 40 | self._append(text.format(*args) if args else text) 41 | def break_(self): 42 | self.stmt("break") 43 | def continue_(self): 44 | self.stmt("continue") 45 | def return_(self, expr, *args): 46 | self.stmt("return %s" % (expr,), *args) 47 | def var(self, name, init = None): 48 | self.stmt("var {0} = {1}", name, init if isinstance(init, str) else json.dumps(init)) 49 | 50 | @contextmanager 51 | def suite(self, headline, *args, **kwargs): 52 | headline = str(headline) 53 | terminator = kwargs.pop("terminator", None) 54 | if kwargs: 55 | raise TypeError("Invalid keyword argument %r" % (kwargs.keys(),)) 56 | if headline[-1] not in "{:": 57 | headline += " {" 58 | self._append(headline.format(*args) if args else headline) 59 | prev = self._curr 60 | self._curr = [] 61 | prev.append(self._curr) 62 | yield 63 | self._curr = prev 64 | if terminator is None: 65 | self._append("}") 66 | else: 67 | if terminator: 68 | self._append(terminator) 69 | 70 | def if_(self, cond, *args): 71 | return self.suite("if (%s)" % (cond,), *args) 72 | def elif_(self, cond, *args): 73 | return self.suite("else if (%s)" % (cond,), *args) 74 | def else_(self): 75 | return self.suite("else") 76 | def for_(self, init, cond, next): 77 | return self.suite("for (%s; %s; %s)" % (init, cond, next)) 78 | def while_(self, cond, *args): 79 | return self.suite("while %s:" % (cond,), *args) 80 | def do_while(self, cond, *args): 81 | return self.suite("do", terminator = "} while(%s);" % (cond,), *args) 82 | 83 | @contextmanager 84 | def func(self, name, *args): 85 | with self.suite("function %s(%s)" % (name, ", ".join(str(a) for a in args))): yield 86 | self.sep() 87 | 88 | 89 | class JExpr(object): 90 | __slots__ = ["_text"] 91 | def __init__(self, text): 92 | object.__setattr__(self, "_text", text) 93 | def __str__(self): 94 | return self._text 95 | def __getattr__(self, name): 96 | return JExpr("%s.%s" % (self, name)) 97 | def __setattr__(self, name, value): 98 | return JExpr("%s.%s = %s" % (self, name, value if isinstance(value, str) else json.dumps(value))) 99 | def __getitem__(self, index): 100 | return JExpr("%s[%s]" % (self, json.dumps(index))) 101 | def __setitem__(self, index, val): 102 | return JExpr("%s[%s] = %s" % (self, json.dumps(index), val if isinstance(val, str) else json.dumps(val))) 103 | def __call__(self, *args): 104 | return JExpr("%s(%s)" % (self, ", ".join(json.dumps(a) for a in args))) 105 | def __add__(self, other): 106 | return JExpr("(%s + %s)" % (self, other)) 107 | def __sub__(self, other): 108 | return JExpr("(%s - %s)" % (self, other)) 109 | def __mul__(self, other): 110 | return JExpr("(%s * %s)" % (self, other)) 111 | def __div__(self, other): 112 | return JExpr("(%s / %s)" % (self, other)) 113 | def __pow__(self, other): 114 | return JExpr("(%s ** %s)" % (self, other)) 115 | 116 | # @contextmanager 117 | # def func(self, *args): 118 | # body = JS() 119 | # yield body 120 | # return JExp("%s(function(%s) {\n%s\n})" % (", ".join(json.dumps(a) for a in args), body)) 121 | 122 | 123 | #if __name__ == "__main__": 124 | # m = JS() 125 | # with m.func("foo", "a", "b"): 126 | # with m.if_("a > b"): 127 | # m.return_(17) 128 | # with m.else_(): 129 | # m.return_(18) 130 | # 131 | # print m 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | -------------------------------------------------------------------------------- /srcgen/python.py: -------------------------------------------------------------------------------- 1 | from __future__ import with_statement 2 | import pickle 3 | import six 4 | from contextlib import contextmanager 5 | from srcgen.base import BaseModule, BaseE, R 6 | 7 | 8 | class PythonModule(BaseModule): 9 | def comment(self, *lines, **kwargs): 10 | box = kwargs.pop("box", False) 11 | sep = kwargs.pop("sep", False) 12 | if sep and box: 13 | self._append("") 14 | self._append("#" * self._line_width) 15 | elif sep: 16 | self._append("#") 17 | elif box: 18 | self._append("#" * self._line_width) 19 | self._curr.extend("# %s" % (l,) for l in "\n".join(lines).splitlines()) 20 | if sep and box: 21 | self._append("#" * self._line_width) 22 | self._append("") 23 | elif sep: 24 | self._append("#") 25 | elif box: 26 | self._append("#" * self._line_width) 27 | 28 | # 29 | # Statements 30 | # 31 | def stmt(self, text, *args): 32 | self._append(text.format(*args) if args else text) 33 | def doc(self, text): 34 | self.stmt(repr(text)) 35 | def break_(self): 36 | self.stmt("break") 37 | def continue_(self): 38 | self.stmt("continue") 39 | def return_(self, expr, *args): 40 | self.stmt("return %s" % (expr,), *args) 41 | def yield_(self, expr, *args): 42 | self.stmt("yield %s" % (expr,), *args) 43 | def raise_(self, expr, *args): 44 | self.stmt("raise %s" % (expr,), *args) 45 | def import_(self, modname): 46 | self.stmt("import %s" % (modname,)) 47 | def from_(self, modname, *attrs): 48 | self.stmt("from %s import %s" % (modname, ", ".join(attrs))) 49 | def pass_(self): 50 | self.stmt("pass") 51 | 52 | # 53 | # Suites 54 | # 55 | @contextmanager 56 | def suite(self, headline, *args): 57 | self.stmt(headline, *args) 58 | prev = self._curr 59 | self._curr = [] 60 | prev.append(self._curr) 61 | yield 62 | self._curr = prev 63 | def if_(self, cond, *args): 64 | return self.suite("if %s:" % (cond,), *args) 65 | def elif_(self, cond, *args): 66 | return self.suite("elif %s:" % (cond,), *args) 67 | def else_(self): 68 | return self.suite("else:") 69 | def for_(self, var, expr): 70 | return self.suite("for %s in %s:" % (var, expr)) 71 | def while_(self, cond, *args): 72 | return self.suite("while %s:" % (cond,), *args) 73 | def try_(self): 74 | return self.suite("try:") 75 | def except_(self, exceptions, var = None): 76 | if var: 77 | return self.suite("except (%s) as %s:" % (", ".join(exceptions), var)) 78 | else: 79 | return self.suite("except (%s):" % (", ".join(exceptions),)) 80 | def finally_(self): 81 | return self.suite("finally:") 82 | @contextmanager 83 | def def_(self, name, *args): 84 | with self.suite("def %s(%s):" % (name, ", ".join(str(a) for a in args))): yield 85 | self.sep() 86 | 87 | @contextmanager 88 | def class_(self, name, bases = ("object",)): 89 | if isinstance(bases, six.string_types): 90 | bases = (bases,) 91 | with self.suite("class %s(%s):" % (name, ", ".join(bases,))): yield 92 | self.sep() 93 | 94 | @contextmanager 95 | def cython(self): 96 | mod = CythonModule() 97 | mod._curr = self._curr 98 | yield mod 99 | 100 | def method(self, name, *args): 101 | args = ("self",) + args 102 | return self.def_(name, *args) 103 | def classmethod(self, name, *args): 104 | args = ("cls",) + args 105 | self.stmt("@classmethod") 106 | return self.def_(name, *args) 107 | def staticmethod(self, name, *args): 108 | self.stmt("@staticmethod") 109 | return self.def_(name, *args) 110 | 111 | 112 | class CythonModule(PythonModule): 113 | def __init__(self, *args, **kwargs): 114 | PythonModule.__init__(self, *args, **kwargs) 115 | self._in_cdef = False 116 | 117 | @property 118 | def cdef(self): 119 | self._in_cdef = True 120 | return self 121 | 122 | @contextmanager 123 | def __call__(self, name, *args): 124 | assert self._in_cdef 125 | with self.suite("%s(%s):" % (name, ", ".join(str(a) for a in args))): yield 126 | self.sep() 127 | 128 | def stmt(self, text, *args): 129 | in_cdef = self._in_cdef 130 | self._in_cdef = False 131 | PythonModule.stmt(self, ("cdef " + text) if in_cdef else text, *args) 132 | 133 | def typedef(self, type, newname): 134 | self.stmt("ctypedef %s %s" % (type, newname)) 135 | 136 | @contextmanager 137 | def suite(self, text, *args): 138 | in_cdef = self._in_cdef 139 | self._in_cdef = False 140 | with PythonModule.suite(self, ("cdef " + text) if in_cdef else text, *args): yield 141 | 142 | def cppclass(self, name, bases = ()): 143 | return self.suite("cppclass %s:" % (name)) 144 | 145 | @contextmanager 146 | def extern(self, from_ = None, namespace = None): 147 | head = "extern" 148 | if from_: 149 | head += ' from "%s"' % (repr(from_)[1:-1],) 150 | if namespace: 151 | head += ' namespace "%s"' % (repr(namespace)[1:-1],) 152 | with self.suite(head): yield 153 | self.sep() 154 | 155 | @contextmanager 156 | def struct(self, name): 157 | with self.suite("struct %s:" % (name,)): yield 158 | self.sep() 159 | @contextmanager 160 | def union(self, name): 161 | with self.suite("union %s:" % (name,)): yield 162 | self.sep() 163 | @contextmanager 164 | def enum(self, name): 165 | with self.suite("enum %s:" % (name,)): yield 166 | self.sep() 167 | 168 | @contextmanager 169 | def property(self, name): 170 | with self.suite("property %s:" % (name,)): yield 171 | self.sep() 172 | @contextmanager 173 | def get(self): 174 | with self.suite("def __get__(self):"): yield 175 | self.sep() 176 | @contextmanager 177 | def set(self): 178 | with self.suite("def __set__(self, value):"): yield 179 | self.sep() 180 | @contextmanager 181 | def get_property(self, name): 182 | with self.property(name): 183 | with self.get(): 184 | yield 185 | 186 | 187 | class P(object): 188 | """ 189 | Pickled object 190 | """ 191 | __slots__ = ["data"] 192 | def __init__(self, obj): 193 | self.data = "pickle.loads(%r)" % (pickle.dumps(obj),) 194 | def __str__(self): 195 | return self.data 196 | __repr__ = __str__ 197 | 198 | class E(BaseE): 199 | __slots__ = [] 200 | 201 | def __floordiv__(self, other): 202 | return E("(%r // %r)" % (self, other)) 203 | def __or__(self, other): 204 | return E("(%r or %r)" % (self, other)) 205 | def __and__(self, other): 206 | return E("(%r and %r)" % (self, other)) 207 | def __rfloordiv__(self, other): 208 | return E("(%r // %r)" % (other, self)) 209 | def __ror__(self, other): 210 | return E("(%r or %r)" % (other, self)) 211 | def __rand__(self, other): 212 | return E("(%r and %r)" % (other, self)) 213 | 214 | def __inv__(self): 215 | return E("not %r" % (self,)) 216 | __invert__ = __inv__ 217 | 218 | def __call__(self, *args, **kwargs): 219 | textargs = "" 220 | if args: 221 | textargs += ", ".join(repr(a) for a in args) 222 | if kwargs: 223 | if args: 224 | textargs += ", " 225 | textargs += ",".join("%s = %r" % (k, v) for k, v in kwargs.items()) 226 | return E("%r(%s)" % (self, textargs)) 227 | 228 | 229 | -------------------------------------------------------------------------------- /srcgen/version.py: -------------------------------------------------------------------------------- 1 | version = (1, 1, 0) 2 | version_string = "1.1.0" 3 | release_date = "2013.07.17" 4 | -------------------------------------------------------------------------------- /tests/test_c.py: -------------------------------------------------------------------------------- 1 | from __future__ import with_statement 2 | import unittest 3 | from srcgen.c import CModule, E 4 | 5 | 6 | class TestC(unittest.TestCase): 7 | def test(self): 8 | m = CModule("foo") 9 | m.include("") 10 | m.include("") 11 | m.sep() 12 | m.comment("this is a simple comment") 13 | with m.enum("weekdays"): 14 | m.enum_member("sun") 15 | m.enum_member("mon") 16 | m.enum_member("tue") 17 | m.enum_member("wed") 18 | 19 | m.comment("this is a boxed comment", box = True) 20 | with m.typedef_union("foo"): 21 | with m.struct("", "raw"): 22 | m.stmt("uint64_t a") 23 | m.stmt("uint64_t b") 24 | m.stmt("uint64_t c") 25 | m.stmt("uint64_t d") 26 | 27 | m.comment("this is a sep comment", sep = True) 28 | with m.func("int", "main", "int argv", "const char ** argc"): 29 | with m.if_(E("x") > 5): 30 | m.stmt(E("printf")("hi")) 31 | output = """\ 32 | #include 33 | #include 34 | 35 | /* this is a simple comment */ 36 | enum weekdays { 37 | sun, 38 | mon, 39 | tue, 40 | wed 41 | }; 42 | 43 | /* ****************************************************************************** 44 | /* this is a boxed comment 45 | ****************************************************************************** */ 46 | typedef union _foo { 47 | struct { 48 | uint64_t a; 49 | uint64_t b; 50 | uint64_t c; 51 | uint64_t d; 52 | } raw; 53 | 54 | } foo; 55 | 56 | /* 57 | /* this is a sep comment 58 | */ 59 | int main(int argv, const char ** argc) { 60 | if ((x > 5)) { 61 | printf("hi"); 62 | } 63 | } 64 | """ 65 | self.assertEqual(str(m), output) 66 | 67 | 68 | if __name__ == "__main__": 69 | unittest.main() 70 | 71 | 72 | -------------------------------------------------------------------------------- /tests/test_html.py: -------------------------------------------------------------------------------- 1 | from __future__ import with_statement 2 | import unittest 3 | from srcgen.html import HtmlDocument 4 | from srcgen.js import JS 5 | 6 | 7 | class TestPython(unittest.TestCase): 8 | def test_basic(self): 9 | doc = HtmlDocument() 10 | with doc.head(): 11 | doc.title("das title") 12 | doc.link(rel = "foobar", type="text/css") 13 | 14 | with doc.body(): 15 | with doc.h1(class_="the_header"): 16 | doc.text("hello", "world") 17 | with doc.p(): 18 | doc.text("i am a para&graph\nwith newlnes") 19 | doc.raw(" ") 20 | doc.attrs(data_role = "description") 21 | 22 | self.assertEquals(doc.render(" "), """\ 23 | 24 | 25 | 26 | das title 27 | 28 | 29 | 30 |

helloworld

31 |

32 | i am a para&graph 33 | with newl<i>nes  34 |

35 | 36 | """) 37 | 38 | def test_css(self): 39 | doc = HtmlDocument() 40 | with doc.head(): 41 | doc.title("das title") 42 | doc.link(rel = "foobar", type="text/css") 43 | 44 | css = doc.head_css() 45 | with css("div"): 46 | with css("a", "a:hover", "a:visited"): 47 | with css(".foo"): 48 | css["backgroun-color"] = "black" 49 | css["color"] = "#aabbcc" 50 | 51 | with doc.body(): 52 | with doc.div(): 53 | doc.a("link1", href = "http://www.google.com") 54 | doc.a("link2", href = "http://www.google.com", class_="foo") 55 | doc.a("link3", href = "http://www.google.com") 56 | 57 | self.assertEquals(doc.render(" "), """\ 58 | 59 | 60 | 61 | das title 62 | 63 | 85 | 86 | 87 |
88 | link1link2link3 89 |
90 | 91 | """) 92 | 93 | def test_js(self): 94 | doc = HtmlDocument() 95 | with doc.head(): 96 | doc.title("das title") 97 | with doc.script(): 98 | m = JS() 99 | with m.func("onclick", "self"): 100 | m.stmt("alert('oh no')") 101 | with m.if_("self > 'foo'"): 102 | m.return_(17) 103 | with m.else_(): 104 | m.return_(18) 105 | doc.text(m) 106 | 107 | with doc.body(): 108 | with doc.div(): 109 | pass 110 | 111 | self.assertEquals(doc.render(" "), """\ 112 | 113 | 114 | 115 | das title 116 | 127 | 128 | 129 |
130 | 131 | """) 132 | 133 | def test_comments(self): 134 | doc = HtmlDocument() 135 | with doc.head(): 136 | doc.title("das title") 137 | doc.comment("hello") 138 | doc.comment("hello", "world") 139 | 140 | self.assertEquals(doc.render(" "), """\ 141 | 142 | 143 | 144 | das title 145 | 146 | 150 | 151 | """) 152 | 153 | 154 | 155 | if __name__ == "__main__": 156 | unittest.main() 157 | 158 | 159 | -------------------------------------------------------------------------------- /tests/test_python.py: -------------------------------------------------------------------------------- 1 | from __future__ import with_statement 2 | import unittest 3 | from srcgen.python import PythonModule, R, E, CythonModule 4 | 5 | 6 | class TestPython(unittest.TestCase): 7 | def test(self): 8 | m = PythonModule() 9 | m.stmt("import sys") 10 | m.stmt("import os") 11 | m.sep() 12 | m.comment("hi there", box = True) 13 | m.stmt(R(x = 18)) 14 | with m.if_("x > 5"): 15 | m.stmt("print '''hello\nworld'''") 16 | with m.if_(E("z") == 18): 17 | m.comment("foo", "bar") 18 | m.stmt("print 'lala'") 19 | with m.if_("z == 19"): 20 | m.stmt("print 'gaga'") 21 | m.stmt("print 'zaza'") 22 | m.sep() 23 | with m.def_("foo", "a", "b", "c"): 24 | m.stmt("return a + b + c") 25 | with m.def_("bar", "a", "b", "c"): 26 | m.return_("a * b * c") 27 | m.stmt("print 'papa'") 28 | 29 | output = """\ 30 | import sys 31 | import os 32 | 33 | ################################################################################ 34 | # hi there 35 | ################################################################################ 36 | x = 18 37 | if x > 5: 38 | print '''hello 39 | world''' 40 | if (z == 18): 41 | # foo 42 | # bar 43 | print 'lala' 44 | if z == 19: 45 | print 'gaga' 46 | print 'zaza' 47 | 48 | def foo(a, b, c): 49 | return a + b + c 50 | 51 | def bar(a, b, c): 52 | return a * b * c 53 | 54 | print 'papa' 55 | """ 56 | self.assertEqual(str(m), output) 57 | 58 | def gen_class(self, m, name, *args): 59 | with m.class_(name): 60 | with m.method("__init__", *args): 61 | for a in args: 62 | m.stmt("self.{0} = {0}", a) 63 | 64 | def test_methods(self): 65 | m = PythonModule() 66 | self.gen_class(m, "MyClass", "a", "b") 67 | self.gen_class(m, "YourClass", "a", "b", "c") 68 | output = """\ 69 | class MyClass(object): 70 | def __init__(self, a, b): 71 | self.a = a 72 | self.b = b 73 | 74 | class YourClass(object): 75 | def __init__(self, a, b, c): 76 | self.a = a 77 | self.b = b 78 | self.c = c 79 | """ 80 | self.assertEqual(str(m), output) 81 | 82 | def test_cython(self): 83 | m = CythonModule() 84 | with m.def_("pyfunc", "a", "b"): 85 | m.return_("a+b") 86 | with m.cdef("int cfunc", "int a", "int b"): 87 | m.return_("a+b") 88 | with m.cdef.class_("MyCClass"): 89 | with m.method("spam", "x"): 90 | m.return_("x * 2") 91 | with m.cdef.extern("myheader.h"): 92 | with m.struct("mystruct"): 93 | m.stmt("int a") 94 | m.stmt("int b") 95 | m.stmt("int c") 96 | 97 | output = """\ 98 | def pyfunc(a, b): 99 | return a+b 100 | 101 | cdef int cfunc(int a, int b): 102 | return a+b 103 | 104 | cdef class MyCClass(object): 105 | def spam(self, x): 106 | return x * 2 107 | 108 | cdef extern from "myheader.h" 109 | struct mystruct: 110 | int a 111 | int b 112 | int c 113 | """ 114 | self.assertEqual(str(m), output) 115 | 116 | 117 | if __name__ == "__main__": 118 | unittest.main() 119 | 120 | 121 | --------------------------------------------------------------------------------