├── .gitignore
├── README.md
├── TODO
└── site
├── app.yaml
├── index.yaml
├── legacy.py
├── main.py
├── models.py
├── static
├── .DS_Store
├── contrib
│ ├── php
│ │ ├── LICENSE
│ │ ├── css
│ │ │ └── phpcolors.css
│ │ ├── index.html
│ │ └── js
│ │ │ ├── parsephp.js
│ │ │ ├── parsephphtmlmixed.js
│ │ │ └── tokenizephp.js
│ └── python
│ │ ├── LICENSE
│ │ ├── css
│ │ └── pythoncolors.css
│ │ ├── index.html
│ │ └── js
│ │ └── parsepython.js
├── css
│ ├── csscolors.css
│ ├── docs.css
│ ├── jscolors.css
│ ├── people.jpg
│ ├── sparqlcolors.css
│ └── xmlcolors.css
├── favicon.ico
├── js
│ ├── codemirror.js
│ ├── editor.js
│ ├── mirrorframe.js
│ ├── parsecss.js
│ ├── parsedummy.js
│ ├── parsehtmlmixed.js
│ ├── parsejavascript.js
│ ├── parsesparql.js
│ ├── parsexml.js
│ ├── select.js
│ ├── stringstream.js
│ ├── tokenize.js
│ ├── tokenizejavascript.js
│ ├── undo.js
│ └── util.js
├── prototype.js
├── robots.txt
└── style.css
└── templates
├── base.html
├── new.html
├── not_authorized.html
├── not_found.html
└── script.html
/.gitignore:
--------------------------------------------------------------------------------
1 | **/*.pyc
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/progrium/scriptlets/ea59e09cc7bd07ee72102e0266662e1770e9af64/README.md
--------------------------------------------------------------------------------
/TODO:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/site/app.yaml:
--------------------------------------------------------------------------------
1 | application: scriptletsapp
2 | version: 2
3 | runtime: python
4 | api_version: 1
5 |
6 | handlers:
7 | - url: /favicon.ico
8 | static_files: static/favicon.ico
9 | upload: static/favicon.ico
10 | - url: /robots.txt
11 | static_files: static/robots.txt
12 | upload: static/robots.txt
13 | - url: /static
14 | static_dir: static
15 | - url: /view.*
16 | script: legacy.py
17 | - url: /code.*
18 | script: legacy.py
19 | - url: /run.*
20 | script: legacy.py
21 | - url: /.*
22 | script: main.py
23 |
--------------------------------------------------------------------------------
/site/index.yaml:
--------------------------------------------------------------------------------
1 | indexes:
2 |
3 | # AUTOGENERATED
4 |
5 | # This index.yaml is automatically updated whenever the dev_appserver
6 | # detects that a new type of query is run. If you want to manage the
7 | # index.yaml file manually, remove the above marker line (the line
8 | # saying "# AUTOGENERATED"). If you want to manage some indexes
9 | # manually, move them above the marker line. The index.yaml file is
10 | # automatically uploaded to the admin console when you next deploy
11 | # your application using appcfg.py.
12 |
--------------------------------------------------------------------------------
/site/legacy.py:
--------------------------------------------------------------------------------
1 | import wsgiref.handlers
2 | from google.appengine.ext import webapp
3 | from google.appengine.api import urlfetch
4 | import urllib
5 |
6 | LEGACY_URL = "http://1.latest.scriptletsapp.appspot.com"
7 |
8 | class LegacyAdaptor(webapp.RequestHandler):
9 | def get(self):
10 | self.redirect('%s%s' % (LEGACY_URL, self.request.path))
11 |
12 | def post(self):
13 | payload = dict(self.request.POST)
14 | headers = dict(self.request.headers)
15 | self.response.out.write(urlfetch.fetch(
16 | url='%s%s' % (LEGACY_URL, self.request.path),
17 | payload=urllib.urlencode(payload) if len(payload) else None,
18 | method=self.request.method,
19 | headers=headers,
20 | deadline=10).content)
21 |
22 | def main():
23 | application = webapp.WSGIApplication([
24 | ('/view/.*', LegacyAdaptor),
25 | ('/code/.*', LegacyAdaptor),
26 | ('/run/.*', LegacyAdaptor),
27 | ], debug=True)
28 | wsgiref.handlers.CGIHandler().run(application)
29 |
30 |
31 | if __name__ == '__main__':
32 | main()
--------------------------------------------------------------------------------
/site/main.py:
--------------------------------------------------------------------------------
1 | import wsgiref.handlers
2 | import urllib, cgi
3 |
4 | from google.appengine.ext import webapp
5 | from google.appengine.api import users
6 | from google.appengine.api import urlfetch
7 | from google.appengine.ext.webapp import template
8 | from models import Script, Version
9 |
10 | class NewHandler(webapp.RequestHandler):
11 | def get(self):
12 | user = users.get_current_user()
13 | if user:
14 | logout_url = users.create_logout_url('/')
15 | else:
16 | login_url = users.create_login_url('/')
17 | self.response.out.write(template.render('templates/new.html', locals()))
18 |
19 | def post(self):
20 | user = users.get_current_user()
21 | body = self.request.get('script')
22 | if body:
23 | script = Script()
24 | script.put()
25 | version = Version(script=script, body=body)
26 | version.put()
27 | script.latest_version = version
28 | script.put()
29 | self.redirect('/%s' % script.id)
30 | else:
31 | self.redirect('/new')
32 |
33 | def script_routing(f):
34 | def wrap(self):
35 | parts = self.request.path.split('/')[1:]
36 | if parts[-1] == '':
37 | parts.pop()
38 | if '.' in parts[-1]:
39 | part, ext = parts[-1].split('.')
40 | parts[-1] = part
41 | else:
42 | ext = None
43 | script = Script.all().filter('id =', parts[0]).get()
44 | version = None
45 | if script:
46 | if len(parts) > 1:
47 | if parts[1] == 'latest':
48 | return self.redirect('/%s/%s' % (script.id, script.latest_version.id))
49 | else:
50 | version = script.version_set.filter('id =', parts[1]).get()
51 | else:
52 | version = script.latest_version
53 | if not version:
54 | self.not_found()
55 | elif self.should_run():
56 | self.run(script, version)
57 | else:
58 | user = users.get_current_user()
59 | if script.private and script.user.key() != user.key():
60 | return self.not_authorized()
61 | if ext == 'js':
62 | self.response.headers['Content-Type'] = 'text/javascript'
63 | self.response.out.write(version.body)
64 | else:
65 | f(self, script, version, user)
66 | return wrap
67 |
68 | class ScriptHandler(webapp.RequestHandler):
69 | def run(self, script, version):
70 | self.response.out.write(urlfetch.fetch(
71 | url='http://eval.progrium.com',
72 | payload=urllib.urlencode({'script': script.latest_version.body}),
73 | method='POST',
74 | deadline=10).content)
75 |
76 | def should_run(self):
77 | return self.request.host.startswith('run.') or self.request.path.split('/')[-1] == 'run'
78 |
79 | def not_found(self):
80 | self.error(404)
81 | self.response.out.write(template.render('templates/not_found.html', locals()))
82 |
83 | def not_authorized(self):
84 | self.error(403)
85 | self.response.out.write(template.render('templates/not_authorized.html', locals()))
86 |
87 | @script_routing
88 | def get(self, script, version, user=None):
89 | if not script.user:
90 | if user:
91 | script.user = user
92 | script.put()
93 | else:
94 | self.redirect(users.create_login_url('/%s' % script_id))
95 | self.response.out.write(template.render('templates/script.html', locals()))
96 |
97 | @script_routing
98 | def post(self, script, version, user=None):
99 | if script.user.key() != user.key():
100 | return self.not_authorized()
101 | version = Version(script=script, body=self.request.get('script'))
102 | version.put()
103 | script.latest_version = version
104 | script.put()
105 | self.redirect('/%s' % script.id)
106 |
107 | class RootHandler(webapp.RequestHandler):
108 | def get(self):
109 | self.redirect('/new')
110 |
111 | def main():
112 | application = webapp.WSGIApplication([
113 | ('/', RootHandler),
114 | ('/new', NewHandler),
115 | ('/.*', ScriptHandler),
116 | ], debug=True)
117 | wsgiref.handlers.CGIHandler().run(application)
118 |
119 |
120 | if __name__ == '__main__':
121 | main()
--------------------------------------------------------------------------------
/site/models.py:
--------------------------------------------------------------------------------
1 | import time
2 | from google.appengine.ext import db
3 |
4 | def baseN(num,b=62,numerals="0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"):
5 | return ((num == 0) and "0" ) or (baseN(num // b, b).lstrip("0") + numerals[num % b])
6 |
7 | class Script(db.Model):
8 | user = db.UserProperty(auto_current_user_add=True)
9 | id = db.StringProperty(required=True)
10 | name = db.StringProperty()
11 | private = db.BooleanProperty(default=False)
12 | latest_version = db.ReferenceProperty()
13 |
14 | created = db.DateTimeProperty(auto_now_add=True)
15 | edited = db.DateTimeProperty()
16 | executed = db.DateTimeProperty()
17 | run_count = db.IntegerProperty(default=0)
18 |
19 | # Legacy fields
20 | name = db.StringProperty()
21 | code = db.TextProperty()
22 | language = db.StringProperty()
23 |
24 | def __init__(self, *args, **kwargs):
25 | kwargs['id'] = kwargs.get('id', baseN(abs(hash(time.time()))))
26 | super(Script, self).__init__(*args, **kwargs)
27 |
28 | class Version(db.Model):
29 | script = db.ReferenceProperty(Script)
30 | id = db.StringProperty(required=True)
31 | body = db.TextProperty()
32 |
33 | created = db.DateTimeProperty(auto_now_add=True)
34 | executed = db.DateTimeProperty()
35 | run_count = db.IntegerProperty(default=0)
36 |
37 | def __init__(self, *args, **kwargs):
38 | kwargs['id'] = kwargs.get('id', str(abs(hash(time.time()))))
39 | super(Version, self).__init__(*args, **kwargs)
--------------------------------------------------------------------------------
/site/static/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/progrium/scriptlets/ea59e09cc7bd07ee72102e0266662e1770e9af64/site/static/.DS_Store
--------------------------------------------------------------------------------
/site/static/contrib/php/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2008-2009, Yahoo! Inc.
2 | All rights reserved.
3 |
4 | This software is provided for use in connection with the
5 | CodeMirror suite of modules and utilities, hosted and maintained
6 | at http://marijn.haverbeke.nl/codemirror/.
7 |
8 | Redistribution and use of this software in source and binary forms,
9 | with or without modification, are permitted provided that the
10 | following conditions are met:
11 |
12 | * Redistributions of source code must retain the above
13 | copyright notice, this list of conditions and the
14 | following disclaimer.
15 |
16 | * Redistributions in binary form must reproduce the above
17 | copyright notice, this list of conditions and the
18 | following disclaimer in the documentation and/or other
19 | materials provided with the distribution.
20 |
21 | * Neither the name of Yahoo! Inc. nor the names of its
22 | contributors may be used to endorse or promote products
23 | derived from this software without specific prior
24 | written permission of Yahoo! Inc.
25 |
26 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
27 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
28 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
29 | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
30 | COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
31 | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
32 | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
33 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
34 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35 | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
36 | ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37 | POSSIBILITY OF SUCH DAMAGE.
38 |
--------------------------------------------------------------------------------
/site/static/contrib/php/css/phpcolors.css:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2008-2009 Yahoo! Inc. All rights reserved.
3 | The copyrights embodied in the content of this file are licensed by
4 | Yahoo! Inc. under the BSD (revised) open source license
5 |
6 | @author Dan Vlad Dascalescu
7 | */
8 |
9 | .editbox {
10 | margin: .4em;
11 | padding: 0;
12 | font-family: monospace;
13 | font-size: 10pt;
14 | }
15 |
16 | /*We should define specific styles for every element of the syntax.
17 | the setting below will cause some annoying color to show through if we missed
18 | defining a style for a token. This is also the "color" of the whitespace and
19 | of the cursor.
20 | */
21 | pre.code, .editbox {
22 | color: red;
23 | }
24 |
25 | .editbox p {
26 | margin: 0;
27 | }
28 |
29 | span.php-punctuation {
30 | color: blue;
31 | }
32 |
33 | span.php-keyword {
34 | color: #770088;
35 | font-weight: bold;
36 | }
37 |
38 | span.php-operator {
39 | color: blue;
40 | }
41 |
42 | /* __FILE__ etc.; http://php.net/manual/en/reserved.php */
43 | span.php-compile-time-constant {
44 | color: #776088;
45 | font-weight: bold;
46 | }
47 |
48 | /* output of get_defined_constants(). Differs from http://php.net/manual/en/reserved.constants.php */
49 | span.php-predefined-constant {
50 | color: darkgreen;
51 | font-weight: bold;
52 | }
53 |
54 | /* PHP reserved "language constructs"... echo() etc.; http://php.net/manual/en/reserved.php */
55 | span.php-reserved-language-construct {
56 | color: green;
57 | font-weight: bold;
58 | }
59 |
60 | /* PHP built-in functions: glob(), chr() etc.; output of get_defined_functions()["internal"] */
61 | span.php-predefined-function {
62 | color: green;
63 | }
64 |
65 | /* PHP predefined classes: PDO, Exception etc.; output of get_declared_classes() and different from http://php.net/manual/en/reserved.classes.php */
66 | span.php-predefined-class {
67 | color: green;
68 | }
69 |
70 | span.php-atom {
71 | color: #228811;
72 | }
73 |
74 | /* class, interface, namespace or function names, but not $variables */
75 | span.php-t_string {
76 | color: black;
77 | }
78 |
79 | span.php-variable {
80 | color: black;
81 | font-weight: bold;
82 | }
83 |
84 |
85 | span.js-localvariable {
86 | color: #004499;
87 | }
88 |
89 | span.php-comment {
90 | color: #AA7700;
91 | font-stretch: condensed;
92 | /* font-style: italic; This causes line height to slightly change, getting line numbers out of sync */
93 | }
94 |
95 | span.php-string-single-quoted {
96 | color: #AA2222;
97 | }
98 | /* double quoted strings allow interpolation */
99 | span.php-string-double-quoted {
100 | color: #AA2222;
101 | font-weight: bold;
102 | }
103 |
104 | span.syntax-error {
105 | background-color: red;
106 | }
107 |
108 | span.deprecated {
109 | font-size: smaller;
110 | }
111 |
--------------------------------------------------------------------------------
/site/static/contrib/php/index.html:
--------------------------------------------------------------------------------
1 |
9 |
10 |
11 |
12 |
13 |
14 | CodeMirror: PHP+HTML+JavaScript+CSS mixed-mode demonstration
15 |
16 |
17 |
18 |
19 |
This is a complex demonstration of the PHP+HTML+JavaScript+CSS mixed-mode
20 | syntax highlight capabilities of CodeMirror.
21 | <?php ... ?> tags use the PHP parser, <script> tags use the JavaScript
22 | parser, and <style> tags use the CSS parser. The rest of the content is
23 | parsed using the XML parser in HTML mode.
24 |
25 |
Features of the PHP parser:
26 |
27 |
special "deprecated" style for PHP4 keywords like 'var'
28 |
support for PHP 5.3 keywords: 'namespace', 'use'
29 |
911 predefined constants, 1301 predefined functions, 105 predeclared classes
30 | from a typical PHP installation in a LAMP environment
31 |
function definitions with explicitly or implicitly typed arguments and default values
34 |
modifiers (public, static etc.) applied to method and member definitions
35 |
foreach(array_expression as $key [=> $value]) loops
36 |
37 |
differentiation between single-quoted strings and double-quoted interpolating strings
38 |
39 |
40 |
41 |
42 |
276 |
277 |
278 |
289 |
290 |
291 |
292 |
293 |
--------------------------------------------------------------------------------
/site/static/contrib/php/js/parsephp.js:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2008-2009 Yahoo! Inc. All rights reserved.
3 | The copyrights embodied in the content of this file are licensed by
4 | Yahoo! Inc. under the BSD (revised) open source license
5 |
6 | @author Dan Vlad Dascalescu
7 |
8 |
9 | Parse function for PHP. Makes use of the tokenizer from tokenizephp.js.
10 | Based on parsejavascript.js by Marijn Haverbeke.
11 |
12 |
13 | Features:
14 | + special "deprecated" style for PHP4 keywords like 'var'
15 | + support for PHP 5.3 keywords: 'namespace', 'use'
16 | + 911 predefined constants, 1301 predefined functions, 105 predeclared classes
17 | from a typical PHP installation in a LAMP environment
18 | + new feature: syntax error flagging, thus enabling strict parsing of:
19 | + function definitions with explicitly or implicitly typed arguments and default values
20 | + modifiers (public, static etc.) applied to method and member definitions
21 | + foreach(array_expression as $key [=> $value]) loops
22 | + differentiation between single-quoted strings and double-quoted interpolating strings
23 |
24 | */
25 |
26 |
27 | // add the Array.indexOf method for JS engines that don't support it (e.g. IE)
28 | // code from https://developer.mozilla.org/En/Core_JavaScript_1.5_Reference/Global_Objects/Array/IndexOf
29 | if (!Array.prototype.indexOf)
30 | {
31 | Array.prototype.indexOf = function(elt /*, from*/)
32 | {
33 | var len = this.length;
34 |
35 | var from = Number(arguments[1]) || 0;
36 | from = (from < 0)
37 | ? Math.ceil(from)
38 | : Math.floor(from);
39 | if (from < 0)
40 | from += len;
41 |
42 | for (; from < len; from++)
43 | {
44 | if (from in this &&
45 | this[from] === elt)
46 | return from;
47 | }
48 | return -1;
49 | };
50 | };
51 |
52 |
53 | var PHPParser = Editor.Parser = (function() {
54 | // Token types that can be considered to be atoms, part of operator expressions
55 | var atomicTypes = {
56 | "atom": true, "number": true, "variable": true, "string": true
57 | };
58 | // Constructor for the lexical context objects.
59 | function PHPLexical(indented, column, type, align, prev, info) {
60 | // indentation at start of this line
61 | this.indented = indented;
62 | // column at which this scope was opened
63 | this.column = column;
64 | // type of scope ('stat' (statement), 'form' (special form), '[', '{', or '(')
65 | this.type = type;
66 | // '[', '{', or '(' blocks that have any text after their opening
67 | // character are said to be 'aligned' -- any lines below are
68 | // indented all the way to the opening character.
69 | if (align != null)
70 | this.align = align;
71 | // Parent scope, if any.
72 | this.prev = prev;
73 | this.info = info;
74 | };
75 |
76 | // PHP indentation rules
77 | function indentPHP(lexical) {
78 | return function(firstChars) {
79 | var firstChar = firstChars && firstChars.charAt(0), type = lexical.type;
80 | var closing = firstChar == type;
81 | if (type == "form" && firstChar == "{")
82 | return lexical.indented;
83 | else if (type == "stat" || type == "form")
84 | return lexical.indented + indentUnit;
85 | else if (lexical.info == "switch" && !closing)
86 | return lexical.indented + (/^(?:case|default)\b/.test(firstChars) ? indentUnit : 2 * indentUnit);
87 | else if (lexical.align)
88 | return lexical.column - (closing ? 1 : 0);
89 | else
90 | return lexical.indented + (closing ? 0 : indentUnit);
91 | };
92 | };
93 |
94 | // The parser-iterator-producing function itself.
95 | function parsePHP(input, basecolumn) {
96 | // Wrap the input in a token stream
97 | var tokens = tokenizePHP(input);
98 | // The parser state. cc is a stack of actions that have to be
99 | // performed to finish the current statement. For example we might
100 | // know that we still need to find a closing parenthesis and a
101 | // semicolon. Actions at the end of the stack go first. It is
102 | // initialized with an infinitely looping action that consumes
103 | // whole statements.
104 | var cc = [statements];
105 | // The lexical scope, used mostly for indentation.
106 | var lexical = new PHPLexical((basecolumn || 0) - indentUnit, 0, "block", false);
107 | // Current column, and the indentation at the start of the current
108 | // line. Used to create lexical scope objects.
109 | var column = 0;
110 | var indented = 0;
111 | // Variables which are used by the mark, cont, and pass functions
112 | // below to communicate with the driver loop in the 'next' function.
113 | var consume, marked;
114 |
115 | // The iterator object.
116 | var parser = {next: next, copy: copy};
117 |
118 | // parsing is accomplished by calling next() repeatedly
119 | function next(){
120 | // Start by performing any 'lexical' actions (adjusting the
121 | // lexical variable), or the operations below will be working
122 | // with the wrong lexical state.
123 | while(cc[cc.length - 1].lex)
124 | cc.pop()();
125 |
126 | // Fetch the next token.
127 | var token = tokens.next();
128 |
129 | // Adjust column and indented.
130 | if (token.type == "whitespace" && column == 0)
131 | indented = token.value.length;
132 | column += token.value.length;
133 | if (token.content == "\n"){
134 | indented = column = 0;
135 | // If the lexical scope's align property is still undefined at
136 | // the end of the line, it is an un-aligned scope.
137 | if (!("align" in lexical))
138 | lexical.align = false;
139 | // Newline tokens get an indentation function associated with
140 | // them.
141 | token.indentation = indentPHP(lexical);
142 | }
143 | // No more processing for meaningless tokens.
144 | if (token.type == "whitespace" || token.type == "comment"
145 | || token.type == "string_not_terminated" )
146 | return token;
147 | // When a meaningful token is found and the lexical scope's
148 | // align is undefined, it is an aligned scope.
149 | if (!("align" in lexical))
150 | lexical.align = true;
151 |
152 | // Execute actions until one 'consumes' the token and we can
153 | // return it. 'marked' is used to change the style of the current token.
154 | while(true) {
155 | consume = marked = false;
156 | // Take and execute the topmost action.
157 | var action = cc.pop();
158 | action(token);
159 |
160 | if (consume){
161 | if (marked)
162 | token.style = marked;
163 | // Here we differentiate between local and global variables.
164 | return token;
165 | }
166 | }
167 | return 1; // Firebug workaround for http://code.google.com/p/fbug/issues/detail?id=1239#c1
168 | }
169 |
170 | // This makes a copy of the parser state. It stores all the
171 | // stateful variables in a closure, and returns a function that
172 | // will restore them when called with a new input stream. Note
173 | // that the cc array has to be copied, because it is contantly
174 | // being modified. Lexical objects are not mutated, so they can
175 | // be shared between runs of the parser.
176 | function copy(){
177 | var _lexical = lexical, _cc = cc.concat([]), _tokenState = tokens.state;
178 |
179 | return function copyParser(input){
180 | lexical = _lexical;
181 | cc = _cc.concat([]); // copies the array
182 | column = indented = 0;
183 | tokens = tokenizePHP(input, _tokenState);
184 | return parser;
185 | };
186 | }
187 |
188 | // Helper function for pushing a number of actions onto the cc
189 | // stack in reverse order.
190 | function push(fs){
191 | for (var i = fs.length - 1; i >= 0; i--)
192 | cc.push(fs[i]);
193 | }
194 | // cont and pass are used by the action functions to add other
195 | // actions to the stack. cont will cause the current token to be
196 | // consumed, pass will leave it for the next action.
197 | function cont(){
198 | push(arguments);
199 | consume = true;
200 | }
201 | function pass(){
202 | push(arguments);
203 | consume = false;
204 | }
205 | // Used to change the style of the current token.
206 | function mark(style){
207 | marked = style;
208 | }
209 | // Add a lyer of style to the current token, for example syntax-error
210 | function mark_add(style){
211 | marked = marked + ' ' + style;
212 | }
213 |
214 | // Push a new lexical context of the given type.
215 | function pushlex(type, info) {
216 | var result = function pushlexing() {
217 | lexical = new PHPLexical(indented, column, type, null, lexical, info)
218 | };
219 | result.lex = true;
220 | return result;
221 | }
222 | // Pop off the current lexical context.
223 | function poplex(){
224 | lexical = lexical.prev;
225 | }
226 | poplex.lex = true;
227 | // The 'lex' flag on these actions is used by the 'next' function
228 | // to know they can (and have to) be ran before moving on to the
229 | // next token.
230 |
231 | // Creates an action that discards tokens until it finds one of
232 | // the given type. This will ignore (and recover from) syntax errors.
233 | function expect(wanted){
234 | return function expecting(token){
235 | if (token.type == wanted) cont(); // consume the token
236 | else {
237 | cont(arguments.callee); // continue expecting() - call itself
238 | }
239 | };
240 | }
241 |
242 | // Require a specific token type, or one of the tokens passed in the 'wanted' array
243 | // Used to detect blatant syntax errors. 'execute' is used to pass extra code
244 | // to be executed if the token is matched. For example, a '(' match could
245 | // 'execute' a cont( compasep(funcarg), require(")") )
246 | function require(wanted, execute){
247 | return function requiring(token){
248 | var ok;
249 | var type = token.type;
250 | if (typeof(wanted) == "string")
251 | ok = (type == wanted) -1;
252 | else
253 | ok = wanted.indexOf(type);
254 | if (ok >= 0) {
255 | if (execute && typeof(execute[ok]) == "function")
256 | execute[ok](token);
257 | cont(); // just consume the token
258 | }
259 | else {
260 | if (!marked) mark(token.style);
261 | mark_add("syntax-error");
262 | cont(arguments.callee);
263 | }
264 | };
265 | }
266 |
267 | // Looks for a statement, and then calls itself.
268 | function statements(token){
269 | return pass(statement, statements);
270 | }
271 | // Dispatches various types of statements based on the type of the current token.
272 | function statement(token){
273 | var type = token.type;
274 | if (type == "keyword a") cont(pushlex("form"), expression, statement, poplex);
275 | else if (type == "keyword b") cont(pushlex("form"), statement, poplex);
276 | else if (type == "{") cont(pushlex("}"), block, poplex);
277 | else if (type == "function") funcdef();
278 | // technically, "class implode {...}" is correct, but we'll flag that as an error because it overrides a predefined function
279 | else if (type == "class") cont(require("t_string"), expect("{"), pushlex("}"), block, poplex);
280 | else if (type == "foreach") cont(pushlex("form"), require("("), pushlex(")"), expression, require("as"), require("variable"), /* => $value */ expect(")"), poplex, statement, poplex);
281 | else if (type == "for") cont(pushlex("form"), require("("), pushlex(")"), expression, require(";"), expression, require(";"), expression, require(")"), poplex, statement, poplex);
282 | // public final function foo(), protected static $bar;
283 | else if (type == "modifier") cont(require(["modifier", "variable", "function"], [null, null, funcdef]));
284 | else if (type == "switch") cont(pushlex("form"), require("("), expression, require(")"), pushlex("}", "switch"), require([":", "{"]), block, poplex, poplex);
285 | else if (type == "case") cont(expression, require(":"));
286 | else if (type == "default") cont(require(":"));
287 | else if (type == "catch") cont(pushlex("form"), require("("), require("t_string"), require("variable"), require(")"), statement, poplex);
288 | else if (type == "const") cont(require("t_string")); // 'const static x=5' is a syntax error
289 | // technically, "namespace implode {...}" is correct, but we'll flag that as an error because it overrides a predefined function
290 | else if (type == "namespace") cont(namespacedef, require(";"));
291 | // $variables may be followed by operators, () for variable function calls, or [] subscripts
292 | else pass(pushlex("stat"), expression, require(";"), poplex);
293 | }
294 | // Dispatch expression types.
295 | function expression(token){
296 | var type = token.type;
297 | if (atomicTypes.hasOwnProperty(type)) cont(maybeoperator);
298 | else if (type == "<<<") cont(require("string"), maybeoperator); // heredoc/nowdoc
299 | else if (type == "t_string") cont(maybe_double_colon, maybeoperator);
300 | else if (type == "keyword c") cont(expression);
301 | // function call or parenthesized expression: $a = ($b + 1) * 2;
302 | else if (type == "(") cont(pushlex(")"), commasep(expression), require(")"), poplex, maybeoperator);
303 | else if (type == "operator") cont(expression);
304 | }
305 | // Called for places where operators, function calls, or subscripts are
306 | // valid. Will skip on to the next action if none is found.
307 | function maybeoperator(token){
308 | var type = token.type;
309 | if (type == "operator") {
310 | if (token.content == "?") cont(expression, require(":"), expression); // ternary operator
311 | else cont(expression);
312 | }
313 | else if (type == "(") cont(pushlex(")"), expression, commasep(expression), require(")"), poplex, maybeoperator /* $varfunc() + 3 */);
314 | else if (type == "[") cont(pushlex("]"), expression, require("]"), maybeoperator /* for multidimensional arrays, or $func[$i]() */, poplex);
315 | }
316 | // A regular use of the double colon to specify a class, as in self::func() or myclass::$var;
317 | // Differs from `namespace` or `use` in that only one class can be the parent; chains (A::B::$var) are a syntax error.
318 | function maybe_double_colon(token) {
319 | if (token.type == "t_double_colon")
320 | // A::$var, A::func(), A::const
321 | cont(require(["t_string", "variable"]), maybeoperator);
322 | else {
323 | // a t_string wasn't followed by ::, such as in a function call: foo()
324 | pass(expression)
325 | }
326 | }
327 | // the declaration or definition of a function
328 | function funcdef() {
329 | cont(require("t_string"), require("("), pushlex(")"), commasep(funcarg), require(")"), poplex, block);
330 | }
331 | // Parses a comma-separated list of the things that are recognized
332 | // by the 'what' argument.
333 | function commasep(what){
334 | function proceed(token) {
335 | if (token.type == ",") cont(what, proceed);
336 | };
337 | return function commaSeparated() {
338 | pass(what, proceed);
339 | };
340 | }
341 | // Look for statements until a closing brace is found.
342 | function block(token) {
343 | if (token.type == "}") cont();
344 | else pass(statement, block);
345 | }
346 | function maybedefaultparameter(token){
347 | if (token.content == "=") cont(expression);
348 | }
349 | // support for default arguments: http://us.php.net/manual/en/functions.arguments.php#functions.arguments.default
350 | function funcarg(token){
351 | // function foo(myclass $obj) {...}
352 | if (token.type == "t_string") cont(require("variable"), maybedefaultparameter);
353 | // function foo($string) {...}
354 | else if (token.type == "variable") cont(maybedefaultparameter);
355 | }
356 |
357 | // A namespace definition or use
358 | function maybe_double_colon_def(token) {
359 | if (token.type == "t_double_colon")
360 | cont(namespacedef);
361 | }
362 | function namespacedef(token) {
363 | pass(require("t_string"), maybe_double_colon_def);
364 | }
365 |
366 | return parser;
367 | }
368 |
369 | return {make: parsePHP, electricChars: "{}:"};
370 |
371 | })();
372 |
--------------------------------------------------------------------------------
/site/static/contrib/php/js/parsephphtmlmixed.js:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2008-2009 Yahoo! Inc. All rights reserved.
3 | The copyrights embodied in the content of this file are licensed by
4 | Yahoo! Inc. under the BSD (revised) open source license
5 |
6 | @author Dan Vlad Dascalescu
7 |
8 | Based on parsehtmlmixed.js by Marijn Haverbeke.
9 | */
10 |
11 | var PHPHTMLMixedParser = Editor.Parser = (function() {
12 | if (!(PHPParser && CSSParser && JSParser && XMLParser))
13 | throw new Error("PHP, CSS, JS, and XML parsers must be loaded for PHP+HTML mixed mode to work.");
14 | XMLParser.configure({useHTMLKludges: true});
15 |
16 | function parseMixed(stream) {
17 | var htmlParser = XMLParser.make(stream), localParser = null, inTag = false;
18 | var iter = {next: top, copy: copy};
19 |
20 | function top() {
21 | var token = htmlParser.next();
22 | if (token.content == "<")
23 | inTag = true;
24 | else if (token.style == "xml-tagname" && inTag === true)
25 | inTag = token.content.toLowerCase();
26 | else if (token.type == "xml-processing") {
27 | // dispatch on PHP
28 | if (token.content == "");
30 | }
31 | // "xml-processing" tokens are ignored, because they should be handled by a specific local parser
32 | else if (token.content == ">") {
33 | if (inTag == "script")
34 | iter.next = local(JSParser, "
2 |
3 |
4 | CodeMirror: Python demonstration
5 |
18 |
19 |
20 |
21 | This is a simple demonstration of the Python syntax highlighting module
22 | for CodeMirror.
23 |
24 |
25 | Features of this parser include:
26 |
27 |
28 |
Token-based syntax highlighting - currently very little lexical analysis happens. Few lexical errors will be detected.
29 |
Use the normal indentation mode to enforce regular indentation, otherwise the "shift" indentation mode will give you more flexibility.
30 |
Parser Options:
31 |
32 |
pythonVersion (Integer) - 2 or 3 to indicate which version of Python to parse. Default = 2
33 |
strictErrors (Bool) - true to highlight errors that may not be Python errors but cause confusion for this parser. Default = true
34 |
35 |
36 |
37 |
Written by Timothy Farrell (license). Special
38 | thanks to Adam Brand and Marijn Haverbeke for their help in debugging
39 | and providing for this parser.