Cajita Transformation Rules

Default set of transformations used by Cajita

RuleSynopsisReasonMatchesSubstitutes
0syntheticReferencePass through synthetic references.A variable may not be mentionable otherwise./* synthetic */ @ref<expanded>
1syntheticCallsPass through calls where the function name is synthetic.A synthetic method may not be marked callable./* synthetic */ @f(@as*)<expanded>
2syntheticMethodCallsPass through calls where the method name is synthetic.A synthetic method may not be marked callable./* synthetic */ @o.@m(@as*)<expanded>
3syntheticDeletesPass through deletes of synthetic members.A synthetic member may not be marked deletable./* synthetic */ delete @o.@m<expanded>
4syntheticReadsPass through reads of synthetic members.A synthetic member may not be marked readable./* synthetic */ @o.@m<expanded>
5syntheticSetMemberPass through sets of synthetic members.A synthetic member may not be marked writable./* synthetic */ @o.@m = @v<expanded>
6syntheticSetVarPass through set of synthetic vars.A local variable might not be mentionable otherwise./* synthetic */ @lhs = @rhs<expanded>
7syntheticDeclarationPass through synthetic variables which are unmentionable.Synthetic code might need local variables for safe-keeping./* synthetic */ var @v = @initial?;<expanded>
8syntheticFormalsPass through synthetic formals which are unmentionable.Synthetic code might need local variables for safe-keeping./* synthetic */ @x in a parameter list<expanded>
9syntheticFnDeclarationAllow declaration of synthetic functions.Synthetic functions allow generated code to avoid introducing unnecessary scopes./* synthetic */ function @i?(@actuals*) { @body* }<expanded>
10syntheticCatches1Pass through synthetic variables which are unmentionable.Catching unmentionable exceptions helps maintain invariants.try { @body*; } catch (/* synthetic */ @ex___) { @handler*; }try { @body*; } catch (@ex___) { @handler*; }
11syntheticCatches2Pass through synthetic variables which are unmentionable.Catching unmentionable exceptions helps maintain invariants.try { @body*; } catch (/* synthetic */ @ex___) { @handler*; } finally { @cleanup*; }try { @body*; } catch (/* synthetic */ @ex___) { @handler*; } finally { @cleanup*; }
12translatedCodeAllow code received from a *->JS translatorTranslated code should not be treated as user supplied JS.<TranslatedCode><UNKNOWN>
13labeledStatementStatically reject if a label with `__` suffix is foundCaja reserves the `__` suffix for internal use@lbl: @stmt;@lbl: @stmt;
14loadmodulerewrites the load function.load(@arg)depending on whether moduleManager bundles modules
15moduleEnvelopeCajole an UncajoledModule into a CajoledModule. Note that the ouptut is a CajoledModule wrapper *around* thecontents of the 'substitutes' of this rule.So that the module loader can be invoked to load a module.<an UncajoledModule>(/*@synthetic*/{ instantiate: /*@synthetic*/function (___, IMPORTS___) { /*var moduleResult___ = ___.NO_RESULT;*/ @rewrittenModuleStmts*; /*return moduleResult___;*/ }, @metaKeys*: @metaValues*, cajolerName: @cajolerName, cajolerVersion: @cajolerVersion, cajoledDate: @cajoledDate})
16moduleImport free vars. Return last expr-statementBuilds the module body encapsulation around the Cajita code block.{@ss*;}@importedvars*; @startStmts*; @expanded*;
17blockInitialize named functions at the beginning of their enclosing block.Nested named function declarations are illegal in ES3 but are universally supported by all JavaScript implementations, though in different ways. The compromise semantics currently supported by Cajita is to hoist the declaration of a variable with the function's name to the beginning of the enclosing function body or module top level, and to initialize this variable to a new anonymous function every time control re-enters the enclosing block. Note that ES-Harmony will specify a better and safer semantics -- block level lexical scoping -- that we'd like to adopt into Cajita eventually. However, it is so challenging to implement this semantics by translation to currently-implemented JavaScript that we provide something quicker and dirtier for now.{@ss*;}@startStmts*; @ss*;
18withStatically reject if a `with` block is found.`with` violates the assumptions made by Scope, and makes it very hard to write a Scope that works. http://yuiblog.com/blog/2006/04/11/with-statement-considered-harmful/ briefly touches on why `with` is bad for programmers. For reviewers -- matching of references with declarations can only be done at runtime. All other secure JS subsets that we know of (ADSafe, Jacaranda, & FBJS) also disallow `with`.with (@scope) @body;<reject>
19foreachExprGet the keys, then iterate over them.for (@k in @o) @ss;for (@tkeys = cajita.allKeys(@o), @tidx = 0, @tlen = @tkeys.length; @tidx < @tlen; ++@tidx) { @assign; @ss; }
20tryCatchEnsure that only immutable data is thrown, and repair scope confusion in existing JavaScript implementations of try/catch.When manually reviewing code for vulnerability, experience shows that reviewers cannot pay adequate attention to the pervasive possibility of thrown exceptions. These lead to four dangers: 1) leaking an authority-bearing object, endangering integrity, 2) leaking a secret, endangering secrecy, and 3) aborting a partially completed state update, leaving the state malformed, endangering integrity, and 4) preventing an operation that was needed, endangering availability. Caja only seeks to make strong claims about integrity. By ensuring that only immutable (transitively frozen) data is thrown, we prevent problem #1. For the others, programmer vigilance is still needed. Current JavaScript implementations fail, in different ways, to implement the scoping of the catch variable specified in ES3. We translate Caja to JavaScript so as to implement the ES3 specified scoping on current JavaScript implementations.try { @s0*; } catch (@x) { @s1*; }try { @s0*; } catch (ex___) { try { throw ___.tameException(ex___); } catch (@x) { @s1*; } }
21tryCatchFinallyFinally adds no special issues beyond those explained in try/catch.Caja is not attempting to impose determinism, so the reasons for Joe-E to avoid finally do not apply.try { @s0*; } catch (@x) { @s1*; } finally { @s2*; }try { @s0*; } catch (ex___) { try { throw ___.tameException(ex___); } catch (@x) { @s1*; } } finally { @s2*; }
22tryFinallySee bug 383. Otherwise, it's just the trivial translation.try/finally actually seems to work as needed by current JavaScript implementations.try { @s0*; } finally { @s1*; }try { @s0*; } finally { @s1*; }
23varArgsMake all references to the magic "arguments" variable into references to a frozen array containing a snapshot of the actual arguments taken when the function was first entered.ES3 specifies that the magic "arguments" variable is a dynamic ("joined") mutable array-like reflection of the values of the parameter variables. However, the typical usage is to pass it to provide access to one's original arguments -- without the intention of providing the ability to mutate the caller's parameter variables. By making a frozen array snapshot with no "callee" property, we provide the least authority assumed by this typical use. The snapshot is made with a "var a___ = ___.args(arguments);" generated at the beginning of the function body.argumentsa___
24varThisBadThe "this" keyword is not permitted in Cajita.The rules for binding of "this" in JavaScript are dangerous.this<rejected>
25varBadSuffixStatically reject if a variable with `__` suffix is found.Caja reserves the `__` suffix for internal use.@v__<reject>
26varBadSuffixDeclarationStatically reject if a variable with `__` suffix is found.Caja reserves the `__` suffix for internal use.<approx>(var|function) @v__ ...<reject>
27varFuncFreezeAn escaping occurence of a function name freezes the function.@fname___.primFreeze(@fname)
28varDefaultAny remaining uses of a variable name are preserved.@v@v
29readBadSuffixStatically reject if a property has `__` suffix is found.Caja reserves the `__` suffix for internal use.@x.@p__<reject>
30readBadPrototypeWarn that reading the 'prototype' property of a function is useless in Cajita.A programmer reading the 'prototype' property of a function is most likely attempting classic JavaScript prototypical inheritance, which is not supported in Cajita.@f.prototype<warning>
31permittedReadWhen @o.@m is a statically permitted read, translate directly.The static permissions check is recorded so that, when the base of @o is imported, we check that this static permission was actually safe to assume.@o.@m@o.@m
32readPublicLengthLength is whitelisted on Object.prototype@o.length@o.length
33readPublic@o.@p@oRef.@fp ? @oRef.@p : ___.readPub(@oRef, '@p')
34readNumPublicRecognize that array indexing is inherently safe.When the developer knows that their index expression is an array index, they can indicate this with the 'absolute value operator', really an expression which coerces to a nonnegative 32-bit integer. Since these properties are necessarily readable, we can pass them through directly to JavaScript.@o[@s&(-1>>>1)]@o[@s&(-1>>>1)]
35readNumWithConstantIndexRecognize that array indexing is inherently safe.Nonnegative integer properties are always readable; we can pass these through directly to JavaScript.@o[@numLiteral]@o[@numLiteral]
36readIndexPublic@o[@s]___.readPub(@o, @s)
37setBadAssignToFunctionNameStatically reject if an assignment expression assigns to a function name.<approx> @fname @op?= @x<reject>
38setBadThisThe "this" keyword is not permitted in Cajita.The rules for binding of "this" in JavaScript are dangerous.this = @z<reject>
39setBadFreeVariableStatically reject if an expression assigns to a free variable.This is still controversial (see bug 375). However, the rationale is to prevent code that's nested lexically within a module to from introducing mutable state outside its local function-body scope. Without this rule, two nested blocks within the same module could communicate via a pseudo-imported variable that is not declared or used at the outer scope of the module body.@import = @y<reject>
40setBadValueOfStatically reject if assigning to valueOf.We depend on valueOf returning consistent results.@x.valueOf = @z<reject>
41setBadSuffixStatically reject if a property with `__` suffix is found.Caja reserves the `__` suffix for internal use.@x.@p__ = @z<reject>
42setBadPrototypeWarn that setting the 'prototype' property of a function is useless in Cajita.A programmer setting the 'prototype' property of a function is most likely attempting classic JavaScript prototypical inheritance, which is not supported in Cajita.@f.prototype = @rhs<warning>
43setStaticInitialize the direct properties (static members) of a potentially-mutable named function.@fname.@p = @r___.setStatic(@fname, @'p', @r)
44setIndexStaticInitialize the computed direct properties (static members) of a potentially-mutable named function.@fname[@s] = @r___.setStatic(@fname, @s, @r)
45setPublicSet a public property.If the object is an unfrozen JSONContainer (a record or array), then this will create the own property if needed. If it is an unfrozen constructed object, then clients can assign to existing public own properties, but cannot directly create such properties.@o.@p = @r<approx> ___.setPub(@o, @'p', @r);
46setIndexPublic@o[@s] = @r___.setPub(@o, @s, @r)
47setBadInitializeStatically reject if a variable with `__` suffix is found.Caja reserves the `__` suffix for internal use.var @v__ = @r<reject>
48setInitializeEnsure v is not a function name. Expand the right side.var @v = @r@v = @r
49setBadDeclareStatically reject if a variable with `__` suffix is found.Caja reserves the `__` suffix for internal use.var @v__<reject>
50setDeclareEnsure that v isn't a function name.var @vvar @v
51setBadVarStatically reject if a variable with `__` suffix is found.Caja reserves the `__` suffix for internal use.@v__ = @r<reject>
52setVarOnly if v isn't a function name.@v = @r@v = @r
53setReadModifyWriteLocalVar<approx> @x @op= @y<approx> @x = @x @op @y
54setIncrDecrHandle pre and post ++ and --.<approx> ++@x but any {pre,post}{in,de}crement will do<UNKNOWN>
55newCalllessCtorAdd missing empty argument list.JavaScript syntax allows constructor calls without "()".new @ctor___.construct(@ctor, [])
56newCtornew @ctor(@as*)___.construct(@ctor, [@as*])
57deleteBadValueOfProhibit deletion of valueOf.Although a non-existent valueOf should behave the same way asthe default one as regards [[DefaultValue]], for simplicity weonly want to have to consider one of those cases.delete @o.valueOf<reject>
58deleteBadSuffixdelete @o.@p__<reject>
59deletePublicdelete @o.@p___.deletePub(@o, @'p')
60deleteIndexPublicdelete @o[@s]___.deletePub(@o, @s)
61deleteNonPropertydelete @v<reject>
62callBadSuffixStatically reject if a selector with `__` suffix is found.Caja reserves the `__` suffix for internal use.@o.@p__(@as*)<reject>
63permittedCallWhen @o.@m is a statically permitted call, translate directly.The static permissions check is recorded so that, when the base of @o is imported, we check that this static permission was actually safe to assume.@o.@m(@as*)@o.@m(@as*)
64callPublic@o.@m(@as*)<approx> ___.callPub(@o, @'m', [@as*])
65callIndexPublic@o[@s](@as*)___.callPub(@o, @s, [@as*])
66callDeclaredFuncWhen calling a declared function name, leave the freezing to CALL___.If @fname is a declared function name, an escaping use as here would normally generate a call to primFreeze it, so that it's frozen on first use. However, since the default CALL___ method now freezes the function it's called on, if @fname is a declared function name, we avoid expanding it.@fname(@as*)@fname.CALL___(@as*)
67callFunc@f(@as*)@f.CALL___(@as*)
68funcAnonSimplefunction (@ps*) { @bs*; }___.markFuncFreeze( function (@ps*) { @fh*; @stmts*; @bs*; })
69funcNamedTopDeclA non-nested named function doesn't need a makerfunction @fname(@ps*) { @bs*; }function @fname(@ps*) { @fh*; @stmts*; @bs*; } @fnameRef.FUNC___ = '@fname';
70funcNamedSimpleDeclSimulate a nested named function declaration with a top level named function declaration inside an anon function expression.Current (pre-ES5) browsers have wacky scoping semantics for nested named function declarations.function @fname(@ps*) { @bs*; }@fname = (function() { function @fself(@ps*) { @fh*; @stmts*; @bs*; } @fself.FUNC___ = @'fname'; return @fself; })();
71funcNamedSimpleValuefunction @fname(@ps*) { @bs*; }(function() { function @fname(@ps*) { @fh*; @stmts*; @bs*; } return ___.markFuncFreeze(@fRef, '@fname'); })();
72multiDeclarationConsider declarations separately from initializersvar @a=@b?, @c=@d*{ @decl; @init; }
73mapBadKeyValueOfStatically reject 'valueOf' as a keyWe depend on valueOf returning consistent results.'valueOf': @f<reject>
74mapBadKeySuffixStatically reject a property whose name ends with `__`"@k__": @v<reject>
75objectPropertynymize object properties"@k": @v<nymized>
76mapTurns an object literal into an explicit initialization.({@key*: @val*})___.iM([@parts*])
77otherTypeofTypeof translates simplyOne of Caja's deviations from JavaScript is that reading a non-existent imported variable returns 'undefined' rather than throwing a ReferenceError. Therefore, in Caja, 'typeof' can always evaluate its argument.typeof @f___.typeOf(@f)
78inPublicIs a public property present on the object?@i in @o___.inPub(@i, @o)
79voidOpvoid @xvoid @x
80commaOp(@a, @b)(@a, @b)
81breakStmtdisallow labels that end in __break @a;break @a;
82continueStmtdisallow labels that end in __continue @a;continue @a;
83regexLiteralCajita requires use of the regular expression constructorBecause JavaScript regex literal instances are shared by default, and regex literal lexing is difficult./foo/<reject>
84useSubsetDirectivereplace use subset directives with noopsrewriting changes the block structure of the input, which could lead to a directive appearing in an illegal position since directives must appear at the beginning of a program or function body, not in an arbitrary block'use';;
85recurseAutomatically recurse into some structures<many><UNKNOWN>