зеркало из https://github.com/mozilla/pluotsorbet.git
merge
This commit is contained in:
Коммит
d3d7dc68cf
|
@ -7,6 +7,12 @@ certs/j2se_test.ks
|
|||
tests/Testlets.java
|
||||
output/
|
||||
build/
|
||||
.checksum
|
||||
|
||||
# These are generated by the python preprocessor. They're generated from
|
||||
# the *.in files.
|
||||
config.ts
|
||||
main.html
|
||||
config/build.js
|
||||
|
||||
# These are generated by the Java pre-processor. They're generated from
|
||||
|
|
32
Makefile
32
Makefile
|
@ -1,15 +1,35 @@
|
|||
.PHONY: all test tests j2me java certs app clean jasmin aot shumway config-build relooper
|
||||
BASIC_SRCS=$(shell find . -maxdepth 2 -name "*.ts" -not -path "./build/*")
|
||||
.PHONY: all test tests j2me java certs app clean jasmin aot shumway config-build
|
||||
BASIC_SRCS=$(shell find . -maxdepth 2 -name "*.ts" -not -path "./build/*") config.ts
|
||||
JIT_SRCS=$(shell find jit -name "*.ts" -not -path "./build/*")
|
||||
SHUMWAY_SRCS=$(shell find shumway -name "*.ts")
|
||||
RELEASE ?= 0
|
||||
VERSION ?=$(shell date +%s)
|
||||
PROFILE ?= 0
|
||||
|
||||
# Create a checksum file to monitor the changes of the Makefile configuration.
|
||||
# If the configuration has changed, we update the checksum file to let the files
|
||||
# which depend on it to regenerate.
|
||||
|
||||
CHECKSUM := "$(RELEASE)$(PROFILE)"
|
||||
OLD_CHECKSUM := "$(shell [ -f .checksum ] && cat .checksum)"
|
||||
$(shell [ $(CHECKSUM) != $(OLD_CHECKSUM) ] && echo $(CHECKSUM) > .checksum)
|
||||
|
||||
toBool = $(if $(findstring 1,$(1)),true,false)
|
||||
PREPROCESS = python tools/preprocess-1.1.0/lib/preprocess.py -s \
|
||||
-D RELEASE=$(call toBool,$(RELEASE)) \
|
||||
-D PROFILE=$(call toBool,$(PROFILE)) \
|
||||
-D VERSION=$(VERSION)
|
||||
PREPROCESS_SRCS = $(shell find . -name "*.in" -not -path config/build.js.in)
|
||||
PREPROCESS_DESTS = $(PREPROCESS_SRCS:.in=)
|
||||
|
||||
all: config-build java jasmin tests j2me shumway aot
|
||||
|
||||
test: all
|
||||
tests/runtests.py
|
||||
|
||||
$(PREPROCESS_DESTS): $(PREPROCESS_SRCS) .checksum
|
||||
$(foreach file,$(PREPROCESS_SRCS),$(PREPROCESS) -o $(file:.in=) $(file);)
|
||||
|
||||
jasmin:
|
||||
make -C tools/jasmin-2.4
|
||||
|
||||
|
@ -51,10 +71,10 @@ shumway: build/shumway.js
|
|||
build/shumway.js: $(SHUMWAY_SRCS)
|
||||
node tools/tsc.js --sourcemap --target ES5 shumway/references.ts --out build/shumway.js
|
||||
|
||||
config-build:
|
||||
echo "// generated, build-specific configuration" > config/build.js
|
||||
echo "config.release = ${RELEASE};" >> config/build.js
|
||||
echo "config.version = \"${VERSION}\";" >> config/build.js
|
||||
# We should update config/build.js everytime to generate the new VERSION number
|
||||
# based on current time.
|
||||
config-build: config/build.js.in
|
||||
$(PREPROCESS) -o config/build.js config/build.js.in
|
||||
|
||||
tests/tests.jar: tests
|
||||
tests:
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
/*
|
||||
* Copyright 2014 Mozilla Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/** @const */ var release: boolean = @RELEASE@;
|
||||
/** @const */ var profile: boolean = @PROFILE@;
|
|
@ -0,0 +1,4 @@
|
|||
// generated, build-specific configuration
|
||||
|
||||
config.release = @RELEASE@;
|
||||
config.version = "@VERSION@";
|
|
@ -11,7 +11,7 @@ classes.jar: $(SRCS) $(JPP_DESTS)
|
|||
mkdir build build-src
|
||||
cp -a cldc1.1.1/. vm/. midp/. jsr-075/. build-src/
|
||||
cp -a custom/. build-src/
|
||||
javac -cp build-src -source 1.3 -target 1.3 -bootclasspath "" -extdirs "" -d ./build `find ./build-src -name *.java` > /dev/null
|
||||
javac -cp build-src -g:none -source 1.3 -target 1.3 -bootclasspath "" -extdirs "" -d ./build `find ./build-src -name *.java` > /dev/null
|
||||
cd build && jar cvf0 ../classes.jar *
|
||||
jar uvf0 classes.jar $(EXTRA)
|
||||
rm -rf build build-src
|
||||
|
|
|
@ -3,6 +3,9 @@ package com.nokia.mid.s40.bg;
|
|||
import com.sun.midp.main.MIDletSuiteUtils;
|
||||
|
||||
class WaitUserInteractionThread extends Thread {
|
||||
public WaitUserInteractionThread() {
|
||||
setPriority(Thread.MAX_PRIORITY);
|
||||
}
|
||||
public void run() {
|
||||
BGUtils.waitUserInteraction();
|
||||
BGUtils.startMIDlet();
|
||||
|
|
|
@ -14,8 +14,9 @@
|
|||
<script type="text/javascript" src="config/midlet.js" defer></script>
|
||||
<script type="text/javascript" src="config/build.js" defer></script>
|
||||
<script type="text/javascript" src="config/urlparams.js" defer></script>
|
||||
<!-- Uncomment the line below to enable the profiler. -->
|
||||
<!--<script type="text/javascript" src="build/shumway.js" defer></script>-->
|
||||
<!-- #if PROFILE == "true" -->
|
||||
<script type="text/javascript" src="build/shumway.js" defer></script>
|
||||
<!-- #endif -->
|
||||
<!--<script type="text/javascript" src="libs/terminal.js" defer></script>-->
|
||||
<script type="text/javascript" src="libs/console.js" defer></script>
|
||||
<script type="text/javascript" src="libs/promise-6.0.0.js" defer></script>
|
|
@ -1,4 +1,5 @@
|
|||
// Basics
|
||||
///<reference path='config.ts' />
|
||||
///<reference path='utilities.ts' />
|
||||
|
||||
///<reference path='classfile/classfile.ts' />
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
// Basics
|
||||
|
||||
///<reference path='config.ts' />
|
||||
///<reference path='utilities.ts' />
|
||||
|
||||
///<reference path='classfile/classfile.ts' />
|
||||
|
|
23
runtime.ts
23
runtime.ts
|
@ -1170,16 +1170,31 @@ module J2ME {
|
|||
return null;
|
||||
}
|
||||
|
||||
function reportError(method, key) {
|
||||
return function() {
|
||||
try {
|
||||
return method.apply(this, arguments);
|
||||
} catch (e) {
|
||||
// Filter JAVA exception and only report the native js exception, which
|
||||
// cannnot be handled properly by the JAVA code.
|
||||
if (!e.klass) {
|
||||
stderrWriter.errorLn("Native " + key + " throws: " + e);
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function findNativeMethodImplementation(methodInfo: MethodInfo) {
|
||||
var implKey = methodInfo.implKey;
|
||||
// Look in bindings first.
|
||||
var binding = findNativeMethodBinding(methodInfo);
|
||||
if (binding) {
|
||||
return binding;
|
||||
return release ? binding : reportError(binding, implKey);
|
||||
}
|
||||
var implKey = methodInfo.implKey;
|
||||
if (methodInfo.isNative) {
|
||||
if (implKey in Native) {
|
||||
return Native[implKey];
|
||||
return release ? Native[implKey] : reportError(Native[implKey], implKey);
|
||||
} else {
|
||||
// Some Native MethodInfos are constructed but never called;
|
||||
// that's fine, unless we actually try to call them.
|
||||
|
@ -1188,7 +1203,7 @@ module J2ME {
|
|||
}
|
||||
}
|
||||
} else if (implKey in Override) {
|
||||
return Override[implKey];
|
||||
return release ? Override[implKey] : reportError(Override[implKey], implKey);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@ mkdir $PACKAGE_DIR/build
|
|||
# setup the root
|
||||
cp *.js *.html *.webapp $PACKAGE_DIR/.
|
||||
cp build/j2me.js $PACKAGE_DIR/build/.
|
||||
cp build/classes.jar.js $PACKAGE_DIR/build/.
|
||||
|
||||
# copy over jars/jads that are used for the webapp
|
||||
# NB: we could be smart about this and parse the manifest, patches welcome!
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
Copyright (c) 2002-2005 ActiveState Corp.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included
|
||||
in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
|
@ -0,0 +1,420 @@
|
|||
preprocess.py -- a portable multi-language file preprocessor
|
||||
============================================================
|
||||
|
||||
Download the latest preprocess.py packages from here:
|
||||
(archive) http://preprocess.googlecode.com/files/preprocess-1.1.0.zip
|
||||
|
||||
|
||||
Home : http://trentm.com/projects/preprocess/
|
||||
License : MIT (see LICENSE.txt)
|
||||
Platforms : Windows, Linux, Mac OS X, Unix
|
||||
Current Version : 1.1
|
||||
Dev Status : Fairly mature, has been used in the Komodo build system for
|
||||
over 7 years.
|
||||
Requirements : Python >= 2.3 (http://www.activestate.com/ActivePython/)
|
||||
|
||||
|
||||
What's new?
|
||||
-----------
|
||||
|
||||
Support has been added for preprocessing TeX, Fortran, C#, Java, Shell
|
||||
script and PHP files. See the [Change Log](#changelog) below for more.
|
||||
|
||||
|
||||
Why preprocess.py?
|
||||
------------------
|
||||
|
||||
There are millions of templating systems out there (most of them
|
||||
developed for the web). This isn't one of those, though it does share
|
||||
some basics: a markup syntax for templates that are processed to give
|
||||
resultant text output. The main difference with `preprocess.py` is
|
||||
that its syntax is hidden in comments (whatever the syntax for comments
|
||||
maybe in the target filetype) so that the file can still have valid
|
||||
syntax. A comparison with the C preprocessor is more apt.
|
||||
|
||||
`preprocess.py` is targetted at build systems that deal with many
|
||||
types of files. Languages for which it works include: C++, Python,
|
||||
Perl, Tcl, XML, JavaScript, CSS, IDL, TeX, Fortran, PHP, Java, Shell
|
||||
scripts (Bash, CSH, etc.) and C#. Preprocess is usable both as a
|
||||
command line app and as a Python module.
|
||||
|
||||
Here is how is works: All preprocessor statements are on their own
|
||||
line. A preprocessor statement is a comment (as appropriate for the
|
||||
language of the file being preprocessed). This way the preprocessor
|
||||
statements do not make an unpreprocessed file syntactically incorrect.
|
||||
For example:
|
||||
|
||||
preprocess -D FEATURES=macros,scc myapp.py
|
||||
|
||||
will yield this transformation:
|
||||
|
||||
... ...
|
||||
# #if "macros" in FEATURES
|
||||
def do_work_with_macros(): def do_work_with_macros():
|
||||
pass pass
|
||||
# #else
|
||||
def do_work_without_macros():
|
||||
pass
|
||||
# #endif
|
||||
... ...
|
||||
|
||||
or, with a JavaScript file:
|
||||
|
||||
... ...
|
||||
// #if "macros" in FEATURES
|
||||
function do_work_with_macros() { function do_work_with_macros() {
|
||||
} }
|
||||
// #else
|
||||
function do_work_without_macros() {
|
||||
}
|
||||
// #endif
|
||||
... ...
|
||||
|
||||
Despite these contrived examples preprocess has proved useful for
|
||||
build-time code differentiation in the
|
||||
[Komodo](http://www.activestate.com/Komodo) build system -- which
|
||||
includes source code in Python, JavaScript, XML, CSS, Perl, and C/C++.
|
||||
|
||||
The #if expression (`"macros" in FEATURES` in the example) is Python
|
||||
code, so has Python's full comparison richness. A number of
|
||||
preprocessor statements are implemented:
|
||||
|
||||
#define VAR [VALUE]
|
||||
#undef VAR
|
||||
#ifdef VAR
|
||||
#ifndef VAR
|
||||
#if EXPRESSION
|
||||
#elif EXPRESSION
|
||||
#else
|
||||
#endif
|
||||
#error ERROR_STRING
|
||||
#include "FILE"
|
||||
@varName@
|
||||
|
||||
As well, preprocess will do in-line substitution of defined variables.
|
||||
Although this is currently off by default because substitution will occur
|
||||
in program strings, which is not ideal. When a future version of
|
||||
preprocess can lex languages being preprocessed it will NOT substitute
|
||||
into program strings and substitution will be turned ON by default.
|
||||
|
||||
A workaround is made to resolve this issue. Variables embraced by @ will be
|
||||
substitute by its value in the emitted lines. For example if we define
|
||||
NAME="Yuan Xulei", the input file:
|
||||
<p>Hello I'm @NAME@!</p>
|
||||
will output:
|
||||
<p>Hello I'm Yuan Xulei!</p>
|
||||
|
||||
Please send any feedback to [Trent Mick](mailto:trentm@google's mail
|
||||
thing.com).
|
||||
|
||||
|
||||
Install Notes
|
||||
-------------
|
||||
|
||||
Download the latest `preprocess` source package, unzip it, and run `python
|
||||
setup.py install`:
|
||||
|
||||
unzip preprocess-1.1.0.zip
|
||||
cd preprocess-1.1.0
|
||||
python setup.py install
|
||||
|
||||
If your install fails then please visit [the Troubleshooting
|
||||
FAQ](http://trentm.com/faq.html#troubleshooting-python-package-installation).
|
||||
|
||||
This will install `preprocess.py` into your Python `site-packages` and
|
||||
also into your Python bin directory. If you can now run `preprocess`
|
||||
and get a response then you are good to go, otherwise read on.
|
||||
|
||||
The *problem* is that the Python bin directory is not always on your
|
||||
PATH on some operating systems -- notably Mac OS X. To finish the
|
||||
install on OS X either manually move 'preprocess' to somewhere on your
|
||||
PATH:
|
||||
|
||||
cp preprocess.py /usr/local/bin/preprocess
|
||||
|
||||
or create a symlink to it (try one of these depending on your Python
|
||||
version):
|
||||
|
||||
ln -s /System/Library/Frameworks/Python.framework/Versions/2.3/bin/preprocess /usr/local/bin/preprocess
|
||||
ln -s /Library/Frameworks/Python.framework/Versions/2.4/bin/preprocess /usr/local/bin/preprocess
|
||||
|
||||
(Note: You'll probably need to prefix those commands with `sudo` and
|
||||
the exact paths may differ on your system.)
|
||||
|
||||
|
||||
Getting Started
|
||||
---------------
|
||||
|
||||
Once you have it install, run `preprocess --help` for full usage
|
||||
information:
|
||||
|
||||
$ preprocess --help
|
||||
Preprocess a file.
|
||||
|
||||
Command Line Usage:
|
||||
preprocess [<options>...] <infile>
|
||||
|
||||
Options:
|
||||
-h, --help Print this help and exit.
|
||||
-V, --version Print the version info and exit.
|
||||
-v, --verbose Give verbose output for errors.
|
||||
|
||||
-o <outfile> Write output to the given file instead of to stdout.
|
||||
-f, --force Overwrite given output file. (Otherwise an IOError
|
||||
will be raised if <outfile> already exists.
|
||||
-D <define> Define a variable for preprocessing. <define>
|
||||
can simply be a variable name (in which case it
|
||||
will be true) or it can be of the form
|
||||
<var>=<val>. An attempt will be made to convert
|
||||
<val> to an integer so "-D FOO=0" will create a
|
||||
false value.
|
||||
-I <dir> Add an directory to the include path for
|
||||
#include directives.
|
||||
|
||||
-k, --keep-lines Emit empty lines for preprocessor statement
|
||||
lines and skipped output lines. This allows line
|
||||
numbers to stay constant.
|
||||
-s, --substitute Substitute defines into emitted lines. By
|
||||
default substitution is NOT done because it
|
||||
currently will substitute into program strings.
|
||||
|
||||
Module Usage:
|
||||
from preprocess import preprocess
|
||||
preprocess(infile, outfile=sys.stdout, defines={}, force=0,
|
||||
keepLines=0, includePath=[], substitute=0)
|
||||
|
||||
The <infile> can be marked up with special preprocessor statement lines
|
||||
of the form:
|
||||
<comment-prefix> <preprocessor-statement> <comment-suffix>
|
||||
where the <comment-prefix/suffix> are the native comment delimiters for
|
||||
that file type.
|
||||
|
||||
|
||||
Examples
|
||||
--------
|
||||
|
||||
HTML (*.htm, *.html) or XML (*.xml, *.kpf, *.xul) files:
|
||||
|
||||
<!-- #if FOO -->
|
||||
...
|
||||
<!-- #endif -->
|
||||
|
||||
Python (*.py), Perl (*.pl), Tcl (*.tcl), Ruby (*.rb), Bash (*.sh),
|
||||
or make ([Mm]akefile*) files:
|
||||
|
||||
# #if defined('FAV_COLOR') and FAV_COLOR == "blue"
|
||||
...
|
||||
# #elif FAV_COLOR == "red"
|
||||
...
|
||||
# #else
|
||||
...
|
||||
# #endif
|
||||
|
||||
C (*.c, *.h), C++ (*.cpp, *.cxx, *.cc, *.h, *.hpp, *.hxx, *.hh),
|
||||
Java (*.java), PHP (*.php) or C# (*.cs) files:
|
||||
|
||||
// #define FAV_COLOR 'blue'
|
||||
...
|
||||
/* #ifndef FAV_COLOR */
|
||||
...
|
||||
// #endif
|
||||
|
||||
Fortran 77 (*.f) or 90/95 (*.f90) files:
|
||||
|
||||
C #if COEFF == 'var'
|
||||
...
|
||||
C #endif
|
||||
|
||||
|
||||
Preprocessor Syntax
|
||||
-------------------
|
||||
|
||||
- Valid statements:
|
||||
#define <var> [<value>]
|
||||
#undef <var>
|
||||
#ifdef <var>
|
||||
#ifndef <var>
|
||||
#if <expr>
|
||||
#elif <expr>
|
||||
#else
|
||||
#endif
|
||||
#error <error string>
|
||||
#include "<file>"
|
||||
where <expr> is any valid Python expression.
|
||||
- The expression after #if/elif may be a Python statement. It is an
|
||||
error to refer to a variable that has not been defined by a -D
|
||||
option or by an in-content #define.
|
||||
- Special built-in methods for expressions:
|
||||
defined(varName) Return true if given variable is defined.
|
||||
|
||||
|
||||
Tips
|
||||
----
|
||||
|
||||
A suggested file naming convention is to let input files to
|
||||
preprocess be of the form <basename>.p.<ext> and direct the output
|
||||
of preprocess to <basename>.<ext>, e.g.:
|
||||
preprocess -o foo.py foo.p.py
|
||||
The advantage is that other tools (esp. editors) will still
|
||||
recognize the unpreprocessed file as the original language.
|
||||
|
||||
|
||||
And, for module usage, read the preprocess.preprocess() docstring:
|
||||
|
||||
pydoc preprocess.preprocess
|
||||
|
||||
|
||||
Change Log
|
||||
----------
|
||||
|
||||
### v1.1.0
|
||||
- Move to code.google.com/p/preprocess for code hosting.
|
||||
- Re-org directory structure to assist with deployment to pypi and
|
||||
better installation with setup.py.
|
||||
- Pulled the "content.types" file that assists with filetype
|
||||
determination into "preprocess.py". This makes "preprocess.py" fully
|
||||
independent and also makes the "setup.py" simpler. The
|
||||
"-c|--content-types-path" option can be used to specify
|
||||
addition content types information.
|
||||
|
||||
### v1.0.9
|
||||
- Fix the 'contentType' optional arg for #include's.
|
||||
- Add cheap XML content sniffing.
|
||||
|
||||
### v1.0.8
|
||||
- Allow for JS and CSS-style comment delims in XML/HTML. Ideally this
|
||||
would deal with full lexing but that isn't going to happen soon.
|
||||
|
||||
### v1.0.7
|
||||
- Allow explicit specification of content type.
|
||||
### v1.0.6
|
||||
- Add ability to include a filename mentioned in a define: '#include
|
||||
VAR'.
|
||||
|
||||
|
||||
### v1.0.5
|
||||
- Make sure to use the *longest* define names first when doing
|
||||
substitutions. This ensure that substitution in this line:
|
||||
FOO and BAR are FOOBAR
|
||||
will do the right thing if there are "FOO" and "FOOBAR" defines.
|
||||
|
||||
### v1.0.4
|
||||
- Add WiX XML file extensions.
|
||||
- Add XSLT file extensions.
|
||||
|
||||
### v1.0.3
|
||||
- TeX support (from Hans Petter Langtangen)
|
||||
|
||||
### v1.0.2
|
||||
- Fix a bug with -k|--keep-lines and preprocessor some directives in
|
||||
ignored if blocks (undef, define, error, include): those lines were
|
||||
not kept. (bug noted by Eric Promislow)
|
||||
|
||||
### v1.0.1
|
||||
- Fix documentation error for '#define' statement. The correct syntax
|
||||
is '#define VAR [VALUE]' while the docs used to say
|
||||
'#define VAR[=VALUE]'. (from Hans Petter Langtangen)
|
||||
- Correct '! ...' comment-style for Fortran -- the '!' can be on any
|
||||
column in Fortran 90. (from Hans Petter Langtangen)
|
||||
- Return a non-zero exit code on error.
|
||||
|
||||
### v1.0.0
|
||||
- Update the test suite (it had been broken for quite a while) and add
|
||||
a Fortran test case.
|
||||
- Improve Fortran support to support any char in the first column to
|
||||
indicate a comment. (Idea from Hans Petter Langtangen)
|
||||
- Recognize '.f90' files as Fortran. (from Hans Petter Langtangen)
|
||||
- Add Java, C#, Shell script and PHP support. (from Hans Petter
|
||||
Langtangen)
|
||||
|
||||
### v0.9.2
|
||||
- Add Fortran support (from Hans Petter Langtangen)
|
||||
- Ensure content.types gets written to "bindir" next to preprocess.py
|
||||
there so it can be picked up (from Hans Petter Langtangen).
|
||||
|
||||
### v0.9.1
|
||||
- Fully read in the input file before processing. This allows
|
||||
preprocessing of a file onto itself.
|
||||
|
||||
### v0.9.0
|
||||
- Change version attributes and semantics. Before: had a _version_
|
||||
tuple. After: __version__ is a string, __version_info__ is a tuple.
|
||||
|
||||
### v0.8.1
|
||||
- Mentioned #ifdef and #ifndef in documentation (these have been there
|
||||
for a while).
|
||||
- Add preprocess.exe to source package (should fix installation on
|
||||
Windows).
|
||||
- Incorporate Komodo changes:
|
||||
- change 171050: add Ruby support
|
||||
- change 160914: Only attempt to convert define strings from the
|
||||
command-line to *int* instead of eval'ing as any Python
|
||||
expression: which could surprise with strings that work as
|
||||
floats.
|
||||
- change 67962: Fix '#include' directives in preprocessed files.
|
||||
|
||||
### v0.8.0
|
||||
- Move hosting to trentm.com. Improve the starter docs a little bit.
|
||||
|
||||
### 0.7.0:
|
||||
- Fix bug 1: Nested #if-blocks will not be properly handled.
|
||||
- Add 'Text' type for .txt files and default (with a warn) unknown
|
||||
filetypes to 'Text'. Text files are defined to use to '#...'-style
|
||||
comments to allow if/else/.../endif directives as in
|
||||
Perl/Python/Tcl files.
|
||||
|
||||
### 0.6.1:
|
||||
- Fix a bug where preprocessor statements were not ignored when not
|
||||
emitting. For example the following should _not_ cause an error:
|
||||
# #if 0
|
||||
# #error womba womba womba
|
||||
# #endif
|
||||
- Fix a bug where multiple uses of preprocess.preprocess() in the
|
||||
same interpreter would erroneously re-use the same list of
|
||||
__preprocessedFiles. This could cause false detection of recursive
|
||||
#include's.
|
||||
- Fix #include, broken in 0.6.0.
|
||||
|
||||
### 0.6.0:
|
||||
- substitution: Variables can now replaced with their defined value
|
||||
in preprocessed file content. This is turned OFF by default
|
||||
because, IMO, substitution should not be done in program strings.
|
||||
I need to add lexing for all supported languages before I can do
|
||||
*that* properly. Substitution can be turned on with the
|
||||
--substitute command-line option or the subst=1 module interface
|
||||
option.
|
||||
- Add support for preprocessing HTML files.
|
||||
|
||||
### 0.5.0:
|
||||
- Add #error, #define, #undef, #ifdef and #ifndef statements.
|
||||
- #include statement, -I command line option and 'includePath'
|
||||
module interface option to specify an include path
|
||||
- Add __FILE__ and __LINE__ default defines.
|
||||
- More strict and more helpful error messages:
|
||||
- Lines of the form "#else <expr>" and "#endif <expr>" no longer
|
||||
match.
|
||||
- error messages for illegal #if-block constructs
|
||||
- error messages for use of defined(BAR) instead of
|
||||
defined('BAR') in expressions
|
||||
- New "keep lines" option to output blank lines for skipped content
|
||||
lines and preprocessor statement lines (to preserve line numbers
|
||||
in the processed file).
|
||||
|
||||
### 0.4.0:
|
||||
- Add #elif preprocessor statement.
|
||||
- Add defined() built-in, e.g. #if defined('FOO')
|
||||
|
||||
### 0.3.2:
|
||||
- Make #if expressions Python code.
|
||||
- Change "defines" attribute of preprocess.preprocess().
|
||||
- Add -f|--force option to overwrite given output file.
|
||||
|
||||
### 0.2.0:
|
||||
- Add content types for C/C++.
|
||||
- Better module documentation.
|
||||
- You can define *false* vars on the command line now.
|
||||
- 'python setup.py install' works.
|
||||
|
||||
### 0.1.0:
|
||||
- First release.
|
||||
|
|
@ -0,0 +1,847 @@
|
|||
#!/usr/bin/env python
|
||||
# Copyright (c) 2002-2008 ActiveState Software Inc.
|
||||
# License: MIT License (http://www.opensource.org/licenses/mit-license.php)
|
||||
|
||||
"""
|
||||
Preprocess a file.
|
||||
|
||||
Command Line Usage:
|
||||
preprocess [<options>...] <infile>
|
||||
|
||||
Options:
|
||||
-h, --help Print this help and exit.
|
||||
-V, --version Print the version info and exit.
|
||||
-v, --verbose Give verbose output for errors.
|
||||
|
||||
-o <outfile> Write output to the given file instead of to stdout.
|
||||
-f, --force Overwrite given output file. (Otherwise an IOError
|
||||
will be raised if <outfile> already exists.
|
||||
-D <define> Define a variable for preprocessing. <define>
|
||||
can simply be a variable name (in which case it
|
||||
will be true) or it can be of the form
|
||||
<var>=<val>. An attempt will be made to convert
|
||||
<val> to an integer so "-D FOO=0" will create a
|
||||
false value.
|
||||
-I <dir> Add an directory to the include path for
|
||||
#include directives.
|
||||
|
||||
-k, --keep-lines Emit empty lines for preprocessor statement
|
||||
lines and skipped output lines. This allows line
|
||||
numbers to stay constant.
|
||||
-s, --substitute Substitute defines into emitted lines. By
|
||||
default substitution is NOT done because it
|
||||
currently will substitute into program strings.
|
||||
-c, --content-types-path <path>
|
||||
Specify a path to a content.types file to assist
|
||||
with filetype determination. See the
|
||||
`_gDefaultContentTypes` string in this file for
|
||||
details on its format.
|
||||
|
||||
Module Usage:
|
||||
from preprocess import preprocess
|
||||
preprocess(infile, outfile=sys.stdout, defines={}, force=0,
|
||||
keepLines=0, includePath=[], substitute=0,
|
||||
contentType=None)
|
||||
|
||||
The <infile> can be marked up with special preprocessor statement lines
|
||||
of the form:
|
||||
<comment-prefix> <preprocessor-statement> <comment-suffix>
|
||||
where the <comment-prefix/suffix> are the native comment delimiters for
|
||||
that file type.
|
||||
|
||||
|
||||
Examples
|
||||
--------
|
||||
|
||||
HTML (*.htm, *.html) or XML (*.xml, *.kpf, *.xul) files:
|
||||
|
||||
<!-- #if FOO -->
|
||||
...
|
||||
<!-- #endif -->
|
||||
|
||||
Python (*.py), Perl (*.pl), Tcl (*.tcl), Ruby (*.rb), Bash (*.sh),
|
||||
or make ([Mm]akefile*) files:
|
||||
|
||||
# #if defined('FAV_COLOR') and FAV_COLOR == "blue"
|
||||
...
|
||||
# #elif FAV_COLOR == "red"
|
||||
...
|
||||
# #else
|
||||
...
|
||||
# #endif
|
||||
|
||||
C (*.c, *.h), C++ (*.cpp, *.cxx, *.cc, *.h, *.hpp, *.hxx, *.hh),
|
||||
Java (*.java), PHP (*.php) or C# (*.cs) files:
|
||||
|
||||
// #define FAV_COLOR 'blue'
|
||||
...
|
||||
/* #ifndef FAV_COLOR */
|
||||
...
|
||||
// #endif
|
||||
|
||||
Fortran 77 (*.f) or 90/95 (*.f90) files:
|
||||
|
||||
C #if COEFF == 'var'
|
||||
...
|
||||
C #endif
|
||||
|
||||
And other languages.
|
||||
|
||||
Variables embraced by @ will be substitute by its value in the emitted
|
||||
lines. For example if we define NAME="Yuan Xulei", the input file:
|
||||
<p>Hello I'm @NAME@!</p>
|
||||
will output:
|
||||
<p>Hello I'm Yuan Xulei!</p>
|
||||
|
||||
Preprocessor Syntax
|
||||
-------------------
|
||||
|
||||
- Valid statements:
|
||||
#define <var> [<value>]
|
||||
#undef <var>
|
||||
#ifdef <var>
|
||||
#ifndef <var>
|
||||
#if <expr>
|
||||
#elif <expr>
|
||||
#else
|
||||
#endif
|
||||
#error <error string>
|
||||
#include "<file>"
|
||||
#include <var>
|
||||
@varName@
|
||||
where <expr> is any valid Python expression.
|
||||
- The expression after #if/elif may be a Python statement. It is an
|
||||
error to refer to a variable that has not been defined by a -D
|
||||
option or by an in-content #define.
|
||||
- Special built-in methods for expressions:
|
||||
defined(varName) Return true if given variable is defined.
|
||||
|
||||
|
||||
Tips
|
||||
----
|
||||
|
||||
A suggested file naming convention is to let input files to
|
||||
preprocess be of the form <basename>.p.<ext> and direct the output
|
||||
of preprocess to <basename>.<ext>, e.g.:
|
||||
preprocess -o foo.py foo.p.py
|
||||
The advantage is that other tools (esp. editors) will still
|
||||
recognize the unpreprocessed file as the original language.
|
||||
"""
|
||||
|
||||
__version_info__ = (1, 1, 0)
|
||||
__version__ = '.'.join(map(str, __version_info__))
|
||||
|
||||
import os
|
||||
import sys
|
||||
import getopt
|
||||
import types
|
||||
import re
|
||||
import pprint
|
||||
|
||||
|
||||
|
||||
#---- exceptions
|
||||
|
||||
class PreprocessError(Exception):
|
||||
def __init__(self, errmsg, file=None, lineno=None, line=None):
|
||||
self.errmsg = str(errmsg)
|
||||
self.file = file
|
||||
self.lineno = lineno
|
||||
self.line = line
|
||||
Exception.__init__(self, errmsg, file, lineno, line)
|
||||
def __str__(self):
|
||||
s = ""
|
||||
if self.file is not None:
|
||||
s += self.file + ":"
|
||||
if self.lineno is not None:
|
||||
s += str(self.lineno) + ":"
|
||||
if self.file is not None or self.lineno is not None:
|
||||
s += " "
|
||||
s += self.errmsg
|
||||
#if self.line is not None:
|
||||
# s += ": " + self.line
|
||||
return s
|
||||
|
||||
|
||||
|
||||
#---- global data
|
||||
|
||||
# Comment delimiter info.
|
||||
# A mapping of content type to a list of 2-tuples defining the line
|
||||
# prefix and suffix for a comment. Each prefix or suffix can either
|
||||
# be a string (in which case it is transformed into a pattern allowing
|
||||
# whitespace on either side) or a compiled regex.
|
||||
_commentGroups = {
|
||||
"Python": [ ('#', '') ],
|
||||
"Perl": [ ('#', '') ],
|
||||
"PHP": [ ('/*', '*/'), ('//', ''), ('#', '') ],
|
||||
"Ruby": [ ('#', '') ],
|
||||
"Tcl": [ ('#', '') ],
|
||||
"Shell": [ ('#', '') ],
|
||||
# Allowing for CSS and JavaScript comments in XML/HTML.
|
||||
"XML": [ ('<!--', '-->'), ('/*', '*/'), ('//', '') ],
|
||||
"HTML": [ ('<!--', '-->'), ('/*', '*/'), ('//', '') ],
|
||||
"Makefile": [ ('#', '') ],
|
||||
"JavaScript": [ ('/*', '*/'), ('//', '') ],
|
||||
"CSS": [ ('/*', '*/') ],
|
||||
"C": [ ('/*', '*/') ],
|
||||
"C++": [ ('/*', '*/'), ('//', '') ],
|
||||
"Java": [ ('/*', '*/'), ('//', '') ],
|
||||
"C#": [ ('/*', '*/'), ('//', '') ],
|
||||
"IDL": [ ('/*', '*/'), ('//', '') ],
|
||||
"Text": [ ('#', '') ],
|
||||
"Fortran": [ (re.compile(r'^[a-zA-Z*$]\s*'), ''), ('!', '') ],
|
||||
"TeX": [ ('%', '') ],
|
||||
}
|
||||
|
||||
|
||||
|
||||
#---- internal logging facility
|
||||
|
||||
class _Logger:
|
||||
DEBUG, INFO, WARN, ERROR, CRITICAL = range(5)
|
||||
def __init__(self, name, level=None, streamOrFileName=sys.stderr):
|
||||
self._name = name
|
||||
if level is None:
|
||||
self.level = self.WARN
|
||||
else:
|
||||
self.level = level
|
||||
if type(streamOrFileName) == types.StringType:
|
||||
self.stream = open(streamOrFileName, 'w')
|
||||
self._opennedStream = 1
|
||||
else:
|
||||
self.stream = streamOrFileName
|
||||
self._opennedStream = 0
|
||||
def __del__(self):
|
||||
if self._opennedStream:
|
||||
self.stream.close()
|
||||
def getLevel(self):
|
||||
return self.level
|
||||
def setLevel(self, level):
|
||||
self.level = level
|
||||
def _getLevelName(self, level):
|
||||
levelNameMap = {
|
||||
self.DEBUG: "DEBUG",
|
||||
self.INFO: "INFO",
|
||||
self.WARN: "WARN",
|
||||
self.ERROR: "ERROR",
|
||||
self.CRITICAL: "CRITICAL",
|
||||
}
|
||||
return levelNameMap[level]
|
||||
def isEnabled(self, level):
|
||||
return level >= self.level
|
||||
def isDebugEnabled(self): return self.isEnabled(self.DEBUG)
|
||||
def isInfoEnabled(self): return self.isEnabled(self.INFO)
|
||||
def isWarnEnabled(self): return self.isEnabled(self.WARN)
|
||||
def isErrorEnabled(self): return self.isEnabled(self.ERROR)
|
||||
def isFatalEnabled(self): return self.isEnabled(self.FATAL)
|
||||
def log(self, level, msg, *args):
|
||||
if level < self.level:
|
||||
return
|
||||
message = "%s: %s: " % (self._name, self._getLevelName(level).lower())
|
||||
message = message + (msg % args) + "\n"
|
||||
self.stream.write(message)
|
||||
self.stream.flush()
|
||||
def debug(self, msg, *args):
|
||||
self.log(self.DEBUG, msg, *args)
|
||||
def info(self, msg, *args):
|
||||
self.log(self.INFO, msg, *args)
|
||||
def warn(self, msg, *args):
|
||||
self.log(self.WARN, msg, *args)
|
||||
def error(self, msg, *args):
|
||||
self.log(self.ERROR, msg, *args)
|
||||
def fatal(self, msg, *args):
|
||||
self.log(self.CRITICAL, msg, *args)
|
||||
|
||||
log = _Logger("preprocess", _Logger.WARN)
|
||||
|
||||
|
||||
|
||||
#---- internal support stuff
|
||||
|
||||
def _evaluate(expr, defines):
|
||||
"""Evaluate the given expression string with the given context.
|
||||
|
||||
WARNING: This runs eval() on a user string. This is unsafe.
|
||||
"""
|
||||
#interpolated = _interpolate(s, defines)
|
||||
try:
|
||||
rv = eval(expr, {'defined':lambda v: v in defines}, defines)
|
||||
except Exception, ex:
|
||||
msg = str(ex)
|
||||
if msg.startswith("name '") and msg.endswith("' is not defined"):
|
||||
# A common error (at least this is presumed:) is to have
|
||||
# defined(FOO) instead of defined('FOO')
|
||||
# We should give a little as to what might be wrong.
|
||||
# msg == "name 'FOO' is not defined" --> varName == "FOO"
|
||||
varName = msg[len("name '"):-len("' is not defined")]
|
||||
if expr.find("defined(%s)" % varName) != -1:
|
||||
# "defined(FOO)" in expr instead of "defined('FOO')"
|
||||
msg += " (perhaps you want \"defined('%s')\" instead of "\
|
||||
"\"defined(%s)\")" % (varName, varName)
|
||||
elif msg.startswith("invalid syntax"):
|
||||
msg = "invalid syntax: '%s'" % expr
|
||||
raise PreprocessError(msg, defines['__FILE__'], defines['__LINE__'])
|
||||
log.debug("evaluate %r -> %s (defines=%r)", expr, rv, defines)
|
||||
return rv
|
||||
|
||||
|
||||
#---- module API
|
||||
|
||||
def preprocess(infile, outfile=sys.stdout, defines={},
|
||||
force=0, keepLines=0, includePath=[], substitute=0,
|
||||
contentType=None, contentTypesRegistry=None,
|
||||
__preprocessedFiles=None):
|
||||
"""Preprocess the given file.
|
||||
|
||||
"infile" is the input path.
|
||||
"outfile" is the output path or stream (default is sys.stdout).
|
||||
"defines" is a dictionary of defined variables that will be
|
||||
understood in preprocessor statements. Keys must be strings and,
|
||||
currently, only the truth value of any key's value matters.
|
||||
"force" will overwrite the given outfile if it already exists. Otherwise
|
||||
an IOError will be raise if the outfile already exists.
|
||||
"keepLines" will cause blank lines to be emitted for preprocessor lines
|
||||
and content lines that would otherwise be skipped.
|
||||
"includePath" is a list of directories to search for given #include
|
||||
directives. The directory of the file being processed is presumed.
|
||||
"substitute", if true, will allow substitution of defines into emitted
|
||||
lines. (NOTE: This substitution will happen within program strings
|
||||
as well. This may not be what you expect.)
|
||||
"contentType" can be used to specify the content type of the input
|
||||
file. It not given, it will be guessed.
|
||||
"contentTypesRegistry" is an instance of ContentTypesRegistry. If not specified
|
||||
a default registry will be created.
|
||||
"__preprocessedFiles" (for internal use only) is used to ensure files
|
||||
are not recusively preprocessed.
|
||||
|
||||
Returns the modified dictionary of defines or raises PreprocessError if
|
||||
there was some problem.
|
||||
"""
|
||||
if __preprocessedFiles is None:
|
||||
__preprocessedFiles = []
|
||||
log.info("preprocess(infile=%r, outfile=%r, defines=%r, force=%r, "\
|
||||
"keepLines=%r, includePath=%r, contentType=%r, "\
|
||||
"__preprocessedFiles=%r)", infile, outfile, defines, force,
|
||||
keepLines, includePath, contentType, __preprocessedFiles)
|
||||
absInfile = os.path.normpath(os.path.abspath(infile))
|
||||
if absInfile in __preprocessedFiles:
|
||||
raise PreprocessError("detected recursive #include of '%s'"\
|
||||
% infile)
|
||||
__preprocessedFiles.append(os.path.abspath(infile))
|
||||
|
||||
# Determine the content type and comment info for the input file.
|
||||
if contentType is None:
|
||||
registry = contentTypesRegistry or getDefaultContentTypesRegistry()
|
||||
contentType = registry.getContentType(infile)
|
||||
if contentType is None:
|
||||
contentType = "Text"
|
||||
log.warn("defaulting content type for '%s' to '%s'",
|
||||
infile, contentType)
|
||||
try:
|
||||
cgs = _commentGroups[contentType]
|
||||
except KeyError:
|
||||
raise PreprocessError("don't know comment delimiters for content "\
|
||||
"type '%s' (file '%s')"\
|
||||
% (contentType, infile))
|
||||
|
||||
# Generate statement parsing regexes. Basic format:
|
||||
# <comment-prefix> <preprocessor-stmt> <comment-suffix>
|
||||
# Examples:
|
||||
# <!-- #if foo -->
|
||||
# ...
|
||||
# <!-- #endif -->
|
||||
#
|
||||
# # #if BAR
|
||||
# ...
|
||||
# # #else
|
||||
# ...
|
||||
# # #endif
|
||||
stmts = ['#\s*(?P<op>if|elif|ifdef|ifndef)\s+(?P<expr>.*?)',
|
||||
'#\s*(?P<op>else|endif)',
|
||||
'#\s*(?P<op>error)\s+(?P<error>.*?)',
|
||||
'#\s*(?P<op>define)\s+(?P<var>[^\s]*?)(\s+(?P<val>.+?))?',
|
||||
'#\s*(?P<op>undef)\s+(?P<var>[^\s]*?)',
|
||||
'#\s*(?P<op>include)\s+"(?P<fname>.*?)"',
|
||||
r'#\s*(?P<op>include)\s+(?P<var>[^\s]+?)',
|
||||
]
|
||||
patterns = []
|
||||
for stmt in stmts:
|
||||
# The comment group prefix and suffix can either be just a
|
||||
# string or a compiled regex.
|
||||
for cprefix, csuffix in cgs:
|
||||
if hasattr(cprefix, "pattern"):
|
||||
pattern = cprefix.pattern
|
||||
else:
|
||||
pattern = r"^\s*%s\s*" % re.escape(cprefix)
|
||||
pattern += stmt
|
||||
if hasattr(csuffix, "pattern"):
|
||||
pattern += csuffix.pattern
|
||||
else:
|
||||
pattern += r"\s*%s\s*$" % re.escape(csuffix)
|
||||
patterns.append(pattern)
|
||||
stmtRes = [re.compile(p) for p in patterns]
|
||||
|
||||
# Process the input file.
|
||||
# (Would be helpful if I knew anything about lexing and parsing
|
||||
# simple grammars.)
|
||||
fin = open(infile, 'r')
|
||||
lines = fin.readlines()
|
||||
fin.close()
|
||||
if type(outfile) in types.StringTypes:
|
||||
if force and os.path.exists(outfile):
|
||||
os.chmod(outfile, 0777)
|
||||
os.remove(outfile)
|
||||
fout = open(outfile, 'w')
|
||||
else:
|
||||
fout = outfile
|
||||
|
||||
defines['__FILE__'] = infile
|
||||
SKIP, EMIT = range(2) # states
|
||||
states = [(EMIT, # a state is (<emit-or-skip-lines-in-this-section>,
|
||||
0, # <have-emitted-in-this-if-block>,
|
||||
0)] # <have-seen-'else'-in-this-if-block>)
|
||||
lineNum = 0
|
||||
for line in lines:
|
||||
lineNum += 1
|
||||
log.debug("line %d: %r", lineNum, line)
|
||||
defines['__LINE__'] = lineNum
|
||||
|
||||
# Is this line a preprocessor stmt line?
|
||||
#XXX Could probably speed this up by optimizing common case of
|
||||
# line NOT being a preprocessor stmt line.
|
||||
for stmtRe in stmtRes:
|
||||
match = stmtRe.match(line)
|
||||
if match:
|
||||
break
|
||||
else:
|
||||
match = None
|
||||
|
||||
if match:
|
||||
op = match.group("op")
|
||||
log.debug("%r stmt (states: %r)", op, states)
|
||||
if op == "define":
|
||||
if not (states and states[-1][0] == SKIP):
|
||||
var, val = match.group("var", "val")
|
||||
if val is None:
|
||||
val = None
|
||||
else:
|
||||
try:
|
||||
val = eval(val, {}, {})
|
||||
except:
|
||||
pass
|
||||
defines[var] = val
|
||||
elif op == "undef":
|
||||
if not (states and states[-1][0] == SKIP):
|
||||
var = match.group("var")
|
||||
try:
|
||||
del defines[var]
|
||||
except KeyError:
|
||||
pass
|
||||
elif op == "include":
|
||||
if not (states and states[-1][0] == SKIP):
|
||||
if "var" in match.groupdict():
|
||||
# This is the second include form: #include VAR
|
||||
var = match.group("var")
|
||||
f = defines[var]
|
||||
else:
|
||||
# This is the first include form: #include "path"
|
||||
f = match.group("fname")
|
||||
|
||||
for d in [os.path.dirname(infile)] + includePath:
|
||||
fname = os.path.normpath(os.path.join(d, f))
|
||||
if os.path.exists(fname):
|
||||
break
|
||||
else:
|
||||
raise PreprocessError("could not find #include'd file "\
|
||||
"\"%s\" on include path: %r"\
|
||||
% (f, includePath))
|
||||
defines = preprocess(fname, fout, defines, force,
|
||||
keepLines, includePath, substitute,
|
||||
contentTypesRegistry=contentTypesRegistry,
|
||||
__preprocessedFiles=__preprocessedFiles)
|
||||
elif op in ("if", "ifdef", "ifndef"):
|
||||
if op == "if":
|
||||
expr = match.group("expr")
|
||||
elif op == "ifdef":
|
||||
expr = "defined('%s')" % match.group("expr")
|
||||
elif op == "ifndef":
|
||||
expr = "not defined('%s')" % match.group("expr")
|
||||
try:
|
||||
if states and states[-1][0] == SKIP:
|
||||
# Were are nested in a SKIP-portion of an if-block.
|
||||
states.append((SKIP, 0, 0))
|
||||
elif _evaluate(expr, defines):
|
||||
states.append((EMIT, 1, 0))
|
||||
else:
|
||||
states.append((SKIP, 0, 0))
|
||||
except KeyError:
|
||||
raise PreprocessError("use of undefined variable in "\
|
||||
"#%s stmt" % op, defines['__FILE__'],
|
||||
defines['__LINE__'], line)
|
||||
elif op == "elif":
|
||||
expr = match.group("expr")
|
||||
try:
|
||||
if states[-1][2]: # already had #else in this if-block
|
||||
raise PreprocessError("illegal #elif after #else in "\
|
||||
"same #if block", defines['__FILE__'],
|
||||
defines['__LINE__'], line)
|
||||
elif states[-1][1]: # if have emitted in this if-block
|
||||
states[-1] = (SKIP, 1, 0)
|
||||
elif states[:-1] and states[-2][0] == SKIP:
|
||||
# Were are nested in a SKIP-portion of an if-block.
|
||||
states[-1] = (SKIP, 0, 0)
|
||||
elif _evaluate(expr, defines):
|
||||
states[-1] = (EMIT, 1, 0)
|
||||
else:
|
||||
states[-1] = (SKIP, 0, 0)
|
||||
except IndexError:
|
||||
raise PreprocessError("#elif stmt without leading #if "\
|
||||
"stmt", defines['__FILE__'],
|
||||
defines['__LINE__'], line)
|
||||
elif op == "else":
|
||||
try:
|
||||
if states[-1][2]: # already had #else in this if-block
|
||||
raise PreprocessError("illegal #else after #else in "\
|
||||
"same #if block", defines['__FILE__'],
|
||||
defines['__LINE__'], line)
|
||||
elif states[-1][1]: # if have emitted in this if-block
|
||||
states[-1] = (SKIP, 1, 1)
|
||||
elif states[:-1] and states[-2][0] == SKIP:
|
||||
# Were are nested in a SKIP-portion of an if-block.
|
||||
states[-1] = (SKIP, 0, 1)
|
||||
else:
|
||||
states[-1] = (EMIT, 1, 1)
|
||||
except IndexError:
|
||||
raise PreprocessError("#else stmt without leading #if "\
|
||||
"stmt", defines['__FILE__'],
|
||||
defines['__LINE__'], line)
|
||||
elif op == "endif":
|
||||
try:
|
||||
states.pop()
|
||||
except IndexError:
|
||||
raise PreprocessError("#endif stmt without leading #if"\
|
||||
"stmt", defines['__FILE__'],
|
||||
defines['__LINE__'], line)
|
||||
elif op == "error":
|
||||
if not (states and states[-1][0] == SKIP):
|
||||
error = match.group("error")
|
||||
raise PreprocessError("#error: "+error, defines['__FILE__'],
|
||||
defines['__LINE__'], line)
|
||||
log.debug("states: %r", states)
|
||||
if keepLines:
|
||||
fout.write("\n")
|
||||
else:
|
||||
try:
|
||||
if states[-1][0] == EMIT:
|
||||
log.debug("emit line (%s)" % states[-1][1])
|
||||
# Substitute all defines into line.
|
||||
# XXX Should avoid recursive substitutions. But that
|
||||
# would be a pain right now.
|
||||
sline = line
|
||||
if substitute:
|
||||
for name in reversed(sorted(defines, key=len)):
|
||||
value = defines[name]
|
||||
sline = sline.replace("@" + name + "@", str(value))
|
||||
fout.write(sline)
|
||||
elif keepLines:
|
||||
log.debug("keep blank line (%s)" % states[-1][1])
|
||||
fout.write("\n")
|
||||
else:
|
||||
log.debug("skip line (%s)" % states[-1][1])
|
||||
except IndexError:
|
||||
raise PreprocessError("superfluous #endif before this line",
|
||||
defines['__FILE__'],
|
||||
defines['__LINE__'])
|
||||
if len(states) > 1:
|
||||
raise PreprocessError("unterminated #if block", defines['__FILE__'],
|
||||
defines['__LINE__'])
|
||||
elif len(states) < 1:
|
||||
raise PreprocessError("superfluous #endif on or before this line",
|
||||
defines['__FILE__'], defines['__LINE__'])
|
||||
|
||||
if fout != outfile:
|
||||
fout.close()
|
||||
|
||||
return defines
|
||||
|
||||
|
||||
#---- content-type handling
|
||||
|
||||
_gDefaultContentTypes = """
|
||||
# Default file types understood by "preprocess.py".
|
||||
#
|
||||
# Format is an extension of 'mime.types' file syntax.
|
||||
# - '#' indicates a comment to the end of the line.
|
||||
# - a line is:
|
||||
# <filetype> [<pattern>...]
|
||||
# where,
|
||||
# <filetype>'s are equivalent in spirit to the names used in the Windows
|
||||
# registry in HKCR, but some of those names suck or are inconsistent;
|
||||
# and
|
||||
# <pattern> is a suffix (pattern starts with a '.'), a regular expression
|
||||
# (pattern is enclosed in '/' characters), a full filename (anything
|
||||
# else).
|
||||
#
|
||||
# Notes on case-sensitivity:
|
||||
#
|
||||
# A suffix pattern is case-insensitive on Windows and case-sensitive
|
||||
# elsewhere. A filename pattern is case-sensitive everywhere. A regex
|
||||
# pattern's case-sensitivity is defined by the regex. This means it is by
|
||||
# default case-sensitive, but this can be changed using Python's inline
|
||||
# regex option syntax. E.g.:
|
||||
# Makefile /^(?i)makefile.*$/ # case-INsensitive regex
|
||||
|
||||
Python .py
|
||||
Python .pyw
|
||||
Perl .pl
|
||||
Ruby .rb
|
||||
Tcl .tcl
|
||||
XML .xml
|
||||
XML .kpf
|
||||
XML .xul
|
||||
XML .rdf
|
||||
XML .xslt
|
||||
XML .xsl
|
||||
XML .wxs
|
||||
XML .wxi
|
||||
HTML .htm
|
||||
HTML .html
|
||||
XML .xhtml
|
||||
Makefile /^[Mm]akefile.*$/
|
||||
PHP .php
|
||||
JavaScript .js
|
||||
JavaScript .ts
|
||||
CSS .css
|
||||
C++ .c # C++ because then we can use //-style comments
|
||||
C++ .cpp
|
||||
C++ .cxx
|
||||
C++ .cc
|
||||
C++ .h
|
||||
C++ .hpp
|
||||
C++ .hxx
|
||||
C++ .hh
|
||||
IDL .idl
|
||||
Text .txt
|
||||
Fortran .f
|
||||
Fortran .f90
|
||||
Shell .sh
|
||||
Shell .csh
|
||||
Shell .ksh
|
||||
Shell .zsh
|
||||
Java .java
|
||||
C# .cs
|
||||
TeX .tex
|
||||
|
||||
# Some Komodo-specific file extensions
|
||||
Python .ksf # Fonts & Colors scheme files
|
||||
Text .kkf # Keybinding schemes files
|
||||
"""
|
||||
|
||||
class ContentTypesRegistry:
|
||||
"""A class that handles determining the filetype of a given path.
|
||||
|
||||
Usage:
|
||||
>>> registry = ContentTypesRegistry()
|
||||
>>> registry.getContentType("foo.py")
|
||||
"Python"
|
||||
"""
|
||||
|
||||
def __init__(self, contentTypesPaths=None):
|
||||
self.contentTypesPaths = contentTypesPaths
|
||||
self._load()
|
||||
|
||||
def _load(self):
|
||||
from os.path import dirname, join, exists
|
||||
|
||||
self.suffixMap = {}
|
||||
self.regexMap = {}
|
||||
self.filenameMap = {}
|
||||
|
||||
self._loadContentType(_gDefaultContentTypes)
|
||||
localContentTypesPath = join(dirname(__file__), "content.types")
|
||||
if exists(localContentTypesPath):
|
||||
log.debug("load content types file: `%r'" % localContentTypesPath)
|
||||
self._loadContentType(open(localContentTypesPath, 'r').read())
|
||||
for path in (self.contentTypesPaths or []):
|
||||
log.debug("load content types file: `%r'" % path)
|
||||
self._loadContentType(open(path, 'r').read())
|
||||
|
||||
def _loadContentType(self, content, path=None):
|
||||
"""Return the registry for the given content.types file.
|
||||
|
||||
The registry is three mappings:
|
||||
<suffix> -> <content type>
|
||||
<regex> -> <content type>
|
||||
<filename> -> <content type>
|
||||
"""
|
||||
for line in content.splitlines(0):
|
||||
words = line.strip().split()
|
||||
for i in range(len(words)):
|
||||
if words[i][0] == '#':
|
||||
del words[i:]
|
||||
break
|
||||
if not words: continue
|
||||
contentType, patterns = words[0], words[1:]
|
||||
if not patterns:
|
||||
if line[-1] == '\n': line = line[:-1]
|
||||
raise PreprocessError("bogus content.types line, there must "\
|
||||
"be one or more patterns: '%s'" % line)
|
||||
for pattern in patterns:
|
||||
if pattern.startswith('.'):
|
||||
if sys.platform.startswith("win"):
|
||||
# Suffix patterns are case-insensitive on Windows.
|
||||
pattern = pattern.lower()
|
||||
self.suffixMap[pattern] = contentType
|
||||
elif pattern.startswith('/') and pattern.endswith('/'):
|
||||
self.regexMap[re.compile(pattern[1:-1])] = contentType
|
||||
else:
|
||||
self.filenameMap[pattern] = contentType
|
||||
|
||||
def getContentType(self, path):
|
||||
"""Return a content type for the given path.
|
||||
|
||||
@param path {str} The path of file for which to guess the
|
||||
content type.
|
||||
@returns {str|None} Returns None if could not determine the
|
||||
content type.
|
||||
"""
|
||||
basename = os.path.basename(path).rstrip(".in")
|
||||
contentType = None
|
||||
# Try to determine from the path.
|
||||
if not contentType and self.filenameMap.has_key(basename):
|
||||
contentType = self.filenameMap[basename]
|
||||
log.debug("Content type of '%s' is '%s' (determined from full "\
|
||||
"path).", path, contentType)
|
||||
# Try to determine from the suffix.
|
||||
if not contentType and '.' in basename:
|
||||
suffix = "." + basename.split(".")[-1]
|
||||
if sys.platform.startswith("win"):
|
||||
# Suffix patterns are case-insensitive on Windows.
|
||||
suffix = suffix.lower()
|
||||
if self.suffixMap.has_key(suffix):
|
||||
contentType = self.suffixMap[suffix]
|
||||
log.debug("Content type of '%s' is '%s' (determined from "\
|
||||
"suffix '%s').", path, contentType, suffix)
|
||||
# Try to determine from the registered set of regex patterns.
|
||||
if not contentType:
|
||||
for regex, ctype in self.regexMap.items():
|
||||
if regex.search(basename):
|
||||
contentType = ctype
|
||||
log.debug("Content type of '%s' is '%s' (matches regex '%s')",
|
||||
path, contentType, regex.pattern)
|
||||
break
|
||||
# Try to determine from the file contents.
|
||||
content = open(path, 'rb').read()
|
||||
if content.startswith("<?xml"): # cheap XML sniffing
|
||||
contentType = "XML"
|
||||
return contentType
|
||||
|
||||
_gDefaultContentTypesRegistry = None
|
||||
def getDefaultContentTypesRegistry():
|
||||
global _gDefaultContentTypesRegistry
|
||||
if _gDefaultContentTypesRegistry is None:
|
||||
_gDefaultContentTypesRegistry = ContentTypesRegistry()
|
||||
return _gDefaultContentTypesRegistry
|
||||
|
||||
|
||||
#---- internal support stuff
|
||||
#TODO: move other internal stuff down to this section
|
||||
|
||||
try:
|
||||
reversed
|
||||
except NameError:
|
||||
# 'reversed' added in Python 2.4 (http://www.python.org/doc/2.4/whatsnew/node7.html)
|
||||
def reversed(seq):
|
||||
rseq = list(seq)
|
||||
rseq.reverse()
|
||||
for item in rseq:
|
||||
yield item
|
||||
try:
|
||||
sorted
|
||||
except NameError:
|
||||
# 'sorted' added in Python 2.4. Note that I'm only implementing enough
|
||||
# of sorted as is used in this module.
|
||||
def sorted(seq, key=None):
|
||||
identity = lambda x: x
|
||||
key_func = (key or identity)
|
||||
sseq = list(seq)
|
||||
sseq.sort(lambda self, other: cmp(key_func(self), key_func(other)))
|
||||
for item in sseq:
|
||||
yield item
|
||||
|
||||
|
||||
#---- mainline
|
||||
|
||||
def main(argv):
|
||||
try:
|
||||
optlist, args = getopt.getopt(argv[1:], 'hVvo:D:fkI:sc:',
|
||||
['help', 'version', 'verbose', 'force', 'keep-lines',
|
||||
'substitute', 'content-types-path='])
|
||||
except getopt.GetoptError, msg:
|
||||
sys.stderr.write("preprocess: error: %s. Your invocation was: %s\n"\
|
||||
% (msg, argv))
|
||||
sys.stderr.write("See 'preprocess --help'.\n")
|
||||
return 1
|
||||
outfile = sys.stdout
|
||||
defines = {}
|
||||
force = 0
|
||||
keepLines = 0
|
||||
substitute = 0
|
||||
includePath = []
|
||||
contentTypesPaths = []
|
||||
for opt, optarg in optlist:
|
||||
if opt in ('-h', '--help'):
|
||||
sys.stdout.write(__doc__)
|
||||
return 0
|
||||
elif opt in ('-V', '--version'):
|
||||
sys.stdout.write("preprocess %s\n" % __version__)
|
||||
return 0
|
||||
elif opt in ('-v', '--verbose'):
|
||||
log.setLevel(log.DEBUG)
|
||||
elif opt == '-o':
|
||||
outfile = optarg
|
||||
if opt in ('-f', '--force'):
|
||||
force = 1
|
||||
elif opt == '-D':
|
||||
if optarg.find('=') != -1:
|
||||
var, val = optarg.split('=', 1)
|
||||
try:
|
||||
val = int(val)
|
||||
except ValueError:
|
||||
pass
|
||||
else:
|
||||
var, val = optarg, None
|
||||
defines[var] = val
|
||||
elif opt in ('-k', '--keep-lines'):
|
||||
keepLines = 1
|
||||
elif opt == '-I':
|
||||
includePath.append(optarg)
|
||||
elif opt in ('-s', '--substitute'):
|
||||
substitute = 1
|
||||
elif opt in ('-c', '--content-types-path'):
|
||||
contentTypesPaths.append(optarg)
|
||||
|
||||
if len(args) != 1:
|
||||
sys.stderr.write("preprocess: error: incorrect number of "\
|
||||
"arguments: argv=%r\n" % argv)
|
||||
return 1
|
||||
else:
|
||||
infile = args[0]
|
||||
|
||||
try:
|
||||
contentTypesRegistry = ContentTypesRegistry(contentTypesPaths)
|
||||
preprocess(infile, outfile, defines, force, keepLines, includePath,
|
||||
substitute, contentTypesRegistry=contentTypesRegistry)
|
||||
except PreprocessError, ex:
|
||||
if log.isDebugEnabled():
|
||||
import traceback
|
||||
traceback.print_exc(file=sys.stderr)
|
||||
else:
|
||||
sys.stderr.write("preprocess: error: %s\n" % str(ex))
|
||||
return 1
|
||||
|
||||
if __name__ == "__main__":
|
||||
__file__ = sys.argv[0]
|
||||
sys.exit( main(sys.argv) )
|
||||
|
|
@ -20,9 +20,6 @@ var inBrowser = typeof console !== "undefined" && console.info;
|
|||
declare var putstr;
|
||||
declare var printErr;
|
||||
|
||||
/** @const */ var release: boolean = true;
|
||||
/** @const */ var profile: boolean = true;
|
||||
|
||||
declare var dateNow: () => number;
|
||||
|
||||
declare var dump: (message: string) => void;
|
||||
|
|
Загрузка…
Ссылка в новой задаче