Showing preview only (2,460K chars total). Download the full file or copy to clipboard to get everything.
Repository: evanw/skew
Branch: master
Commit: df456e7be9cf
Files: 92
Total size: 2.3 MB
Directory structure:
gitextract_luug_bnx/
├── .gitignore
├── .travis.yml
├── LICENSE
├── README.md
├── build.py
├── docs/
│ └── compiler.md
├── extras/
│ ├── Atom/
│ │ └── README.md
│ └── Sublime Text/
│ ├── README.md
│ └── Skew/
│ ├── Comments.tmPreferences
│ ├── Skew.sublime-completions
│ └── Skew.tmLanguage
├── npm/
│ ├── README
│ └── package.json
├── package.json
├── skewc.js
├── src/
│ ├── backend/
│ │ ├── cplusplus.sk
│ │ ├── csharp.sk
│ │ ├── emitter.sk
│ │ ├── javascript.sk
│ │ ├── lisptree.sk
│ │ ├── sourcemap.sk
│ │ └── typescript.sk
│ ├── core/
│ │ ├── content.sk
│ │ ├── node.sk
│ │ ├── operators.sk
│ │ ├── support.sk
│ │ └── symbol.sk
│ ├── cpp/
│ │ ├── fast.cpp
│ │ ├── skew.cpp
│ │ ├── skew.h
│ │ ├── support.cpp
│ │ └── support.h
│ ├── driver/
│ │ ├── jsapi.d.ts
│ │ ├── jsapi.sk
│ │ ├── options.sk
│ │ ├── terminal.sk
│ │ └── tests.sk
│ ├── frontend/
│ │ ├── flex.l
│ │ ├── flex.py
│ │ ├── lexer.py
│ │ ├── lexer.sk
│ │ ├── log.sk
│ │ ├── parser.sk
│ │ ├── pratt.sk
│ │ ├── range.sk
│ │ ├── source.sk
│ │ ├── token.sk
│ │ └── version.sk
│ ├── lib/
│ │ ├── build.sk
│ │ ├── io.sk
│ │ ├── terminal.sk
│ │ ├── timestamp.sk
│ │ └── unit.sk
│ └── middle/
│ ├── callgraph.sk
│ ├── compiler.sk
│ ├── controlflow.sk
│ ├── folding.sk
│ ├── globalizing.sk
│ ├── ide.sk
│ ├── inlining.sk
│ ├── interfaceremoval.sk
│ ├── lambdaconversion.sk
│ ├── library.sk
│ ├── librarycpp.sk
│ ├── librarycs.sk
│ ├── libraryjs.sk
│ ├── merging.sk
│ ├── motion.sk
│ ├── renaming.sk
│ ├── resolving.sk
│ ├── scope.sk
│ ├── shaking.sk
│ ├── type.sk
│ ├── typecache.sk
│ └── unicode.sk
├── tests/
│ ├── cplusplus.sk
│ ├── csharp.sk
│ ├── formatting.sk
│ ├── ide.sk
│ ├── javascript.mangle.sk
│ ├── javascript.minify.sk
│ ├── javascript.sk
│ ├── library.sk
│ ├── node.sk
│ ├── other.sk
│ ├── parsing.sk
│ ├── simple.sk
│ └── unicode.sk
└── www/
├── benchmark.html
├── index.html
├── index.js
└── style.css
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitignore
================================================
.DS_Store
*.pyc
/node_modules/
/out/
/npm/skew.js
/npm/skewc
/npm/skew.cpp
/npm/skew.h
/npm/skew.d.ts
================================================
FILE: .travis.yml
================================================
language: node_js
node_js:
- stable
================================================
FILE: LICENSE
================================================
Copyright (c) 2015 Evan Wallace
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.
================================================
FILE: README.md
================================================
# Skew Programming Language
Visit https://evanw.github.io/skew-lang.org/ for more information and a live demo of the compiler.
================================================
FILE: build.py
================================================
#!/usr/bin/env python
import os
import sys
import glob
import gzip
import json
import time
import pipes
import base64
import shutil
import subprocess
SOURCES = (
glob.glob('src/backend/*.sk') +
glob.glob('src/core/*.sk') +
glob.glob('src/driver/*.sk') +
glob.glob('src/frontend/*.sk') +
glob.glob('src/lib/*.sk') +
glob.glob('src/middle/*.sk') +
glob.glob('tests/*.sk')
)
PUBLIC_CPP_FILES = [
'src/cpp/skew.cpp',
'src/cpp/skew.h',
]
FLAGS = [
'--inline-functions',
'--verbose',
'--message-limit=0',
]
CPP_FLAGS = [
'-std=c++11',
'-Wall',
'-Wextra',
'-Wno-switch',
'-Wno-unused-parameter',
'-Wno-unused-variable',
'-include', 'src/cpp/skew.h',
'-include', 'src/cpp/support.h',
]
CPP_DEBUG_FLAGS = [
'src/cpp/skew.cpp',
'src/cpp/support.cpp',
]
CPP_RELEASE_FLAGS = [
'-O3',
'-DNDEBUG',
'-fomit-frame-pointer',
'-include', 'src/cpp/skew.cpp',
'-include', 'src/cpp/support.cpp',
'-include', 'src/cpp/fast.cpp',
]
CPP_GC_FLAGS = [
'-DSKEW_GC_MARK_AND_SWEEP',
]
node_binary = None
jobs = {}
################################################################################
def job(fn):
jobs[fn.__name__] = fn
return fn
def run(args, exit_on_failure=True, **kwargs):
# Print the command for debugging so that it can be copied and pasted into a terminal directly
print(' '.join(map(pipes.quote, args)))
# Start the process
process = subprocess.Popen(args, stdin=sys.stdin, stdout=sys.stdout, stderr=sys.stderr, **kwargs)
try:
process.wait()
# Abort on failure
if exit_on_failure and process.returncode:
print('error: command exited with code %d' % process.returncode)
sys.exit(1)
return process.returncode
# Ensure the process is terminated
finally:
try:
process.terminate()
except:
pass
def watch_folder(folder, callback):
before = None
while True:
after = ''
for path, name, files in os.walk(folder):
for f in files:
both = '%s/%s' % (path, f)
try:
mtime = os.stat(both).st_mtime
except:
mtime = -1
after += both + '%d,' % mtime
if before != after:
before = after
callback()
time.sleep(0.1)
def load_version():
return json.load(open('npm/package.json'))['version']
def update_version(version):
open('src/frontend/version.sk', 'w').write('namespace Skew {\n const VERSION = %s\n}\n' % json.dumps(version))
def check_same(a, b):
run(['diff', a, b])
def mkdir(path):
try:
os.makedirs(path)
except:
pass
def rmtree(path):
try:
shutil.rmtree(path)
except:
pass
def run_js(source, args, exit_on_failure=True):
global node_binary
if node_binary is None:
node_binary = 'nodejs' if run(['which', 'nodejs'], exit_on_failure=False) == 0 else 'node'
run([node_binary, source] + args, exit_on_failure=exit_on_failure)
def run_cs(source, args):
run(['mono', '--debug', source] + args)
def run_cpp(source, args):
run([source] + args)
def skewc_js(source, target, sources=SOURCES, build='SKEWC', release=False, exit_on_failure=True):
run_js(source, sources + FLAGS + ['--output-file=' + target, '--define:BUILD=' + build] + (['--release'] if release else []), exit_on_failure=exit_on_failure)
def skewc_cs(source, target, sources=SOURCES, build='SKEWC', release=False):
run_cs(source, sources + FLAGS + ['--output-file=' + target, '--define:BUILD=' + build] + (['--release'] if release else []))
def skewc_cpp(source, target, sources=SOURCES, build='SKEWC', release=False):
run_cpp(source, sources + FLAGS + ['--output-file=' + target, '--define:BUILD=' + build] + (['--release'] if release else []))
def compile_cs(sources, target):
run(['mcs', '-debug'] + sources + ['-out:' + target])
def compile_cpp(source, target, release=False, gc=False):
run(['c++', source, '-o', target] + CPP_FLAGS + (CPP_RELEASE_FLAGS if release else CPP_DEBUG_FLAGS) + (CPP_GC_FLAGS if gc else []))
################################################################################
@job
def default():
mkdir('out')
skewc_js('skewc.js', 'out/skewc.min.js', build='SKEWC', release=True)
skewc_js('skewc.js', 'out/skew-api.min.js', build='API', release=True)
@job
def clean():
rmtree('out')
@job
def replace():
mkdir('out')
skewc_js('skewc.js', 'out/skewc.js', build='SKEWC')
skewc_js('out/skewc.js', 'out/skewc2.js', build='SKEWC')
skewc_js('out/skewc2.js', 'out/skewc3.js', build='SKEWC')
check_same('out/skewc2.js', 'out/skewc3.js')
os.remove('skewc.js')
os.remove('out/skewc2.js')
os.rename('out/skewc3.js', 'skewc.js')
@job
def check():
check_js()
check_cs()
check_cpp()
@job
def check_js():
mkdir('out')
skewc_js('skewc.js', 'out/skewc.min.js', build='SKEWC', release=True)
skewc_js('out/skewc.min.js', 'out/skewc2.min.js', build='SKEWC', release=True)
skewc_js('out/skewc2.min.js', 'out/skewc3.min.js', build='SKEWC', release=True)
check_same('out/skewc2.min.js', 'out/skewc3.min.js')
@job
def check_cs():
mkdir('out')
skewc_js('skewc.js', 'out/skewc.cs', build='SKEWC')
# Iteration 1
compile_cs(['out/skewc.cs'], 'out/skewc.exe')
skewc_cs('out/skewc.exe', 'out/skewc2.cs', build='SKEWC')
# Iteration 2
compile_cs(['out/skewc2.cs'], 'out/skewc2.exe')
skewc_cs('out/skewc2.exe', 'out/skewc3.cs', build='SKEWC')
check_same('out/skewc2.cs', 'out/skewc3.cs')
@job
def check_cpp():
mkdir('out')
skewc_js('skewc.js', 'out/skewc.cpp', build='SKEWC', release=True)
# Iteration 1: Debug
compile_cpp('out/skewc.cpp', 'out/skewc')
skewc_cpp('out/skewc', 'out/skewc2.cpp', build='SKEWC')
# Iteration 2: Release
compile_cpp('out/skewc2.cpp', 'out/skewc2', release=True)
skewc_cpp('out/skewc2', 'out/skewc3.cpp', build='SKEWC')
check_same('out/skewc2.cpp', 'out/skewc3.cpp')
# Iteration 3: GC
compile_cpp('out/skewc3.cpp', 'out/skewc3', gc=True)
skewc_cpp('out/skewc3', 'out/skewc4.cpp', build='SKEWC')
check_same('out/skewc3.cpp', 'out/skewc4.cpp')
@job
def check_determinism():
# Generate JavaScript debug and release builds
mkdir('out')
skewc_js('skewc.js', 'out/skewc.js.js', build='SKEWC')
skewc_js('skewc.js', 'out/skewc.js.min.js', build='SKEWC', release=True)
# Check C#
skewc_js('skewc.js', 'out/skewc.cs', build='SKEWC')
compile_cs(['out/skewc.cs'], 'out/skewc.exe')
skewc_cs('out/skewc.exe', 'out/skewc.cs.js', build='SKEWC')
check_same('out/skewc.js.js', 'out/skewc.cs.js')
skewc_cs('out/skewc.exe', 'out/skewc.cs.min.js', build='SKEWC', release=True)
check_same('out/skewc.js.min.js', 'out/skewc.cs.min.js')
# Check C++
skewc_js('skewc.js', 'out/skewc.cpp', build='SKEWC')
compile_cpp('out/skewc.cpp', 'out/skewc')
skewc_cpp('out/skewc', 'out/skewc.cpp.js', build='SKEWC')
check_same('out/skewc.js.js', 'out/skewc.cpp.js')
skewc_cpp('out/skewc', 'out/skewc.cpp.min.js', build='SKEWC', release=True)
check_same('out/skewc.js.min.js', 'out/skewc.cpp.min.js')
@job
def test():
test_js()
test_cs()
test_cpp()
@job
def test_js():
mkdir('out')
skewc_js('skewc.js', 'out/skewc.js', build='SKEWC')
# Debug
skewc_js('out/skewc.js', 'out/test.js', build='TEST')
run_js('out/test.js', [])
# Release
skewc_js('out/skewc.js', 'out/test.min.js', build='TEST', release=True)
run_js('out/test.min.js', [])
@job
def test_cs():
mkdir('out')
skewc_js('skewc.js', 'out/skewc.js', build='SKEWC')
# Single file
skewc_js('out/skewc.js', 'out/test.cs', build='TEST')
compile_cs(['out/test.cs'], 'out/test.exe')
run_cs('out/test.exe', [])
# Multiple files
rmtree('out/cs')
mkdir('out/cs')
run_js('out/skewc.js', SOURCES + ['--target=cs', '--output-dir=out/cs', '--define:BUILD=TEST'])
compile_cs(glob.glob('out/cs/*.cs'), 'out/test.exe')
run_cs('out/test.exe', [])
@job
def test_cpp():
mkdir('out')
skewc_js('skewc.js', 'out/skewc.js', build='SKEWC')
# Debug
skewc_js('out/skewc.js', 'out/test.debug.cpp', build='TEST')
compile_cpp('out/test.debug.cpp', 'out/test.debug')
run_cpp('out/test.debug', [])
# Release
skewc_js('out/skewc.js', 'out/test.release.cpp', build='TEST', release=True)
compile_cpp('out/test.release.cpp', 'out/test.release', release=True)
run_cpp('out/test.release', [])
# GC
skewc_js('out/skewc.js', 'out/test.gc.cpp', build='TEST')
compile_cpp('out/test.gc.cpp', 'out/test.gc', gc=True)
run_cpp('out/test.gc', [])
@job
def benchmark():
mkdir('out')
open('out/benchmark.sk', 'w').write('\n'.join(open(f).read() for f in SOURCES))
skewc_js('skewc.js', 'out/benchmark.js', sources=['out/benchmark.sk'], release=True)
@job
def watch():
mkdir('out')
watch_folder('src', lambda: skewc_js('skewc.js', 'out/skew-api.js', build='API', exit_on_failure=False))
@job
def flex():
run(['python', 'src/frontend/lexer.py'])
@job
def publish():
test()
check()
run(['npm', 'version', 'patch'], cwd='npm')
version = load_version()
update_version(version)
replace()
skewc_js('skewc.js', 'out/skewc.min.js', build='SKEWC', release=True)
skewc_js('skewc.js', 'npm/skew.js', build='API', release=True)
open('npm/skewc', 'w').write('#!/usr/bin/env node\n' + open('out/skewc.min.js').read())
run(['chmod', '+x', 'npm/skewc'])
shutil.copyfile('src/driver/jsapi.d.ts', 'npm/skew.d.ts')
for name in PUBLIC_CPP_FILES:
shutil.copyfile(name, 'npm/' + os.path.basename(name))
run(['npm', 'publish'], cwd='npm')
################################################################################
def main(args):
if not args:
args = ['default']
for arg in args:
if arg in jobs:
jobs[arg]()
else:
sys.exit('error: unknown job name "%s"' % arg)
main(sys.argv[1:])
================================================
FILE: docs/compiler.md
================================================
# Compiler
This documents the internals of the compiler.
## Development
Development on the compiler itself is straightforward since the compiler compiles itself. The current build of the compiler in JavaScript is included in the repo as `skewc.js` and is used by `build.py`. Here are some useful commands (see `Makefile` for a complete list):
* `./build.py`: Build the compiler into `out/browser.js` which can be tested using `www/index.html`
* `./build.py check`: Run various sanity checks including compiling the compiler with itself a few times
* `./build.py test`: Run all tests using all supported language targets
* `./build.py replace`: Replace the top-level `skewc.js` file with a newer version of itself
The core of the compiler is the `compile` method in `src/middle/compiler.sk` and is a good place to start reading for an overview of the compilation process.
## Lexing
The lexer is split into two files, `src/frontend/token.sk` and `src/frontend/lexer.sk`. It started off as a hand-written lexer but now uses [flex](http://flex.sourceforge.net/) for speed. The `src/frontend/build.py` script takes `src/frontend/flex.l` and generates `lexer.sk` by running flex and extracting the embedded magic constants and lookup tables from its output. Use `./build.py flex` to do this from the root directory. The generated lexer source code is checked in because it changes infrequently and because it avoids requiring flex as a dependency. The output of flex is awful for a number of reasons but it's really fast.
Lexing technically requires infinite lookahead due to the generic type syntax. Like C#, angle brackets are matched using syntactic structure alone without a symbol table. When a `<` token is encountered, it's only considered the start of a parameterization expression if there's a matching `>` ahead in the token stream and the tokens in between meet certain conditions. This lookahead may sound expensive, but it can be done efficiently without backtracking by storing information in a stack. This is done during the lexing pass in `token.sk` and means the lexer is still O(n). Using angle brackets for generics adds the additional complexity of needing to split tokens that start with a `>`. For example, the type `Foo<Bar<T>>` should end with two `>` tokens, not one `>>` token.
## Parsing
The hand-written parser uses recursive descent for statements and a Pratt parser for expressions. Pratt parsing support is in `src/frontend/pratt.sk` and the grammar implementation is in `src/frontend/parser.sk`. For a grammar overview, look at `createExpressionParser` for expressions and `parseStatement` for statements.
## Syntax Tree
Unlike many object-oriented syntax trees, this syntax tree just uses a single `Node` object, defined in `src/core/node.sk`. This makes syntax trees much easier to traverse and optimize. Tree traversal involves a single recursive function instead of a massive visitor object. Structure invariants are maintained by convention and runtime asserts instead of the type system. Primitive literal nodes use `Content` objects to store their constant values, defined in `src/core/content.sk`.
## Preprocessing
Before type checking begins, all parsed syntax trees are merged and preprocessed. Preprocessing is done using an order-independent, outside-in algorithm. A worklist is seeded with top-level preprocessor directives and preprocessing iterates until a fixed point is reached. Each iteration attempts to process top-level `if` directives and the constant variables they reference. Error reporting is delayed until the end since only then can unbound variables be classified as errors. Preprocessing should be pretty fast since it doesn't need to traverse into function definitions.
## Type Checking
Type checking starts by creating a symbol for each declaration, creating a scope for each block that needs one, and inserting each symbol into its enclosing scope. Each scope can both reference symbols on a type and store local symbols. For example, two adjacent namespace declarations with the same name have two separate scopes that both reference the same type.
Once all symbols and scopes are prepared, type checking is done using a single tree traversal. Type checking is made order-independent by applying it recursively. For example, resolving the body of a function may require resolving the type of a variable, which may require resolving its initializer, which may require resolving a constructor, which would then require resolving the enclosing type, which may require resolving base types, and so on:
def foo { bar.baz }
var bar = Bar.new
class Bar : Baz {}
class Baz { def baz {} }
To prevent cycles, symbol resolution is separated into an initialization phase and a resolution phase. The initialization phase resolves just enough to know the type of the symbol while the resolution phase fully resolves the symbol's contents. Using a symbol requires initializing it but not resolving it. Cycles are detected by giving each symbol three states: uninitialized, initializing, and initialized. Encountering an initializing symbol is an error. These rules ensure that `class Foo { var foo Foo }` is valid but `class Foo : Foo {}` is an error.
Limited type inference is performed using type context propagation. A type hint can optionally be provided during expression resolution and will be used to provide missing information if available. For example, type context from the variable type in `var foo List<double> = [0]` ensures that the list literal contains doubles instead of ints.
================================================
FILE: extras/Atom/README.md
================================================
# Atom Syntax Definitions for Skew
Run `apm install skew` to install syntax highlighting for the [Atom editor](https://atom.io). The package repository that it installs from is at https://github.com/evanw/skew-atom.
================================================
FILE: extras/Sublime Text/README.md
================================================
# Sublime Text Syntax Definitions for Skew
## Installing
To install, copy the "Skew" folder into the appropriate location for the given platform and version listed below.
[(more information about Sublime Text packages)](http://docs.sublimetext.info/en/latest/basic_concepts.html#the-packages-directory)
### OS X
_Sublime Text 2_
~/Library/Application Support/Sublime Text 2/Packages/
_Sublime Text 3_
~/Library/Application Support/Sublime Text 3/Packages/
### Windows
_Sublime Text 2_
%APPDATA%\Sublime Text 2\Packages
_Sublime Text 3_
%APPDATA%\Sublime Text 3\Packages
### Linux
_Sublime Text 2_
~/.Sublime Text 2/Packages
_Sublime Text 3_
~/.Sublime Text 3/Packages
================================================
FILE: extras/Sublime Text/Skew/Comments.tmPreferences
================================================
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>name</key>
<string>Comments</string>
<key>scope</key>
<string>source.skew</string>
<key>settings</key>
<dict>
<key>shellVariables</key>
<array>
<dict>
<key>name</key>
<string>TM_COMMENT_START</string>
<key>value</key>
<string># </string>
</dict>
</array>
</dict>
</dict>
</plist>
================================================
FILE: extras/Sublime Text/Skew/Skew.sublime-completions
================================================
{
"scope": "source.skew",
"completions": [
{ "trigger": "as", "contents": "as" },
{ "trigger": "break", "contents": "break" },
{ "trigger": "case", "contents": "case" },
{ "trigger": "catch", "contents": "catch" },
{ "trigger": "class", "contents": "class" },
{ "trigger": "const", "contents": "const" },
{ "trigger": "continue", "contents": "continue" },
{ "trigger": "def", "contents": "def" },
{ "trigger": "default", "contents": "default" },
{ "trigger": "dynamic", "contents": "dynamic" },
{ "trigger": "else", "contents": "else" },
{ "trigger": "enum", "contents": "enum" },
{ "trigger": "false", "contents": "false" },
{ "trigger": "finally", "contents": "finally" },
{ "trigger": "for", "contents": "for" },
{ "trigger": "if", "contents": "if" },
{ "trigger": "in", "contents": "in" },
{ "trigger": "interface", "contents": "interface" },
{ "trigger": "is", "contents": "is" },
{ "trigger": "namespace", "contents": "namespace" },
{ "trigger": "null", "contents": "null" },
{ "trigger": "over", "contents": "over" },
{ "trigger": "return", "contents": "return" },
{ "trigger": "super", "contents": "super" },
{ "trigger": "switch", "contents": "switch" },
{ "trigger": "throw", "contents": "throw" },
{ "trigger": "true", "contents": "true" },
{ "trigger": "try", "contents": "try" },
{ "trigger": "var", "contents": "var" },
{ "trigger": "while", "contents": "while" }
]
}
================================================
FILE: extras/Sublime Text/Skew/Skew.tmLanguage
================================================
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>fileTypes</key>
<array>
<string>sk</string>
</array>
<key>name</key>
<string>Skew</string>
<key>scopeName</key>
<string>source.skew</string>
<key>patterns</key>
<array>
<dict>
<key>match</key>
<string>#.*</string>
<key>name</key>
<string>comment.skew</string>
</dict>
<dict>
<key>match</key>
<string>\b(?:as|break|case|continue|default|else|finally|if|in|is|return|super|switch|throw|try|while)\b</string>
<key>name</key>
<string>keyword.skew</string>
</dict>
<dict>
<key>match</key>
<string>\b(?:[A-Z_][A-Z0-9_]+|null|true|false|self|0b[01]+(?:\.[01]+)?|0o[0-7]+(?:\.[0-7]+)?|0x[0-9A-Fa-f]+(?:\.[0-9A-Fa-f]+)?|[0-9]+(?:\.[0-9]+)?(?:e[+-]?[0-9]+)?f?)\b</string>
<key>name</key>
<string>constant.numeric.skew</string>
</dict>
<dict>
<key>match</key>
<string>@[A-Za-z_][A-Za-z0-9_]*\b</string>
<key>name</key>
<string>keyword.skew</string>
</dict>
<dict>
<key>match</key>
<string>\b(?:bool|double|dynamic|fn|int|string|[A-Z][A-Za-z0-9_]*(?:\.[A-Z][A-Za-z0-9_]*[a-z][A-Za-z0-9_]*)*)\b(?:<.*?>(?!>))?</string>
<key>name</key>
<string>storage.type.skew</string>
</dict>
<dict>
<key>match</key>
<string>\bdef\b(?:\s+([A-Za-z0-9_\-\+\*/%!^&|~=><\[\]\{\}\.]+))?</string>
<key>name</key>
<string>keyword.skew</string>
<key>captures</key>
<dict>
<key>1</key>
<dict>
<key>name</key>
<string>entity.name.function.skew</string>
</dict>
</dict>
</dict>
<dict>
<key>match</key>
<string>\b(?:catch|const|for|var)\b(?:\s+([A-Za-z0-9_\.]+))?</string>
<key>name</key>
<string>keyword.skew</string>
<key>captures</key>
<dict>
<key>1</key>
<dict>
<key>name</key>
<string>entity.name.function.skew</string>
</dict>
</dict>
</dict>
<dict>
<key>match</key>
<string>^\s*\b(?:class|def|enum|flags|interface|namespace|over|type)\b(?:\s+([A-Za-z0-9_\.]+))?</string>
<key>name</key>
<string>keyword.skew</string>
<key>captures</key>
<dict>
<key>1</key>
<dict>
<key>name</key>
<string>entity.name.function.skew</string>
</dict>
</dict>
</dict>
<dict>
<key>begin</key>
<string>'</string>
<key>end</key>
<string>'</string>
<key>name</key>
<string>string.quoted.single.skew</string>
<key>patterns</key>
<array>
<dict>
<key>match</key>
<string>\\.</string>
<key>name</key>
<string>constant.character.escape.skew</string>
</dict>
</array>
</dict>
<dict>
<key>begin</key>
<string>"</string>
<key>end</key>
<string>"</string>
<key>name</key>
<string>string.quoted.double.skew</string>
<key>patterns</key>
<array>
<dict>
<key>begin</key>
<string>\\\(</string>
<key>end</key>
<string>\)</string>
<key>name</key>
<string>string.interpolated.skew</string>
</dict>
<dict>
<key>match</key>
<string>\\.</string>
<key>name</key>
<string>constant.character.escape.skew</string>
</dict>
</array>
</dict>
</array>
</dict>
</plist>
================================================
FILE: npm/README
================================================
See [http://skew-lang.org](http://skew-lang.org) for more information.
================================================
FILE: npm/package.json
================================================
{
"name": "skew",
"version": "0.9.19",
"author": "Evan Wallace",
"description": "A compiler for the Skew programming language",
"license": "MIT",
"main": "skew.js",
"bin": {
"skewc": "skewc"
},
"types": "./skew.d.ts",
"repository": {
"type": "git",
"url": "https://github.com/evanw/skew"
}
}
================================================
FILE: package.json
================================================
{
"scripts": {
"test": "python build.py test_js"
}
}
================================================
FILE: skewc.js
================================================
(function() {
var __create = Object.create ? Object.create : function(prototype) {
return {'__proto__': prototype};
};
function __extends(derived, base) {
derived.prototype = __create(base.prototype);
derived.prototype.constructor = derived;
}
var __imul = Math.imul ? Math.imul : function(a, b) {
return (a * (b >>> 16) << 16) + a * (b & 65535) | 0;
};
function assert(truth) {
if (!truth) {
throw Error('Assertion failed');
}
}
var Target = {
CSHARP: 2,
JAVASCRIPT: 3
};
function StringBuilder() {
this.buffer = '';
}
function Box(value) {
this.value = value;
}
var Unicode = {};
Unicode.codeUnitCountForCodePoints = function(codePoints, encoding) {
var count = 0;
switch (encoding) {
case Unicode.Encoding.UTF8: {
for (var i = 0, list = codePoints, count1 = list.length; i < count1; i = i + 1 | 0) {
var codePoint = in_List.get(list, i);
if (codePoint < 128) {
count = count + 1 | 0;
}
else if (codePoint < 2048) {
count = count + 2 | 0;
}
else if (codePoint < 65536) {
count = count + 3 | 0;
}
else {
count = count + 4 | 0;
}
}
break;
}
case Unicode.Encoding.UTF16: {
for (var i1 = 0, list1 = codePoints, count2 = list1.length; i1 < count2; i1 = i1 + 1 | 0) {
var codePoint1 = in_List.get(list1, i1);
if (codePoint1 < 65536) {
count = count + 1 | 0;
}
else {
count = count + 2 | 0;
}
}
break;
}
case Unicode.Encoding.UTF32: {
count = codePoints.length;
break;
}
}
return count;
};
Unicode.Encoding = {
UTF8: 0,
UTF16: 1,
UTF32: 2
};
Unicode.StringIterator = function() {
this.value = '';
this.index = 0;
this.stop = 0;
};
Unicode.StringIterator.prototype.reset = function(text, start) {
this.value = text;
this.index = start;
this.stop = text.length;
return this;
};
Unicode.StringIterator.prototype.nextCodePoint = function() {
if (this.index >= this.stop) {
return -1;
}
var a = in_string.get1(this.value, (this.index = this.index + 1 | 0) + -1 | 0);
if ((a & 64512) != 55296) {
return a;
}
if (this.index >= this.stop) {
return -1;
}
var b = in_string.get1(this.value, (this.index = this.index + 1 | 0) + -1 | 0);
return ((a << 10) + b | 0) + ((65536 - (55296 << 10) | 0) - 56320 | 0) | 0;
};
/////////////////////////////////////////////////////////////////////////////////
//
// This is a generated file, all edits will be lost!
//
/////////////////////////////////////////////////////////////////////////////////
var Skew = {};
Skew.quoteString = function(text, style, octal) {
var count = text.length;
// Use whichever quote character is less frequent
if (style == Skew.QuoteStyle.SHORTEST) {
var singleQuotes = 0;
var doubleQuotes = 0;
for (var i = 0, count1 = count; i < count1; i = i + 1 | 0) {
var c = in_string.get1(text, i);
if (c == 34) {
doubleQuotes = doubleQuotes + 1 | 0;
}
else if (c == 39) {
singleQuotes = singleQuotes + 1 | 0;
}
}
style = singleQuotes <= doubleQuotes ? Skew.QuoteStyle.SINGLE : Skew.QuoteStyle.DOUBLE;
}
var builder = new StringBuilder();
var quoteString = style == Skew.QuoteStyle.SINGLE ? "'" : '"';
var quote = style == Skew.QuoteStyle.TYPESCRIPT_TEMPLATE ? 96 : style == Skew.QuoteStyle.SINGLE ? 39 : 34;
var escaped = '';
// Append long runs of unescaped characters using a single slice for speed
var start = 0;
if (style != Skew.QuoteStyle.TYPESCRIPT_TEMPLATE) {
builder.buffer += quoteString;
}
for (var i1 = 0, count2 = count; i1 < count2; i1 = i1 + 1 | 0) {
var c1 = in_string.get1(text, i1);
if (c1 == quote) {
escaped = '\\' + quoteString;
}
else if (c1 == 10) {
escaped = '\\n';
}
else if (c1 == 13) {
escaped = '\\r';
}
else if (c1 == 9) {
escaped = '\\t';
}
else if (c1 == 0) {
// Avoid issues around accidental octal encoding
var next = (i1 + 1 | 0) < count ? in_string.get1(text, i1 + 1 | 0) : 0;
escaped = octal == Skew.QuoteOctal.OCTAL_WORKAROUND && next >= 48 && next <= 57 ? '\\000' : '\\0';
}
else if (c1 == 92) {
escaped = '\\\\';
}
else if (c1 == 36 && style == Skew.QuoteStyle.TYPESCRIPT_TEMPLATE) {
escaped = '\\$';
}
else if (c1 < 32) {
escaped = '\\x' + in_string.get(Skew.HEX, c1 >> 4) + in_string.get(Skew.HEX, c1 & 15);
}
else {
continue;
}
builder.buffer += in_string.slice2(text, start, i1);
builder.buffer += escaped;
start = i1 + 1 | 0;
}
builder.buffer += in_string.slice2(text, start, count);
if (style != Skew.QuoteStyle.TYPESCRIPT_TEMPLATE) {
builder.buffer += quoteString;
}
return builder.buffer;
};
// A single base 64 digit can contain 6 bits of data. For the base 64 variable
// length quantities we use in the source map spec, the first bit is the sign,
// the next four bits are the actual value, and the 6th bit is the continuation
// bit. The continuation bit tells us whether there are more digits in this
// value following this digit.
//
// Continuation
// | Sign
// | |
// V V
// 101011
//
Skew.encodeVLQ = function(value) {
var vlq = value < 0 ? -value << 1 | 1 : value << 1;
var encoded = '';
while (true) {
var digit = vlq & 31;
vlq >>= 5;
// If there are still more digits in this value, we must make sure the
// continuation bit is marked
if (vlq != 0) {
digit |= 32;
}
encoded += in_string.get(Skew.BASE64, digit);
if (vlq == 0) {
break;
}
}
return encoded;
};
Skew.hashCombine = function(left, right) {
return left ^ ((right - 1640531527 | 0) + (left << 6) | 0) + (left >> 2);
};
Skew.splitPath = function(path) {
var slashIndex = Math.max(path.lastIndexOf('/'), path.lastIndexOf('\\'));
return slashIndex == -1 ? new Skew.SplitPath('.', path) : new Skew.SplitPath(in_string.slice2(path, 0, slashIndex), in_string.slice1(path, slashIndex + 1 | 0));
};
Skew.withUppercaseFirstLetter = function(text) {
return text == '' ? text : in_string.get(text, 0).toUpperCase() + in_string.slice1(text, 1);
};
Skew.indentIndex = function(text) {
var i = 0;
while (i < text.length && (in_string.get1(text, i) == 32 || in_string.get1(text, i) == 9)) {
i = i + 1 | 0;
}
return i;
};
Skew.indentOfLine = function(line) {
return in_string.slice2(line, 0, Skew.indentIndex(line));
};
Skew.lineWithoutIndent = function(line) {
return in_string.slice1(line, Skew.indentIndex(line));
};
Skew.bytesToString = function(bytes) {
var KB = 1 << 10;
var MB = 1 << 20;
var GB = 1 << 30;
if (bytes == 1) {
return '1 byte';
}
if (bytes < KB) {
return bytes.toString() + ' bytes';
}
if (bytes < MB) {
return (Math.round(bytes / KB * 10) / 10).toString() + 'kb';
}
if (bytes < GB) {
return (Math.round(bytes / MB * 10) / 10).toString() + 'mb';
}
return (Math.round(bytes / GB * 10) / 10).toString() + 'gb';
};
Skew.doubleToStringWithDot = function(value) {
// These cases are different for each language target and must be handled before this
assert(isFinite(value));
var text = value.toString();
// The C# implementation of double.ToString() uses an uppercase "E"
if (TARGET == Target.CSHARP) {
text = text.toLowerCase();
}
// "1" => "1.0"
// "1.5" => "1.5"
// "1e+100" => "1.0e+100"
// "1.5e+100" => "1.5e+100"
if (!(text.indexOf('.') != -1)) {
var e = text.indexOf('e');
if (e != -1) {
text = in_string.slice2(text, 0, e) + '.0' + in_string.slice1(text, e);
}
else {
text += '.0';
}
}
return text;
};
// The cost of changing the case of a letter is 0.5 instead of 1
Skew.caseAwareLevenshteinEditDistance = function(a, b) {
var an = a.length;
var bn = b.length;
var v0 = [];
var v1 = [];
for (var i = 0, count = bn + 1 | 0; i < count; i = i + 1 | 0) {
v0.push(i);
v1.push(i);
}
for (var i1 = 0, count3 = an; i1 < count3; i1 = i1 + 1 | 0) {
var ca = in_string.get1(a, i1);
in_List.set(v1, 0, i1 + 1 | 0);
for (var j = 0, count1 = bn; j < count1; j = j + 1 | 0) {
var cb = in_string.get1(b, j);
in_List.set(v1, j + 1 | 0, Math.min(in_List.get(v0, j) + (ca == cb ? 0 : Skew.toLowerCase(ca) == Skew.toLowerCase(cb) ? 0.5 : 1), Math.min(in_List.get(v1, j), in_List.get(v0, j + 1 | 0)) + 1));
}
for (var j1 = 0, count2 = bn + 1 | 0; j1 < count2; j1 = j1 + 1 | 0) {
in_List.set(v0, j1, in_List.get(v1, j1));
}
}
return in_List.get(v1, bn);
};
Skew.toLowerCase = function(c) {
return c >= 65 && c <= 90 ? (97 - 65 | 0) + c | 0 : c;
};
Skew.replaceSingleQuotesWithDoubleQuotes = function(text) {
assert(text.startsWith("'"));
assert(text.endsWith("'"));
var builder = new StringBuilder();
var start = 1;
var limit = text.length - 1 | 0;
builder.buffer += '"';
for (var i = start; i < limit; i = i + 1 | 0) {
var c = in_string.get1(text, i);
if (c == 34) {
builder.buffer += in_string.slice2(text, start, i);
builder.buffer += '\\"';
start = i + 1 | 0;
}
else if (c == 92) {
if (in_string.get1(text, i + 1 | 0) == 39) {
builder.buffer += in_string.slice2(text, start, i);
builder.buffer += "'";
start = i + 2 | 0;
}
i = i + 1 | 0;
}
}
builder.buffer += in_string.slice2(text, start, limit);
builder.buffer += '"';
return builder.buffer;
};
Skew.argumentCountForOperator = function(text) {
if (Skew.validArgumentCounts == null) {
Skew.validArgumentCounts = new Map();
for (var i = 0, list = Array.from(Skew.operatorInfo.values()), count = list.length; i < count; i = i + 1 | 0) {
var value = in_List.get(list, i);
in_StringMap.set(Skew.validArgumentCounts, value.text, value.validArgumentCounts);
}
in_StringMap.set(Skew.validArgumentCounts, '<>...</>', [1]);
in_StringMap.set(Skew.validArgumentCounts, '[...]', [1]);
in_StringMap.set(Skew.validArgumentCounts, '[new]', [0, 1]);
in_StringMap.set(Skew.validArgumentCounts, '{...}', [2]);
in_StringMap.set(Skew.validArgumentCounts, '{new}', [0, 2]);
}
return in_StringMap.get(Skew.validArgumentCounts, text, null);
};
Skew.skewcMain = function($arguments) {
var log = new Skew.Log();
var diagnosticLimit = 0;
var printDiagnostic = function(diagnostic) {
var terminalWidth = process.stdout.columns;
if (diagnosticLimit > 0 && log.diagnostics.length >= diagnosticLimit) {
return;
}
if (diagnostic.range != null) {
Skew.printWithColor(Terminal.Color.BOLD, diagnostic.range.locationString() + ': ');
}
switch (diagnostic.kind) {
case Skew.DiagnosticKind.WARNING: {
Skew.printWarning(diagnostic.text);
break;
}
case Skew.DiagnosticKind.ERROR: {
Skew.printError(diagnostic.text);
break;
}
}
if (diagnostic.range != null) {
var formatted = diagnostic.range.format(terminalWidth);
process.stdout.write(formatted.line + '\n');
Skew.printWithColor(Terminal.Color.GREEN, formatted.range + '\n');
}
if (diagnostic.noteRange != null) {
var formatted1 = diagnostic.noteRange.format(terminalWidth);
Skew.printWithColor(Terminal.Color.BOLD, diagnostic.noteRange.locationString() + ': ');
Skew.printNote(diagnostic.noteText);
process.stdout.write(formatted1.line + '\n');
Skew.printWithColor(Terminal.Color.GREEN, formatted1.range + '\n');
}
};
// Print diagnostics immediately when generated to improve perceived speed
log.appendCallback = printDiagnostic;
// Translate frontend flags to compiler options
var parser = new Skew.Options.Parser();
var options = Skew.parseOptions(log, parser, $arguments);
diagnosticLimit = parser.intForOption(Skew.Option.MESSAGE_LIMIT, Skew.DEFAULT_MESSAGE_LIMIT);
var fixAll = parser.boolForOption(Skew.Option.FIX_ALL, false);
var fixCount = 0;
// Optionally have the log transform warnings into errors
if (options != null) {
log.warningsAreErrors = options.warningsAreErrors;
}
// Suppress logging during fixes
if (fixAll) {
log = new Skew.Log();
}
// Iterate until fixed point when applying fixes
while (true) {
var inputs = [];
var inputRanges = [];
Skew.readSources(log, parser.normalArguments, inputs, inputRanges);
// Run the compilation
if (!log.hasErrors() && options != null) {
var result = Skew.compile(log, options, inputs);
// Write all outputs
if (!log.hasErrors()) {
for (var i = 0, list = result.outputs, count1 = list.length; i < count1; i = i + 1 | 0) {
var output = in_List.get(list, i);
if (output.name != null && !IO.writeFile(output.name, output.contents)) {
var outputFile = parser.rangeForOption(Skew.Option.OUTPUT_FILE);
var outputDirectory = parser.rangeForOption(Skew.Option.OUTPUT_DIRECTORY);
log.commandLineErrorUnwritableFile(outputFile != null ? outputFile : outputDirectory, output.name);
break;
}
}
// Print compilation statistics
if (!log.hasErrors()) {
Skew.printWithColor(Terminal.Color.GRAY, result.statistics(inputs, options.verbose ? Skew.StatisticsKind.LONG : Skew.StatisticsKind.SHORT) + '\n');
}
}
}
if (!fixAll) {
break;
}
// Attempt to automatically fix warnings and errors
var applyLog = new Skew.Log();
var count = Skew.applyFixes(log, applyLog, function(source) {
for (var i = 0, count2 = inputs.length; i < count2; i = i + 1 | 0) {
if (source.name == in_List.get(inputs, i).name) {
return in_List.get(inputRanges, i);
}
}
return parser.rangeForOption(Skew.Option.FIX_ALL);
});
fixCount = fixCount + count | 0;
log = applyLog;
if (count == 0 || applyLog.hasErrors()) {
break;
}
}
// Print diagnostics afterward when applying fixes since they aren't printed earlier
if (fixAll) {
for (var i1 = 0, list1 = log.diagnostics, count2 = list1.length; i1 < count2; i1 = i1 + 1 | 0) {
var diagnostic = in_List.get(list1, i1);
printDiagnostic(diagnostic);
}
process.stdout.write(fixCount.toString() + ' ' + (fixCount == 1 ? 'fix' : 'fixes') + ' applied' + '\n');
}
// Print any errors and warnings
Skew.printLogSummary(log, diagnosticLimit);
// Optionally report a failure if any warnings were found
if (options != null && options.warningsAreErrors) {
return log.hasErrors() || log.hasWarnings() ? 1 : 0;
}
else {
return log.hasErrors() ? 1 : 0;
}
};
Skew.printWithColor = function(color, text) {
Terminal.setColor(color);
process.stdout.write(text);
Terminal.setColor(Terminal.Color.DEFAULT);
};
Skew.printError = function(text) {
Skew.printWithColor(Terminal.Color.RED, 'error: ');
Skew.printWithColor(Terminal.Color.BOLD, text + '\n');
};
Skew.printNote = function(text) {
Skew.printWithColor(Terminal.Color.GRAY, 'note: ');
Skew.printWithColor(Terminal.Color.BOLD, text + '\n');
};
Skew.printWarning = function(text) {
Skew.printWithColor(Terminal.Color.MAGENTA, 'warning: ');
Skew.printWithColor(Terminal.Color.BOLD, text + '\n');
};
Skew.printUsage = function(parser) {
Skew.printWithColor(Terminal.Color.GREEN, '\nusage: ');
Skew.printWithColor(Terminal.Color.BOLD, 'skewc [flags] [inputs]\n');
process.stdout.write(parser.usageText(Math.min(process.stdout.columns, 80)));
};
Skew.printLogSummary = function(log, diagnosticLimit) {
var hasErrors = log.hasErrors();
var hasWarnings = log.hasWarnings();
var summary = '';
if (hasWarnings) {
summary += Skew.PrettyPrint.plural1(log.warningCount(), 'warning');
if (hasErrors) {
summary += ' and ';
}
}
if (hasErrors) {
summary += Skew.PrettyPrint.plural1(log.errorCount(), 'error');
}
if (hasWarnings || hasErrors) {
process.stdout.write(summary + ' generated');
if (log.wasWarningCount() > 0) {
process.stdout.write(' (warnings are being treated as errors due to "--warnings-are-errors")');
}
if (diagnosticLimit > 0 && log.diagnostics.length > diagnosticLimit) {
Skew.printWithColor(Terminal.Color.GRAY, ' (only showing ' + Skew.PrettyPrint.plural1(diagnosticLimit, 'message') + ', use "--message-limit=0" to see all)');
}
process.stdout.write('\n');
}
};
Skew.readSources = function(log, normalArguments, inputs, inputRanges) {
var visit = null;
visit = function(range, path, isExplicit) {
if (Skew.splitPath(path).entry.startsWith('.')) {
return;
}
// Directories
if (IO.isDirectory(path)) {
var entries = IO.readDirectory(path);
if (entries == null) {
log.commandLineErrorUnreadableFile(range, path);
}
for (var i = 0, list = entries, count = list.length; i < count; i = i + 1 | 0) {
var entry = in_List.get(list, i);
if (!entry.startsWith('.')) {
visit(range, path + '/' + entry, false);
}
}
}
// Files (ignore non-skew files that aren't explicitly specified)
else if (isExplicit || path.endsWith('.sk')) {
var contents = IO.readFile(path);
if (contents == null) {
log.commandLineErrorUnreadableFile(range, path);
}
else {
inputs.push(new Skew.Source(path, contents));
inputRanges.push(range);
}
}
};
// Recursively visit input directories
for (var i = 0, list = normalArguments, count = list.length; i < count; i = i + 1 | 0) {
var range = in_List.get(list, i);
visit(range, range.toString(), true);
}
};
Skew.parseOptions = function(log, parser, $arguments) {
// Configure the parser
parser.define(Skew.Options.Type.BOOL, Skew.Option.HELP, '--help', 'Prints this message.').aliases(['-help', '?', '-?', '-h', '-H', '/?', '/h', '/H']);
parser.define(Skew.Options.Type.STRING, Skew.Option.TARGET, '--target', 'Sets the target format. Valid targets are ' + Skew.joinKeys(Array.from(Skew.VALID_TARGETS.keys())) + '.');
parser.define(Skew.Options.Type.STRING, Skew.Option.OUTPUT_FILE, '--output-file', 'Combines all output into a single file. Mutually exclusive with --output-dir.');
parser.define(Skew.Options.Type.STRING, Skew.Option.OUTPUT_DIRECTORY, '--output-dir', 'Places all output files in the specified directory. Mutually exclusive with --output-file.');
parser.define(Skew.Options.Type.BOOL, Skew.Option.NO_OUTPUT, '--no-output', 'Stops after the type checking pass and does not generate any output.');
parser.define(Skew.Options.Type.BOOL, Skew.Option.RELEASE, '--release', 'Implies --js-mangle, --js-minify, --fold-constants, --inline-functions, --globalize-functions, and --define:RELEASE=true.');
parser.define(Skew.Options.Type.BOOL, Skew.Option.VERBOSE, '--verbose', 'Prints out information about the compilation.');
parser.define(Skew.Options.Type.BOOL, Skew.Option.VERSION, '--version', 'Prints the current compiler version (' + Skew.VERSION + ') and exits.');
parser.define(Skew.Options.Type.INT, Skew.Option.MESSAGE_LIMIT, '--message-limit', 'Sets the maximum number of messages to report. ' + ('Pass 0 to disable the message limit. The default is ' + Skew.DEFAULT_MESSAGE_LIMIT.toString() + '.'));
parser.define(Skew.Options.Type.STRING_LIST, Skew.Option.DEFINE, '--define', 'Override variable values at compile time.');
parser.define(Skew.Options.Type.BOOL, Skew.Option.JS_MANGLE, '--js-mangle', 'Transforms emitted JavaScript to be as small as possible. The "@export" annotation prevents renaming a symbol.');
parser.define(Skew.Options.Type.BOOL, Skew.Option.JS_MINIFY, '--js-minify', 'Remove whitespace when compiling to JavaScript.');
parser.define(Skew.Options.Type.BOOL, Skew.Option.JS_SOURCE_MAP, '--js-source-map', 'Generates a source map when targeting JavaScript. ' + 'The source map is saved with the ".map" extension in the same directory as the main output file.');
parser.define(Skew.Options.Type.BOOL, Skew.Option.FOLD_CONSTANTS, '--fold-constants', 'Evaluates constants at compile time and removes dead code inside functions.');
parser.define(Skew.Options.Type.BOOL, Skew.Option.INLINE_FUNCTIONS, '--inline-functions', 'Uses heuristics to automatically inline simple global functions.');
parser.define(Skew.Options.Type.BOOL, Skew.Option.GLOBALIZE_FUNCTIONS, '--globalize-functions', 'Convert instance functions to global functions for better inlining.');
parser.define(Skew.Options.Type.BOOL, Skew.Option.FIX_ALL, '--fix-all', 'Attempt to automatically fix as many errors and warnings as possible. ' + "THIS WILL WRITE OVER YOUR SOURCE CODE. Make sure you know what you're doing.");
parser.define(Skew.Options.Type.BOOL, Skew.Option.IGNORED_COMMENT_WARNING, '--ignored-comment-warning', "Warn when the compiler doesn't store a comment in the parse tree.");
parser.define(Skew.Options.Type.BOOL, Skew.Option.WARNINGS_ARE_ERRORS, '--warnings-are-errors', 'Turns warnings into errors.');
// Parse the command line arguments
parser.parse(log, $arguments);
if (log.hasErrors()) {
return null;
}
// Early-out when printing the usage text
if (parser.boolForOption(Skew.Option.HELP, $arguments.length == 0)) {
Skew.printUsage(parser);
return null;
}
// Early-out when printing the version
if (parser.boolForOption(Skew.Option.VERSION, false)) {
process.stdout.write(Skew.VERSION + '\n');
return null;
}
// Set up the options for the compiler
var options = new Skew.CompilerOptions();
var releaseFlag = parser.boolForOption(Skew.Option.RELEASE, false);
options.foldAllConstants = parser.boolForOption(Skew.Option.FOLD_CONSTANTS, releaseFlag);
options.globalizeAllFunctions = parser.boolForOption(Skew.Option.GLOBALIZE_FUNCTIONS, releaseFlag);
options.inlineAllFunctions = parser.boolForOption(Skew.Option.INLINE_FUNCTIONS, releaseFlag);
options.jsMangle = parser.boolForOption(Skew.Option.JS_MANGLE, releaseFlag);
options.jsMinify = parser.boolForOption(Skew.Option.JS_MINIFY, releaseFlag);
options.jsSourceMap = parser.boolForOption(Skew.Option.JS_SOURCE_MAP, false);
options.stopAfterResolve = parser.boolForOption(Skew.Option.NO_OUTPUT, false);
options.verbose = parser.boolForOption(Skew.Option.VERBOSE, false);
options.warnAboutIgnoredComments = parser.boolForOption(Skew.Option.IGNORED_COMMENT_WARNING, false);
options.warningsAreErrors = parser.boolForOption(Skew.Option.WARNINGS_ARE_ERRORS, false);
// Prepare the defines
if (releaseFlag) {
options.define('RELEASE', 'true');
}
for (var i = 0, list = parser.rangeListForOption(Skew.Option.DEFINE), count = list.length; i < count; i = i + 1 | 0) {
var range = in_List.get(list, i);
var name = range.toString();
var equals = name.indexOf('=');
if (equals < 0) {
log.commandLineErrorExpectedDefineValue(range, name);
continue;
}
in_StringMap.set(options.defines, in_string.slice2(name, 0, equals), new Skew.Define(range.fromStart(equals), range.fromEnd((name.length - equals | 0) - 1 | 0)));
}
// There must be at least one source file
var end = parser.source.contents.length;
var trailingSpace = new Skew.Range(parser.source, end - 1 | 0, end);
if (parser.normalArguments.length == 0 && !options.stopAfterResolve) {
log.commandLineErrorNoInputFiles(trailingSpace);
}
// Parse the output location
if (!options.stopAfterResolve) {
var outputFile = parser.rangeForOption(Skew.Option.OUTPUT_FILE);
var outputDirectory = parser.rangeForOption(Skew.Option.OUTPUT_DIRECTORY);
if (outputFile == null && outputDirectory == null) {
log.commandLineErrorMissingOutput(trailingSpace, '--output-file', '--output-dir');
}
else if (outputFile != null && outputDirectory != null) {
log.commandLineErrorDuplicateOutput(outputFile.start > outputDirectory.start ? outputFile : outputDirectory, '--output-file', '--output-dir');
}
else if (outputFile != null) {
options.outputFile = outputFile.toString();
}
else {
options.outputDirectory = outputDirectory.toString();
}
}
// Check the target format
var target = parser.rangeForOption(Skew.Option.TARGET);
if (target != null) {
options.target = Skew.parseEnum(log, 'target', Skew.VALID_TARGETS, target, null);
}
else if (!options.createTargetFromExtension()) {
log.commandLineErrorMissingTarget(trailingSpace);
}
return options;
};
Skew.applyFixes = function(log, applyLog, rangeForSource) {
var fixCount = 0;
// Collect diagnostics by source file
var map = new Map();
for (var i1 = 0, list = log.diagnostics, count = list.length; i1 < count; i1 = i1 + 1 | 0) {
var diagnostic = in_List.get(list, i1);
if (diagnostic.range != null && diagnostic.fixes != null && diagnostic.fixes.length == 1) {
var name = diagnostic.range.source.name;
var diagnostics = in_StringMap.get(map, name, null);
if (diagnostics == null) {
in_StringMap.set(map, name, diagnostics = []);
}
diagnostics.push(diagnostic);
}
}
// Apply for each source file
for (var i2 = 0, list1 = Array.from(map.values()), count2 = list1.length; i2 < count2; i2 = i2 + 1 | 0) {
var diagnostics1 = in_List.get(list1, i2);
var source = in_List.first(diagnostics1).range.source;
var contents = source.contents;
diagnostics1.sort(function(a, b) {
return in_int.compare(b.range.start, a.range.start);
});
// Apply fixes in reverse to avoid issues with changing offsets
var last = contents.length;
for (var i = 0, count1 = diagnostics1.length; i < count1; i = i + 1 | 0) {
var fix = in_List.first(in_List.get(diagnostics1, i).fixes);
// Typo correction isn't robust enough right now to fix automatically
if (fix.kind == Skew.FixKind.SYMBOL_TYPO || fix.range.end > last) {
continue;
}
contents = in_string.slice2(contents, 0, fix.range.start) + fix.replacement + in_string.slice1(contents, fix.range.end);
last = fix.range.start;
fixCount = fixCount + 1 | 0;
}
// Write over the source file in place
if (!IO.writeFile(source.name, contents)) {
applyLog.commandLineErrorUnwritableFile(rangeForSource(source), source.name);
}
}
return fixCount;
};
Skew.joinKeys = function(keys) {
keys.sort(Skew.SORT_STRINGS);
return Skew.PrettyPrint.joinQuoted(keys, 'and');
};
Skew.parseEnum = function(log, name, map, range, defaultValue) {
if (range != null) {
var key = range.toString();
if (map.has(key)) {
return in_StringMap.get1(map, key);
}
var keys = Array.from(map.keys());
// Sort so the order is deterministic
keys.sort(Skew.SORT_STRINGS);
log.commandLineErrorInvalidEnum(range, name, key, keys);
}
return defaultValue;
};
// This is the inner loop from "flex", an ancient lexer generator. The output
// of flex is pretty bad (obfuscated variable names and the opposite of modular
// code) but it's fast and somewhat standard for compiler design. The code below
// replaces a simple hand-coded lexer and offers much better performance.
Skew.tokenize = function(log, source) {
var comments = null;
var tokens = [];
var text = source.contents;
var count = text.length;
var previousKind = Skew.TokenKind.NULL;
var previousWasComment = false;
var stack = [];
// For backing up
var yy_last_accepting_state = 0;
var yy_last_accepting_cpos = 0;
// The current character pointer
var yy_cp = 0;
while (yy_cp < count) {
// Reset the NFA
var yy_current_state = 1;
// The pointer to the beginning of the token
var yy_bp = yy_cp;
var yy_act = Skew.TokenKind.ERROR;
// Special-case string interpolation
var c = in_string.get1(text, yy_cp);
var isStringInterpolation = c == 34;
if (c == 41) {
for (var i = stack.length - 1 | 0; i >= 0; i = i - 1 | 0) {
var kind = in_List.get(stack, i).kind;
if (kind == Skew.TokenKind.STRING_INTERPOLATION_START) {
isStringInterpolation = true;
}
else if (kind != Skew.TokenKind.LESS_THAN) {
break;
}
}
}
if (isStringInterpolation) {
var isExit = c == 41;
yy_cp = yy_cp + 1 | 0;
while (yy_cp < count) {
c = in_string.get1(text, (yy_cp = yy_cp + 1 | 0) + -1 | 0);
if (c == 34) {
yy_act = isExit ? Skew.TokenKind.STRING_INTERPOLATION_END : Skew.TokenKind.STRING;
break;
}
if (c == 92) {
if (yy_cp == count) {
break;
}
c = in_string.get1(text, (yy_cp = yy_cp + 1 | 0) + -1 | 0);
if (c == 40) {
yy_act = isExit ? Skew.TokenKind.STRING_INTERPOLATION_CONTINUE : Skew.TokenKind.STRING_INTERPOLATION_START;
break;
}
}
}
}
// Special-case XML literals
else if (c == 62 && !(stack.length == 0) && in_List.last(stack).kind == Skew.TokenKind.XML_START) {
yy_cp = yy_cp + 1 | 0;
yy_act = Skew.TokenKind.XML_END;
}
// Search for a match
else {
while (yy_current_state != Skew.YY_JAM_STATE) {
if (yy_cp >= count) {
// This prevents syntax errors from causing infinite loops
break;
}
c = in_string.get1(text, yy_cp);
// All of the interesting characters are ASCII
var index = c < 127 ? c : 127;
var yy_c = in_List.get(Skew.yy_ec, index);
if (in_List.get(Skew.yy_accept, yy_current_state) != Skew.TokenKind.YY_INVALID_ACTION) {
yy_last_accepting_state = yy_current_state;
yy_last_accepting_cpos = yy_cp;
}
while (in_List.get(Skew.yy_chk, in_List.get(Skew.yy_base, yy_current_state) + yy_c | 0) != yy_current_state) {
yy_current_state = in_List.get(Skew.yy_def, yy_current_state);
if (yy_current_state >= Skew.YY_ACCEPT_LENGTH) {
yy_c = in_List.get(Skew.yy_meta, yy_c);
}
}
yy_current_state = in_List.get(Skew.yy_nxt, in_List.get(Skew.yy_base, yy_current_state) + yy_c | 0);
yy_cp = yy_cp + 1 | 0;
}
// Find the action
yy_act = in_List.get(Skew.yy_accept, yy_current_state);
while (yy_act == Skew.TokenKind.YY_INVALID_ACTION) {
// Have to back up
yy_cp = yy_last_accepting_cpos;
yy_current_state = yy_last_accepting_state;
yy_act = in_List.get(Skew.yy_accept, yy_current_state);
}
// Ignore whitespace
if (yy_act == Skew.TokenKind.WHITESPACE) {
continue;
}
// Stop at the end of the file
if (yy_act == Skew.TokenKind.END_OF_FILE) {
break;
}
}
// Special-case XML literals
if (yy_act == Skew.TokenKind.LESS_THAN && !Skew.FORBID_XML_AFTER.has(previousKind)) {
yy_act = Skew.TokenKind.XML_START;
}
// This is the default action in flex, which is usually called ECHO
else if (yy_act == Skew.TokenKind.ERROR) {
var iterator = Unicode.StringIterator.INSTANCE.reset(text, yy_bp);
iterator.nextCodePoint();
var range = new Skew.Range(source, yy_bp, iterator.index);
log.syntaxErrorExtraData(range, range.toString());
break;
}
var token = new Skew.Token(new Skew.Range(source, yy_bp, yy_cp), yy_act, null);
// Have a nice error message for certain tokens
if (yy_act == Skew.TokenKind.COMMENT_ERROR) {
log.syntaxErrorSlashComment(token.range);
token.kind = Skew.TokenKind.COMMENT;
}
else if (yy_act == Skew.TokenKind.NOT_EQUAL_ERROR) {
log.syntaxErrorOperatorTypo(token.range, '!=');
token.kind = Skew.TokenKind.NOT_EQUAL;
}
else if (yy_act == Skew.TokenKind.EQUAL_ERROR) {
log.syntaxErrorOperatorTypo(token.range, '==');
token.kind = Skew.TokenKind.EQUAL;
}
// Tokens that start with a greater than may need to be split, potentially multiple times
var loop = true;
while (loop) {
var tokenStartsWithGreaterThan = in_string.get1(text, token.range.start) == 62;
var tokenKind = token.kind;
loop = false;
// Remove tokens from the stack if they aren't working out
while (!(stack.length == 0)) {
var top = in_List.last(stack);
var topKind = top.kind;
// Stop parsing a type if we find a token that no type expression uses
if (topKind == Skew.TokenKind.LESS_THAN && tokenKind != Skew.TokenKind.LESS_THAN && tokenKind != Skew.TokenKind.IDENTIFIER && tokenKind != Skew.TokenKind.COMMA && tokenKind != Skew.TokenKind.DYNAMIC && tokenKind != Skew.TokenKind.DOT && tokenKind != Skew.TokenKind.LEFT_PARENTHESIS && tokenKind != Skew.TokenKind.RIGHT_PARENTHESIS && !tokenStartsWithGreaterThan) {
in_List.removeLast(stack);
}
else {
break;
}
}
// Group open
if (tokenKind == Skew.TokenKind.LEFT_PARENTHESIS || tokenKind == Skew.TokenKind.LEFT_BRACE || tokenKind == Skew.TokenKind.LEFT_BRACKET || tokenKind == Skew.TokenKind.LESS_THAN || tokenKind == Skew.TokenKind.STRING_INTERPOLATION_START || tokenKind == Skew.TokenKind.XML_START) {
stack.push(token);
}
// Group close
else if (tokenKind == Skew.TokenKind.RIGHT_PARENTHESIS || tokenKind == Skew.TokenKind.RIGHT_BRACE || tokenKind == Skew.TokenKind.RIGHT_BRACKET || tokenKind == Skew.TokenKind.STRING_INTERPOLATION_END || tokenKind == Skew.TokenKind.XML_END || tokenStartsWithGreaterThan) {
// Search for a matching opposite token
while (!(stack.length == 0)) {
var top1 = in_List.last(stack);
var topKind1 = top1.kind;
// Don't match ">" that don't work since they are just operators
if (tokenStartsWithGreaterThan && topKind1 != Skew.TokenKind.LESS_THAN) {
break;
}
// Consume the current token
in_List.removeLast(stack);
// Stop if it's a match
if (tokenKind == Skew.TokenKind.RIGHT_PARENTHESIS && topKind1 == Skew.TokenKind.LEFT_PARENTHESIS || tokenKind == Skew.TokenKind.RIGHT_BRACKET && topKind1 == Skew.TokenKind.LEFT_BRACKET || tokenKind == Skew.TokenKind.RIGHT_BRACE && topKind1 == Skew.TokenKind.LEFT_BRACE || tokenKind == Skew.TokenKind.STRING_INTERPOLATION_END && topKind1 == Skew.TokenKind.STRING_INTERPOLATION_START) {
break;
}
// Special-case angle brackets matches and ignore tentative matches that didn't work out
if (topKind1 == Skew.TokenKind.LESS_THAN && tokenStartsWithGreaterThan) {
// Break apart operators that start with a closing angle bracket
if (tokenKind != Skew.TokenKind.GREATER_THAN) {
var start = token.range.start;
tokens.push(new Skew.Token(new Skew.Range(source, start, start + 1 | 0), Skew.TokenKind.PARAMETER_LIST_END, null));
token.range = new Skew.Range(source, start + 1 | 0, token.range.end);
token.kind = tokenKind == Skew.TokenKind.SHIFT_RIGHT ? Skew.TokenKind.GREATER_THAN : tokenKind == Skew.TokenKind.UNSIGNED_SHIFT_RIGHT ? Skew.TokenKind.SHIFT_RIGHT : tokenKind == Skew.TokenKind.GREATER_THAN_OR_EQUAL ? Skew.TokenKind.ASSIGN : tokenKind == Skew.TokenKind.ASSIGN_SHIFT_RIGHT ? Skew.TokenKind.GREATER_THAN_OR_EQUAL : tokenKind == Skew.TokenKind.ASSIGN_UNSIGNED_SHIFT_RIGHT ? Skew.TokenKind.ASSIGN_SHIFT_RIGHT : Skew.TokenKind.NULL;
assert(token.kind != Skew.TokenKind.NULL);
// Split this token again
loop = tokenKind != Skew.TokenKind.GREATER_THAN_OR_EQUAL;
}
else {
token.kind = Skew.TokenKind.PARAMETER_LIST_END;
}
// Convert the "<" into a bound for type parameter lists
top1.kind = Skew.TokenKind.PARAMETER_LIST_START;
// Stop the search since we found a match
break;
}
}
}
}
// Remove newlines based on the previous token to enable line continuations.
// Make sure to be conservative. We want to be like Python, not like
// JavaScript ASI! Anything that is at all ambiguous should be disallowed.
//
// Examples:
// - "var x = 0 \n .toString"
// - "var x = 0 # comment \n .toString"
// - "var x = 0 \n # comment \n .toString"
// - "var x = 0 \n ### \n multi-line comment \n ### \n return 0"
//
if (previousKind == Skew.TokenKind.NEWLINE && token.kind == Skew.TokenKind.NEWLINE) {
if (comments != null && !previousWasComment) {
in_List.last(comments).hasGapBelow = true;
}
previousWasComment = false;
continue;
}
else if (previousKind == Skew.TokenKind.NEWLINE && Skew.REMOVE_WHITESPACE_BEFORE.has(token.kind)) {
var last = in_List.takeLast(tokens);
if (last.comments != null) {
if (comments == null) {
comments = [];
}
in_List.append1(comments, last.comments);
}
}
// Attach comments to tokens instead of having comments be tokens
previousWasComment = token.kind == Skew.TokenKind.COMMENT;
if (previousWasComment) {
if (comments == null) {
comments = [];
}
if (comments.length == 0 || in_List.last(comments).hasGapBelow) {
comments.push(new Skew.Comment(token.range, [], false, false));
}
var range1 = token.range;
var line = in_string.slice2(source.contents, range1.start + 1 | 0, range1.end);
var hashes = 0;
for (var j = 0, count1 = line.length; j < count1; j = j + 1 | 0) {
if (in_string.get1(line, j) != 35) {
break;
}
hashes = hashes + 1 | 0;
}
if (hashes != 0) {
line = in_string.repeat('/', hashes) + in_string.slice1(line, hashes);
}
in_List.last(comments).lines.push(line);
continue;
}
previousKind = token.kind;
if (previousKind != Skew.TokenKind.NEWLINE) {
token.comments = comments;
comments = null;
}
// Capture trailing comments
if (!(tokens.length == 0) && comments != null && comments.length == 1 && in_List.first(comments).lines.length == 1 && !in_List.first(comments).hasGapBelow) {
in_List.first(comments).isTrailing = true;
token.comments = comments;
comments = null;
}
// Accumulate the token for this iteration
tokens.push(token);
}
// Every token stream ends in END_OF_FILE
tokens.push(new Skew.Token(new Skew.Range(source, yy_cp, yy_cp), Skew.TokenKind.END_OF_FILE, comments));
// Also return preprocessor token presence so the preprocessor can be avoided
return tokens;
};
// Remove all code that isn't reachable from the entry point or from an
// imported or exported symbol. This is called tree shaking here but is also
// known as dead code elimination. Tree shaking is perhaps a better name
// because this pass doesn't remove dead code inside functions.
Skew.shakingPass = function(global, entryPoint, mode) {
var graph = new Skew.UsageGraph(global, mode);
var symbols = [];
Skew.Shaking.collectExportedSymbols(global, symbols, entryPoint);
var usages = graph.usagesForSymbols(symbols);
if (usages != null) {
Skew.Shaking.removeUnusedSymbols(global, usages);
}
};
Skew.compile = function(log, options, inputs) {
inputs = inputs.slice();
options.target.includeSources(inputs);
options.target.editOptions(options);
inputs.unshift(new Skew.Source('<unicode>', Skew.UNICODE_LIBRARY));
inputs.unshift(new Skew.Source('<native>', Skew.NATIVE_LIBRARY));
var context = new Skew.PassContext(log, options, inputs);
var passTimers = [];
var totalTimer = new Skew.Timer();
totalTimer.start();
// Run all passes, stop compilation if there are errors after resolving (wait until then to make IDE mode better)
for (var i = 0, list = options.passes, count = list.length; i < count; i = i + 1 | 0) {
var pass = in_List.get(list, i);
if (context.isResolvePassComplete && log.hasErrors()) {
break;
}
if (pass.shouldRun()) {
var passTimer = new Skew.PassTimer(pass.kind());
passTimers.push(passTimer);
passTimer.timer.start();
pass.run(context);
passTimer.timer.stop();
context.verify();
}
}
totalTimer.stop();
return new Skew.CompilerResult(context.cache, context.global, context.outputs, passTimers, totalTimer);
};
Skew.SORT_STRINGS = function(a, b) {
return in_string.compare(a, b);
};
Skew.PassKind = {
EMITTING: 0,
LEXING: 1,
PARSING: 2,
RESOLVING: 3,
LAMBDA_CONVERSION: 4,
CALL_GRAPH: 5,
INLINING: 6,
FOLDING: 7,
MOTION: 8,
GLOBALIZING: 9,
MERGING: 10,
INTERFACE_REMOVAL: 11,
RENAMING: 12
};
Skew.EmitMode = {
ALWAYS_EMIT: 0,
SKIP_IF_EMPTY: 1
};
Skew.Emitter = function() {
this._sources = [];
this._prefix = new StringBuilder();
this._code = new StringBuilder();
this._indentAmount = ' ';
this._indent = '';
};
Skew.Emitter.prototype.sources = function() {
return this._sources;
};
Skew.Emitter.prototype._increaseIndent = function() {
this._indent += this._indentAmount;
};
Skew.Emitter.prototype._decreaseIndent = function() {
this._indent = in_string.slice1(this._indent, this._indentAmount.length);
};
Skew.Emitter.prototype._emit = function(text) {
this._code.buffer += text;
};
Skew.Emitter.prototype._emitPrefix = function(text) {
this._prefix.buffer += text;
};
Skew.Emitter.prototype._createSource = function(name, mode) {
var code = this._code.buffer;
if (mode == Skew.EmitMode.ALWAYS_EMIT || code != '') {
this._prefix.buffer += code;
this._sources.push(new Skew.Source(name, this._prefix.buffer));
}
this._prefix = new StringBuilder();
this._code = new StringBuilder();
};
Skew.Emitter.prototype._collectObjects = function(global) {
var objects = [];
this._findObjects(objects, global);
return objects;
};
Skew.Emitter.prototype._sortedObjects = function(global) {
var objects = this._collectObjects(global);
// Sort by inheritance and containment
for (var i = 0, count = objects.length; i < count; i = i + 1 | 0) {
var j = i;
// Select an object that comes before all other types
while (j < objects.length) {
var object = in_List.get(objects, j);
var k = i;
// Check to see if this comes before all other types
while (k < objects.length) {
if (j != k && Skew.Emitter._objectComesBefore(in_List.get(objects, k), object)) {
break;
}
k = k + 1 | 0;
}
if (k == objects.length) {
break;
}
j = j + 1 | 0;
}
// Swap the object into the correct order
if (j < objects.length) {
in_List.swap(objects, i, j);
}
}
return objects;
};
Skew.Emitter.prototype._markVirtualFunctions = function(symbol) {
for (var i = 0, list = symbol.objects, count = list.length; i < count; i = i + 1 | 0) {
var object = in_List.get(list, i);
this._markVirtualFunctions(object);
}
for (var i2 = 0, list2 = symbol.functions, count2 = list2.length; i2 < count2; i2 = i2 + 1 | 0) {
var $function = in_List.get(list2, i2);
if ($function.overridden != null) {
$function.overridden.flags |= Skew.SymbolFlags.IS_VIRTUAL;
$function.flags |= Skew.SymbolFlags.IS_VIRTUAL;
}
if ($function.implementations != null) {
for (var i1 = 0, list1 = $function.implementations, count1 = list1.length; i1 < count1; i1 = i1 + 1 | 0) {
var other = in_List.get(list1, i1);
other.flags |= Skew.SymbolFlags.IS_VIRTUAL;
$function.flags |= Skew.SymbolFlags.IS_VIRTUAL;
}
}
}
};
Skew.Emitter.prototype._findObjects = function(objects, object) {
objects.push(object);
for (var i = 0, list = object.objects, count = list.length; i < count; i = i + 1 | 0) {
var o = in_List.get(list, i);
this._findObjects(objects, o);
}
};
Skew.Emitter._isContainedBy = function(inner, outer) {
if (inner.parent == null) {
return false;
}
if (inner.parent == outer) {
return true;
}
return Skew.Emitter._isContainedBy(inner.parent.asObjectSymbol(), outer);
};
Skew.Emitter._objectComesBefore = function(before, after) {
return after.hasBaseClass(before) || after.hasInterface(before) || Skew.Emitter._isContainedBy(after, before) || after.forwardTo == before;
};
// These dump() functions are helpful for debugging syntax trees
Skew.LispTreeEmitter = function(_options) {
Skew.Emitter.call(this);
this._options = _options;
};
__extends(Skew.LispTreeEmitter, Skew.Emitter);
Skew.LispTreeEmitter.prototype.visit = function(global) {
this._visitObject(global);
this._emit('\n');
this._createSource(this._options.outputDirectory != null ? this._options.outputDirectory + '/compiled.lisp' : this._options.outputFile, Skew.EmitMode.ALWAYS_EMIT);
};
Skew.LispTreeEmitter.prototype._visitObject = function(symbol) {
this._emit('(' + this._mangleKind(in_List.get(Skew.in_SymbolKind._strings, symbol.kind)) + ' ' + Skew.quoteString(symbol.name, Skew.QuoteStyle.DOUBLE, Skew.QuoteOctal.OCTAL_WORKAROUND));
this._increaseIndent();
for (var i = 0, list = symbol.objects, count = list.length; i < count; i = i + 1 | 0) {
var object = in_List.get(list, i);
this._emit('\n' + this._indent);
this._visitObject(object);
}
for (var i1 = 0, list1 = symbol.functions, count1 = list1.length; i1 < count1; i1 = i1 + 1 | 0) {
var $function = in_List.get(list1, i1);
this._emit('\n' + this._indent);
this._visitFunction($function);
}
for (var i2 = 0, list2 = symbol.variables, count2 = list2.length; i2 < count2; i2 = i2 + 1 | 0) {
var variable = in_List.get(list2, i2);
this._emit('\n' + this._indent);
this._visitVariable(variable);
}
this._decreaseIndent();
this._emit(')');
};
Skew.LispTreeEmitter.prototype._visitFunction = function(symbol) {
this._emit('(' + this._mangleKind(in_List.get(Skew.in_SymbolKind._strings, symbol.kind)) + ' ' + Skew.quoteString(symbol.name, Skew.QuoteStyle.DOUBLE, Skew.QuoteOctal.OCTAL_WORKAROUND));
this._increaseIndent();
for (var i = 0, list = symbol.$arguments, count = list.length; i < count; i = i + 1 | 0) {
var argument = in_List.get(list, i);
this._emit('\n' + this._indent);
this._visitVariable(argument);
}
this._emit('\n' + this._indent);
this._visitNode(symbol.returnType);
this._emit('\n' + this._indent);
this._visitNode(symbol.block);
this._decreaseIndent();
this._emit(')');
};
Skew.LispTreeEmitter.prototype._visitVariable = function(symbol) {
this._emit('(' + this._mangleKind(in_List.get(Skew.in_SymbolKind._strings, symbol.kind)) + ' ' + Skew.quoteString(symbol.name, Skew.QuoteStyle.DOUBLE, Skew.QuoteOctal.OCTAL_WORKAROUND) + ' ');
this._visitNode(symbol.type);
this._emit(' ');
this._visitNode(symbol.value);
this._emit(')');
};
Skew.LispTreeEmitter.prototype._visitNode = function(node) {
if (node == null) {
this._emit('nil');
return;
}
this._emit('(' + this._mangleKind(in_List.get(Skew.in_NodeKind._strings, node.kind)));
var content = node.content;
if (content != null) {
switch (content.kind()) {
case Skew.ContentKind.INT: {
this._emit(' ' + Skew.in_Content.asInt(content).toString());
break;
}
case Skew.ContentKind.BOOL: {
this._emit(' ' + Skew.in_Content.asBool(content).toString());
break;
}
case Skew.ContentKind.DOUBLE: {
this._emit(' ' + Skew.in_Content.asDouble(content).toString());
break;
}
case Skew.ContentKind.STRING: {
this._emit(' ' + Skew.quoteString(Skew.in_Content.asString(content), Skew.QuoteStyle.DOUBLE, Skew.QuoteOctal.OCTAL_WORKAROUND));
break;
}
}
}
if (node.kind == Skew.NodeKind.VARIABLE) {
this._emit(' ');
this._visitVariable(node.symbol.asVariableSymbol());
}
else if (node.kind == Skew.NodeKind.LAMBDA) {
this._emit(' ');
this._visitFunction(node.symbol.asFunctionSymbol());
}
else if (node.hasChildren()) {
this._increaseIndent();
for (var child = node.firstChild(); child != null; child = child.nextSibling()) {
this._emit('\n' + this._indent);
this._visitNode(child);
}
this._decreaseIndent();
}
this._emit(')');
};
Skew.LispTreeEmitter.prototype._mangleKind = function(kind) {
return kind.toLowerCase().split('_').join('-');
};
Skew.CSharpEmitter = function(_options, _cache) {
Skew.Emitter.call(this);
this._options = _options;
this._cache = _cache;
this._previousNode = null;
this._previousSymbol = null;
this._namespaceStack = [];
this._symbolsCheckedForUsing = new Map();
this._usingNames = new Map();
this._loopLabels = new Map();
this._enclosingFunction = null;
};
__extends(Skew.CSharpEmitter, Skew.Emitter);
Skew.CSharpEmitter.prototype.visit = function(global) {
this._indentAmount = ' ';
this._moveGlobalsIntoClasses(global);
// Generate the entry point
var entryPoint = this._cache.entryPointSymbol;
if (entryPoint != null) {
entryPoint.name = 'Main';
// The entry point in C# takes an array, not a list
if (entryPoint.$arguments.length == 1) {
var argument = in_List.first(entryPoint.$arguments);
var array = new Skew.VariableSymbol(Skew.SymbolKind.VARIABLE_ARGUMENT, argument.name);
array.type = new Skew.Node(Skew.NodeKind.NAME).withContent(new Skew.StringContent('string[]')).withType(Skew.Type.DYNAMIC);
array.resolvedType = Skew.Type.DYNAMIC;
entryPoint.$arguments = [array];
entryPoint.resolvedType.argumentTypes = [array.resolvedType];
// Create the list from the array
if (entryPoint.block != null) {
array.name = entryPoint.scope.generateName(array.name);
argument.kind = Skew.SymbolKind.VARIABLE_LOCAL;
argument.value = Skew.Node.createCall(new Skew.Node(Skew.NodeKind.DOT).withContent(new Skew.StringContent('new')).appendChild(new Skew.Node(Skew.NodeKind.TYPE).withType(argument.resolvedType)).withType(Skew.Type.DYNAMIC)).withType(Skew.Type.DYNAMIC).appendChild(Skew.Node.createSymbolReference(array));
entryPoint.block.prependChild(new Skew.Node(Skew.NodeKind.VARIABLES).appendChild(Skew.Node.createVariable(argument)));
}
}
}
// Avoid emitting unnecessary stuff
Skew.shakingPass(global, entryPoint, Skew.ShakingMode.USE_TYPES);
this._markVirtualFunctions(global);
var emitIndividualFiles = this._options.outputDirectory != null;
var objects = this._collectObjects(global);
for (var i1 = 0, list1 = objects, count1 = list1.length; i1 < count1; i1 = i1 + 1 | 0) {
var object = in_List.get(list1, i1);
// Convert "flags" types to wrapped types
if (object.kind == Skew.SymbolKind.OBJECT_FLAGS) {
object.kind = Skew.SymbolKind.OBJECT_WRAPPED;
object.wrappedType = this._cache.intType;
// Enum values become normal global variables
for (var i = 0, list = object.variables, count = list.length; i < count; i = i + 1 | 0) {
var variable = in_List.get(list, i);
if (variable.kind == Skew.SymbolKind.VARIABLE_ENUM_OR_FLAGS) {
variable.kind = Skew.SymbolKind.VARIABLE_GLOBAL;
variable.flags |= Skew.SymbolFlags.IS_CSHARP_CONST;
}
}
}
}
// All code in C# is inside objects, so just emit objects recursively
for (var i2 = 0, list2 = objects, count2 = list2.length; i2 < count2; i2 = i2 + 1 | 0) {
var object1 = in_List.get(list2, i2);
// Nested objects will be emitted by their parent
if (object1.parent != null && object1.parent.kind == Skew.SymbolKind.OBJECT_CLASS) {
continue;
}
this._emitObject(object1);
// Emit each object into its own file if requested
if (emitIndividualFiles) {
this._finalizeEmittedFile();
this._createSource(this._options.outputDirectory + '/' + Skew.CSharpEmitter._fullName(object1) + '.cs', Skew.EmitMode.SKIP_IF_EMPTY);
}
}
// Emit a single file if requested
if (!emitIndividualFiles) {
this._finalizeEmittedFile();
this._createSource(this._options.outputFile, Skew.EmitMode.ALWAYS_EMIT);
}
};
Skew.CSharpEmitter.prototype._moveGlobalsIntoClasses = function(symbol) {
if (!Skew.in_SymbolKind.isNamespaceOrGlobal(symbol.kind)) {
return;
}
// Just change namespaces into classes if there aren't nested objects
if (symbol.kind == Skew.SymbolKind.OBJECT_NAMESPACE && symbol.objects.length == 0 && (!(symbol.functions.length == 0) || !(symbol.variables.length == 0))) {
symbol.kind = Skew.SymbolKind.OBJECT_CLASS;
return;
}
var globals = null;
var lazilyCreateGlobals = function() {
if (globals == null) {
globals = new Skew.ObjectSymbol(Skew.SymbolKind.OBJECT_CLASS, symbol.scope.generateName(symbol.kind == Skew.SymbolKind.OBJECT_NAMESPACE ? symbol.name + 'Globals' : 'Globals'));
globals.resolvedType = new Skew.Type(Skew.TypeKind.SYMBOL, globals);
globals.state = Skew.SymbolState.INITIALIZED;
globals.parent = symbol;
symbol.objects.push(globals);
}
};
for (var i = 0, list = symbol.objects, count = list.length; i < count; i = i + 1 | 0) {
var object = in_List.get(list, i);
this._moveGlobalsIntoClasses(object);
}
in_List.removeIf(symbol.functions, function($function) {
if ($function.kind != Skew.SymbolKind.FUNCTION_ANNOTATION && !$function.isImported()) {
lazilyCreateGlobals();
$function.parent = globals;
globals.functions.push($function);
return true;
}
return false;
});
in_List.removeIf(symbol.variables, function(variable) {
if (variable.kind == Skew.SymbolKind.VARIABLE_GLOBAL && !variable.isImported()) {
lazilyCreateGlobals();
variable.parent = globals;
globals.variables.push(variable);
return true;
}
return false;
});
};
Skew.CSharpEmitter.prototype._adjustNamespace = function(symbol) {
// Get the namespace chain for this symbol
var symbols = [];
while (symbol != null && symbol.kind != Skew.SymbolKind.OBJECT_GLOBAL) {
if (symbol.kind == Skew.SymbolKind.OBJECT_NAMESPACE) {
symbols.unshift(symbol);
}
symbol = symbol.parent;
}
// Find the intersection
var limit = Math.min(this._namespaceStack.length, symbols.length);
var i = 0;
while (i < limit) {
if (in_List.get(this._namespaceStack, i) != in_List.get(symbols, i)) {
break;
}
i = i + 1 | 0;
}
// Leave the old namespace
while (this._namespaceStack.length > i) {
var object = in_List.takeLast(this._namespaceStack);
this._decreaseIndent();
this._emit(this._indent + '}\n');
this._emitNewlineAfterSymbol(object);
}
// Enter the new namespace
while (this._namespaceStack.length < symbols.length) {
var object1 = in_List.get(symbols, this._namespaceStack.length);
this._emitNewlineBeforeSymbol(object1);
this._emit(this._indent + 'namespace ' + Skew.CSharpEmitter._mangleName(object1) + '\n');
this._emit(this._indent + '{\n');
this._increaseIndent();
this._namespaceStack.push(object1);
}
};
Skew.CSharpEmitter.prototype._finalizeEmittedFile = function() {
var usings = Array.from(this._usingNames.keys());
if (!(usings.length == 0)) {
// Sort so the order is deterministic
usings.sort(Skew.SORT_STRINGS);
for (var i = 0, list = usings, count = list.length; i < count; i = i + 1 | 0) {
var using = in_List.get(list, i);
this._emitPrefix('using ' + using + ';\n');
}
this._emitPrefix('\n');
}
this._adjustNamespace(null);
this._previousSymbol = null;
this._symbolsCheckedForUsing = new Map();
this._usingNames = new Map();
};
Skew.CSharpEmitter.prototype._handleSymbol = function(symbol) {
if (!Skew.in_SymbolKind.isLocal(symbol.kind) && !this._symbolsCheckedForUsing.has(symbol.id)) {
in_IntMap.set(this._symbolsCheckedForUsing, symbol.id, 0);
if (symbol.annotations != null) {
for (var i = 0, list = symbol.annotations, count = list.length; i < count; i = i + 1 | 0) {
var annotation = in_List.get(list, i);
if (annotation.symbol != null && annotation.symbol.fullName() == 'using') {
var value = annotation.annotationValue();
if (value.childCount() == 2) {
in_StringMap.set(this._usingNames, value.lastChild().asString(), 0);
}
}
}
}
if (symbol.parent != null) {
this._handleSymbol(symbol.parent);
}
}
};
Skew.CSharpEmitter.prototype._emitNewlineBeforeSymbol = function(symbol) {
if (this._previousSymbol != null && (!Skew.in_SymbolKind.isVariable(this._previousSymbol.kind) || !Skew.in_SymbolKind.isVariable(symbol.kind) || symbol.comments != null)) {
this._emit('\n');
}
this._previousSymbol = null;
};
Skew.CSharpEmitter.prototype._emitNewlineAfterSymbol = function(symbol) {
this._previousSymbol = symbol;
};
Skew.CSharpEmitter.prototype._emitNewlineBeforeStatement = function(node) {
if (this._previousNode != null && (node.comments != null || !Skew.CSharpEmitter._isCompactNodeKind(this._previousNode.kind) || !Skew.CSharpEmitter._isCompactNodeKind(node.kind))) {
this._emit('\n');
}
this._previousNode = null;
};
Skew.CSharpEmitter.prototype._emitNewlineAfterStatement = function(node) {
this._previousNode = node;
};
Skew.CSharpEmitter.prototype._emitComments = function(comments) {
if (comments != null) {
for (var i1 = 0, list1 = comments, count1 = list1.length; i1 < count1; i1 = i1 + 1 | 0) {
var comment = in_List.get(list1, i1);
for (var i = 0, list = comment.lines, count = list.length; i < count; i = i + 1 | 0) {
var line = in_List.get(list, i);
this._emit(this._indent + '//' + line + '\n');
}
if (comment.hasGapBelow) {
this._emit('\n');
}
}
}
};
Skew.CSharpEmitter.prototype._emitObject = function(symbol) {
this._handleSymbol(symbol);
if (symbol.isImported() || Skew.in_SymbolKind.isNamespaceOrGlobal(symbol.kind)) {
return;
}
this._adjustNamespace(symbol);
this._emitNewlineBeforeSymbol(symbol);
this._emitComments(symbol.comments);
this._emit(this._indent + 'public ');
if (symbol.isAbstract()) {
this._emit('abstract ');
}
switch (symbol.kind) {
case Skew.SymbolKind.OBJECT_CLASS: {
this._emit('class ');
break;
}
case Skew.SymbolKind.OBJECT_ENUM:
case Skew.SymbolKind.OBJECT_FLAGS: {
this._emit('enum ');
break;
}
case Skew.SymbolKind.OBJECT_INTERFACE: {
this._emit('interface ');
break;
}
case Skew.SymbolKind.OBJECT_WRAPPED:
case Skew.SymbolKind.OBJECT_NAMESPACE: {
this._emit('static class ');
break;
}
default: {
assert(false);
break;
}
}
this._emit(Skew.CSharpEmitter._mangleName(symbol));
this._emitTypeParameters(symbol.parameters);
if ((symbol.$extends != null || symbol.$implements != null) && symbol.kind != Skew.SymbolKind.OBJECT_WRAPPED) {
this._emit(' : ');
if (symbol.$extends != null) {
this._emitExpressionOrType(symbol.$extends, symbol.baseType);
}
if (symbol.$implements != null) {
for (var i = 0, list = symbol.$implements, count = list.length; i < count; i = i + 1 | 0) {
var node = in_List.get(list, i);
if (node != in_List.first(symbol.$implements) || symbol.$extends != null) {
this._emit(', ');
}
this._emitExpressionOrType(node, node.resolvedType);
}
}
}
this._emit('\n' + this._indent + '{\n');
this._increaseIndent();
for (var i1 = 0, list1 = symbol.objects, count1 = list1.length; i1 < count1; i1 = i1 + 1 | 0) {
var object = in_List.get(list1, i1);
this._emitObject(object);
}
for (var i2 = 0, list2 = symbol.variables, count2 = list2.length; i2 < count2; i2 = i2 + 1 | 0) {
var variable = in_List.get(list2, i2);
this._emitVariable(variable);
}
for (var i3 = 0, list3 = symbol.functions, count3 = list3.length; i3 < count3; i3 = i3 + 1 | 0) {
var $function = in_List.get(list3, i3);
this._emitFunction($function);
}
this._decreaseIndent();
this._emit(this._indent + '}\n');
this._emitNewlineAfterSymbol(symbol);
};
Skew.CSharpEmitter.prototype._emitTypeParameters = function(parameters) {
if (parameters != null) {
this._emit('<');
for (var i = 0, list = parameters, count = list.length; i < count; i = i + 1 | 0) {
var parameter = in_List.get(list, i);
if (parameter != in_List.first(parameters)) {
this._emit(', ');
}
this._emit(Skew.CSharpEmitter._mangleName(parameter));
}
this._emit('>');
}
};
Skew.CSharpEmitter.prototype._emitArgumentList = function(symbol) {
this._emit('(');
for (var i = 0, list = symbol.$arguments, count = list.length; i < count; i = i + 1 | 0) {
var argument = in_List.get(list, i);
if (argument != in_List.first(symbol.$arguments)) {
this._emit(', ');
}
this._emitExpressionOrType(argument.type, argument.resolvedType);
this._emit(' ' + Skew.CSharpEmitter._mangleName(argument));
}
this._emit(')');
};
Skew.CSharpEmitter.prototype._emitVariable = function(symbol) {
this._handleSymbol(symbol);
if (symbol.isImported()) {
return;
}
this._emitNewlineBeforeSymbol(symbol);
this._emitComments(symbol.comments);
if (symbol.kind == Skew.SymbolKind.VARIABLE_ENUM_OR_FLAGS) {
this._emit(this._indent + Skew.CSharpEmitter._mangleName(symbol));
if (symbol.value != null) {
// Enum values are initialized with integers
symbol.value.resolvedType = this._cache.intType;
this._emit(' = ');
this._emitExpression(symbol.value, Skew.Precedence.COMMA);
}
this._emit(',\n');
}
else {
this._emit(this._indent + 'public ');
if (symbol.kind == Skew.SymbolKind.VARIABLE_GLOBAL) {
this._emit(symbol.isCSharpConst() ? 'const ' : 'static ');
}
this._emitExpressionOrType(symbol.type, symbol.resolvedType);
this._emit(' ' + Skew.CSharpEmitter._mangleName(symbol));
if (symbol.value != null) {
this._emit(' = ');
this._emitExpression(symbol.value, Skew.Precedence.COMMA);
}
this._emit(';\n');
}
this._emitNewlineAfterSymbol(symbol);
};
Skew.CSharpEmitter.prototype._emitFunction = function(symbol) {
this._handleSymbol(symbol);
if (symbol.isImported()) {
return;
}
// C# has sane capture rules for "this" so no variable insertion is needed
if (symbol.$this != null) {
symbol.$this.name = 'this';
symbol.$this.flags |= Skew.SymbolFlags.IS_EXPORTED;
}
this._enclosingFunction = symbol;
this._emitNewlineBeforeSymbol(symbol);
this._emitComments(symbol.comments);
this._emit(this._indent);
if (symbol.parent.kind != Skew.SymbolKind.OBJECT_INTERFACE) {
this._emit('public ');
}
if (symbol.kind == Skew.SymbolKind.FUNCTION_GLOBAL) {
this._emit('static ');
}
if (symbol.kind != Skew.SymbolKind.FUNCTION_CONSTRUCTOR) {
if (symbol.parent.kind != Skew.SymbolKind.OBJECT_INTERFACE) {
if (symbol.block == null) {
this._emit('abstract ');
}
else if (symbol.overridden != null) {
this._emit('override ');
}
else if (symbol.isVirtual()) {
this._emit('virtual ');
}
}
this._emitExpressionOrType(symbol.returnType, symbol.resolvedType.returnType);
this._emit(' ');
}
this._emit(Skew.CSharpEmitter._mangleName(symbol));
this._emitTypeParameters(symbol.parameters);
this._emitArgumentList(symbol);
var block = symbol.block;
if (block == null) {
this._emit(';\n');
}
else {
// Move the super constructor call out of the function body
if (symbol.kind == Skew.SymbolKind.FUNCTION_CONSTRUCTOR && block.hasChildren()) {
var first = block.firstChild();
if (first.kind == Skew.NodeKind.EXPRESSION) {
var call = first.expressionValue();
if (call.kind == Skew.NodeKind.CALL && call.callValue().kind == Skew.NodeKind.SUPER) {
this._emit(' : ');
first.remove();
this._emitExpression(call, Skew.Precedence.LOWEST);
}
}
}
this._emit('\n');
this._emitBlock(block);
this._emit('\n');
}
this._emitNewlineAfterSymbol(symbol);
this._enclosingFunction = null;
};
Skew.CSharpEmitter.prototype._emitType = function(type) {
if (type == null) {
this._emit('void');
return;
}
type = this._cache.unwrappedType(type);
if (type == Skew.Type.DYNAMIC) {
this._emit('dynamic');
}
else if (type.kind == Skew.TypeKind.LAMBDA) {
var argumentTypes = type.argumentTypes;
var returnType = type.returnType;
this._emit(returnType != null ? 'System.Func' : 'System.Action');
if (!(argumentTypes.length == 0) || returnType != null) {
this._emit('<');
for (var i = 0, count = argumentTypes.length; i < count; i = i + 1 | 0) {
if (i != 0) {
this._emit(', ');
}
this._emitType(in_List.get(argumentTypes, i));
}
if (returnType != null) {
if (!(argumentTypes.length == 0)) {
this._emit(', ');
}
this._emitType(returnType);
}
this._emit('>');
}
}
else {
assert(type.kind == Skew.TypeKind.SYMBOL);
this._handleSymbol(type.symbol);
this._emit(Skew.CSharpEmitter._fullName(type.symbol));
if (type.isParameterized()) {
this._emit('<');
if (this._cache.isIntMap(type) || this._cache.isStringMap(type)) {
this._emit(this._cache.isIntMap(type) ? 'int' : 'string');
this._emit(', ');
this._emitType(in_List.first(type.substitutions));
}
else {
for (var i1 = 0, count1 = type.substitutions.length; i1 < count1; i1 = i1 + 1 | 0) {
if (i1 != 0) {
this._emit(', ');
}
this._emitType(in_List.get(type.substitutions, i1));
}
}
this._emit('>');
}
}
};
Skew.CSharpEmitter.prototype._emitExpressionOrType = function(node, type) {
if (node != null && (type == null || type == Skew.Type.DYNAMIC)) {
this._emitExpression(node, Skew.Precedence.LOWEST);
}
else {
this._emitType(type);
}
};
Skew.CSharpEmitter.prototype._emitStatements = function(node) {
this._previousNode = null;
for (var child = node.firstChild(); child != null; child = child.nextSibling()) {
this._emitNewlineBeforeStatement(child);
this._emitComments(child.comments);
this._emitStatement(child);
this._emitNewlineAfterStatement(child);
}
this._previousNode = null;
};
Skew.CSharpEmitter.prototype._emitBlock = function(node) {
assert(node.kind == Skew.NodeKind.BLOCK);
this._emit(this._indent + '{\n');
this._increaseIndent();
this._emitStatements(node);
this._decreaseIndent();
this._emit(this._indent + '}');
};
Skew.CSharpEmitter.prototype._emitIf = function(node) {
this._emit('if (');
this._emitExpression(node.ifTest(), Skew.Precedence.LOWEST);
this._emit(')\n');
this._emitBlock(node.ifTrue());
this._emit('\n');
var block = node.ifFalse();
if (block != null) {
var singleIf = block.hasOneChild() && block.firstChild().kind == Skew.NodeKind.IF ? block.firstChild() : null;
if (block.comments != null || singleIf != null && singleIf.comments != null) {
this._emit('\n');
this._emitComments(block.comments);
if (singleIf != null) {
this._emitComments(singleIf.comments);
}
}
this._emit(this._indent + 'else');
if (singleIf != null) {
this._emit(' ');
this._emitIf(singleIf);
}
else {
this._emit('\n');
this._emitBlock(block);
this._emit('\n');
}
}
};
Skew.CSharpEmitter.prototype._scanForSwitchBreak = function(node, loop) {
if (node.kind == Skew.NodeKind.BREAK) {
for (var parent = node.parent(); parent != loop; parent = parent.parent()) {
if (parent.kind == Skew.NodeKind.SWITCH) {
var label = in_IntMap.get(this._loopLabels, loop.id, null);
if (label == null) {
label = new Skew.VariableSymbol(Skew.SymbolKind.VARIABLE_LOCAL, this._enclosingFunction.scope.generateName('label'));
in_IntMap.set(this._loopLabels, loop.id, label);
}
in_IntMap.set(this._loopLabels, node.id, label);
break;
}
}
}
// Stop at nested loops since those will be tested later
else if (node == loop || !Skew.in_NodeKind.isLoop(node.kind)) {
for (var child = node.firstChild(); child != null; child = child.nextSibling()) {
this._scanForSwitchBreak(child, loop);
}
}
};
Skew.CSharpEmitter.prototype._emitStatement = function(node) {
if (Skew.in_NodeKind.isLoop(node.kind)) {
this._scanForSwitchBreak(node, node);
}
switch (node.kind) {
case Skew.NodeKind.COMMENT_BLOCK: {
break;
}
case Skew.NodeKind.VARIABLES: {
for (var child = node.firstChild(); child != null; child = child.nextSibling()) {
var symbol = child.symbol.asVariableSymbol();
this._emit(this._indent);
this._emitExpressionOrType(symbol.type, symbol.resolvedType);
this._emit(' ' + Skew.CSharpEmitter._mangleName(symbol));
if (symbol.value != null) {
this._emit(' = ');
this._emitExpression(symbol.value, Skew.Precedence.ASSIGN);
}
this._emit(';\n');
}
break;
}
case Skew.NodeKind.EXPRESSION: {
this._emit(this._indent);
this._emitExpression(node.expressionValue(), Skew.Precedence.LOWEST);
this._emit(';\n');
break;
}
case Skew.NodeKind.BREAK: {
var label = in_IntMap.get(this._loopLabels, node.id, null);
if (label != null) {
this._emit(this._indent + 'goto ' + Skew.CSharpEmitter._mangleName(label) + ';\n');
}
else {
this._emit(this._indent + 'break;\n');
}
break;
}
case Skew.NodeKind.CONTINUE: {
this._emit(this._indent + 'continue;\n');
break;
}
case Skew.NodeKind.IF: {
this._emit(this._indent);
this._emitIf(node);
break;
}
case Skew.NodeKind.SWITCH: {
var switchValue = node.switchValue();
this._emit(this._indent + 'switch (');
this._emitExpression(switchValue, Skew.Precedence.LOWEST);
this._emit(')\n' + this._indent + '{\n');
this._increaseIndent();
for (var child1 = switchValue.nextSibling(); child1 != null; child1 = child1.nextSibling()) {
var block = child1.caseBlock();
if (child1.previousSibling() != switchValue) {
this._emit('\n');
}
if (child1.hasOneChild()) {
this._emit(this._indent + 'default:');
}
else {
for (var value = child1.firstChild(); value != block; value = value.nextSibling()) {
if (value.previousSibling() != null) {
this._emit('\n');
}
this._emit(this._indent + 'case ');
this._emitExpression(value, Skew.Precedence.LOWEST);
this._emit(':');
}
}
this._emit('\n' + this._indent + '{\n');
this._increaseIndent();
this._emitStatements(block);
if (block.hasControlFlowAtEnd()) {
this._emit(this._indent + 'break;\n');
}
this._decreaseIndent();
this._emit(this._indent + '}\n');
}
this._decreaseIndent();
this._emit(this._indent + '}\n');
break;
}
case Skew.NodeKind.RETURN: {
this._emit(this._indent + 'return');
var value1 = node.returnValue();
if (value1 != null) {
this._emit(' ');
this._emitExpression(value1, Skew.Precedence.LOWEST);
}
this._emit(';\n');
break;
}
case Skew.NodeKind.THROW: {
this._emit(this._indent + 'throw ');
this._emitExpression(node.throwValue(), Skew.Precedence.LOWEST);
this._emit(';\n');
break;
}
case Skew.NodeKind.FOREACH: {
this._emit(this._indent + 'foreach (var ' + Skew.CSharpEmitter._mangleName(node.symbol) + ' in ');
this._emitExpression(node.foreachValue(), Skew.Precedence.LOWEST);
this._emit(')\n');
this._emitBlock(node.foreachBlock());
this._emit('\n');
break;
}
case Skew.NodeKind.FOR: {
var setup = node.forSetup();
var test = node.forTest();
var update = node.forUpdate();
this._emit(this._indent + 'for (');
if (!setup.isEmptySequence()) {
if (setup.kind == Skew.NodeKind.VARIABLES) {
var symbol1 = setup.firstChild().symbol.asVariableSymbol();
this._emitExpressionOrType(symbol1.type, symbol1.resolvedType);
this._emit(' ');
for (var child2 = setup.firstChild(); child2 != null; child2 = child2.nextSibling()) {
symbol1 = child2.symbol.asVariableSymbol();
assert(child2.kind == Skew.NodeKind.VARIABLE);
if (child2.previousSibling() != null) {
this._emit(', ');
}
this._emit(Skew.CSharpEmitter._mangleName(symbol1) + ' = ');
this._emitExpression(symbol1.value, Skew.Precedence.COMMA);
}
}
else {
this._emitExpression(setup, Skew.Precedence.LOWEST);
}
}
this._emit('; ');
if (!test.isEmptySequence()) {
this._emitExpression(test, Skew.Precedence.LOWEST);
}
this._emit('; ');
if (!update.isEmptySequence()) {
this._emitExpression(update, Skew.Precedence.LOWEST);
}
this._emit(')\n');
this._emitBlock(node.forBlock());
this._emit('\n');
break;
}
case Skew.NodeKind.TRY: {
var tryBlock = node.tryBlock();
var finallyBlock = node.finallyBlock();
this._emit(this._indent + 'try\n');
this._emitBlock(tryBlock);
this._emit('\n');
for (var child3 = tryBlock.nextSibling(); child3 != finallyBlock; child3 = child3.nextSibling()) {
if (child3.comments != null) {
this._emit('\n');
this._emitComments(child3.comments);
}
this._emit(this._indent + 'catch');
if (child3.symbol != null) {
this._emit(' (');
this._emitExpressionOrType(child3.symbol.asVariableSymbol().type, child3.symbol.resolvedType);
this._emit(' ' + Skew.CSharpEmitter._mangleName(child3.symbol) + ')');
}
this._emit('\n');
this._emitBlock(child3.catchBlock());
this._emit('\n');
}
if (finallyBlock != null) {
if (finallyBlock.comments != null) {
this._emit('\n');
this._emitComments(finallyBlock.comments);
}
this._emit(this._indent + 'finally\n');
this._emitBlock(finallyBlock);
this._emit('\n');
}
break;
}
case Skew.NodeKind.WHILE: {
this._emit(this._indent + 'while (');
this._emitExpression(node.whileTest(), Skew.Precedence.LOWEST);
this._emit(')\n');
this._emitBlock(node.whileBlock());
this._emit('\n');
break;
}
default: {
assert(false);
break;
}
}
if (Skew.in_NodeKind.isLoop(node.kind)) {
var label1 = in_IntMap.get(this._loopLabels, node.id, null);
if (label1 != null) {
this._emit(this._indent + Skew.CSharpEmitter._mangleName(label1) + (node.nextSibling() != null ? ':\n' : ':;\n'));
}
}
};
Skew.CSharpEmitter.prototype._emitContent = function(content) {
switch (content.kind()) {
case Skew.ContentKind.BOOL: {
this._emit(Skew.in_Content.asBool(content).toString());
break;
}
case Skew.ContentKind.INT: {
this._emit(Skew.in_Content.asInt(content).toString());
break;
}
case Skew.ContentKind.DOUBLE: {
var value = Skew.in_Content.asDouble(content);
if (!isFinite(value)) {
in_StringMap.set(this._usingNames, 'System', 0);
}
this._emit(isNaN(value) ? 'Double.NaN' : value == 1 / 0 ? 'Double.PositiveInfinity' : value == -(1 / 0) ? 'Double.NegativeInfinity' : Skew.doubleToStringWithDot(value));
break;
}
case Skew.ContentKind.STRING: {
this._emit(Skew.quoteString(Skew.in_Content.asString(content), Skew.QuoteStyle.DOUBLE, Skew.QuoteOctal.NORMAL));
break;
}
}
};
Skew.CSharpEmitter.prototype._emitCommaSeparatedExpressions = function(from, to) {
while (from != to) {
this._emitExpression(from, Skew.Precedence.COMMA);
from = from.nextSibling();
if (from != to) {
this._emit(', ');
}
}
};
Skew.CSharpEmitter.prototype._emitExpression = function(node, precedence) {
var kind = node.kind;
var symbol = node.symbol;
if (symbol != null) {
this._handleSymbol(symbol);
}
switch (kind) {
case Skew.NodeKind.TYPE:
case Skew.NodeKind.LAMBDA_TYPE: {
this._emitType(node.resolvedType);
break;
}
case Skew.NodeKind.NULL: {
this._emit('null');
break;
}
case Skew.NodeKind.NAME: {
this._emit(symbol != null ? Skew.CSharpEmitter._fullName(symbol) : node.asString());
break;
}
case Skew.NodeKind.DOT: {
this._emitExpression(node.dotTarget(), Skew.Precedence.MEMBER);
this._emit('.' + (symbol != null ? Skew.CSharpEmitter._mangleName(symbol) : node.asString()));
break;
}
case Skew.NodeKind.CONSTANT: {
var wrap = precedence == Skew.Precedence.MEMBER && node.isNumberLessThanZero() && (!node.isDouble() || isFinite(node.asDouble()));
if (wrap) {
this._emit('(');
}
if (node.resolvedType.isEnumOrFlags()) {
this._emit('(');
this._emitType(node.resolvedType);
this._emit(')');
}
this._emitContent(node.content);
if (wrap) {
this._emit(')');
}
break;
}
case Skew.NodeKind.CALL: {
var value = node.callValue();
var wrap1 = value.kind == Skew.NodeKind.LAMBDA;
if (wrap1) {
this._emit('new ');
this._emitType(value.resolvedType);
this._emit('(');
}
if (value.kind == Skew.NodeKind.SUPER) {
this._emit('base');
if (symbol.kind != Skew.SymbolKind.FUNCTION_CONSTRUCTOR) {
this._emit('.');
this._emit(Skew.CSharpEmitter._mangleName(symbol));
}
}
else if (symbol != null && symbol.kind == Skew.SymbolKind.FUNCTION_CONSTRUCTOR) {
this._emit('new ');
this._emitType(node.resolvedType);
}
else if (value.kind == Skew.NodeKind.DOT && value.asString() == 'new') {
this._emit('new ');
this._emitExpression(value.dotTarget(), Skew.Precedence.MEMBER);
}
else {
this._emitExpression(value, Skew.Precedence.UNARY_POSTFIX);
}
if (wrap1) {
this._emit(')');
}
this._emit('(');
this._emitCommaSeparatedExpressions(value.nextSibling(), null);
this._emit(')');
break;
}
case Skew.NodeKind.CAST: {
var resolvedType = node.resolvedType;
var type = node.castType();
var value1 = node.castValue();
if (type.kind == Skew.NodeKind.TYPE && type.resolvedType == Skew.Type.DYNAMIC) {
this._emitExpression(value1, precedence);
}
// Automatically promote integer literals to doubles instead of using a cast
else if (this._cache.isEquivalentToDouble(resolvedType) && value1.isInt()) {
this._emitExpression(this._cache.createDouble(value1.asInt()), precedence);
}
// C# doesn't have a cast from bool to int
else if (this._cache.isNumeric(resolvedType) && value1.resolvedType == this._cache.boolType) {
this._emitExpression(Skew.Node.createHook(value1.remove(), this._cache.createInt(1), this._cache.createInt(0)).withType(this._cache.intType), precedence);
}
// C# doesn't have a cast from int to bool
else if (resolvedType == this._cache.boolType && this._cache.isNumeric(value1.resolvedType)) {
this._emitExpression(Skew.Node.createBinary(Skew.NodeKind.NOT_EQUAL, value1.remove(), this._cache.createInt(0)).withType(this._cache.boolType), precedence);
}
// Only emit a cast if the underlying types are different
else if (this._cache.unwrappedType(value1.resolvedType) != this._cache.unwrappedType(type.resolvedType) || type.resolvedType == Skew.Type.DYNAMIC) {
if (Skew.Precedence.UNARY_POSTFIX < precedence) {
this._emit('(');
}
this._emit('(');
this._emitExpressionOrType(type, type.resolvedType);
this._emit(')');
this._emitExpression(value1, Skew.Precedence.UNARY_POSTFIX);
if (Skew.Precedence.UNARY_POSTFIX < precedence) {
this._emit(')');
}
}
// Otherwise, pretend the cast isn't there
else {
this._emitExpression(value1, precedence);
}
break;
}
case Skew.NodeKind.TYPE_CHECK: {
var value2 = node.typeCheckValue();
var type1 = node.typeCheckType();
if (Skew.Precedence.COMPARE < precedence) {
this._emit('(');
}
this._emitExpression(value2, Skew.Precedence.LOWEST);
this._emit(' is ');
this._emitExpressionOrType(type1, type1.resolvedType);
if (Skew.Precedence.COMPARE < precedence) {
this._emit(')');
}
break;
}
case Skew.NodeKind.INITIALIZER_LIST: {
this._emit('new ');
this._emitType(node.resolvedType);
if (node.hasChildren()) {
this._emit(' { ');
this._emitCommaSeparatedExpressions(node.firstChild(), null);
this._emit(' }');
}
else {
this._emit('()');
}
break;
}
case Skew.NodeKind.INDEX: {
this._emitExpression(node.indexLeft(), Skew.Precedence.UNARY_POSTFIX);
this._emit('[');
this._emitExpression(node.indexRight(), Skew.Precedence.LOWEST);
this._emit(']');
break;
}
case Skew.NodeKind.ASSIGN_INDEX: {
if (Skew.Precedence.ASSIGN < precedence) {
this._emit('(');
}
this._emitExpression(node.assignIndexLeft(), Skew.Precedence.UNARY_POSTFIX);
this._emit('[');
this._emitExpression(node.assignIndexCenter(), Skew.Precedence.LOWEST);
this._emit('] = ');
this._emitExpression(node.assignIndexRight(), Skew.Precedence.ASSIGN);
if (Skew.Precedence.ASSIGN < precedence) {
this._emit(')');
}
break;
}
case Skew.NodeKind.PARAMETERIZE: {
var value3 = node.parameterizeValue();
if (value3.isType()) {
this._emitType(node.resolvedType);
}
else {
this._emitExpression(value3, precedence);
this._emit('<');
this._emitCommaSeparatedExpressions(value3.nextSibling(), null);
this._emit('>');
}
break;
}
case Skew.NodeKind.SEQUENCE: {
if (Skew.Precedence.COMMA <= precedence) {
this._emit('(');
}
this._emitCommaSeparatedExpressions(node.firstChild(), null);
if (Skew.Precedence.COMMA <= precedence) {
this._emit(')');
}
break;
}
case Skew.NodeKind.HOOK: {
if (Skew.Precedence.ASSIGN < precedence) {
this._emit('(');
}
this._emitExpression(node.hookTest(), Skew.Precedence.LOGICAL_OR);
this._emit(' ? ');
this._emitExpression(node.hookTrue(), Skew.Precedence.ASSIGN);
this._emit(' : ');
this._emitExpression(node.hookFalse(), Skew.Precedence.ASSIGN);
if (Skew.Precedence.ASSIGN < precedence) {
this._emit(')');
}
break;
}
case Skew.NodeKind.LAMBDA: {
var oldEnclosingFunction = this._enclosingFunction;
this._enclosingFunction = symbol.asFunctionSymbol();
this._emitArgumentList(symbol.asFunctionSymbol());
this._emit(' =>\n');
this._emitBlock(symbol.asFunctionSymbol().block);
this._enclosingFunction = oldEnclosingFunction;
break;
}
case Skew.NodeKind.COMPLEMENT:
case Skew.NodeKind.NEGATIVE:
case Skew.NodeKind.NOT:
case Skew.NodeKind.POSITIVE:
case Skew.NodeKind.POSTFIX_DECREMENT:
case Skew.NodeKind.POSTFIX_INCREMENT:
case Skew.NodeKind.PREFIX_DECREMENT:
case Skew.NodeKind.PREFIX_INCREMENT: {
var value4 = node.unaryValue();
var info = in_IntMap.get1(Skew.operatorInfo, kind);
var sign = node.sign();
if (info.precedence < precedence) {
this._emit('(');
}
if (!Skew.in_NodeKind.isUnaryPostfix(kind)) {
this._emit(info.text);
// Prevent "x - -1" from becoming "x--1"
if (sign != Skew.NodeKind.NULL && sign == value4.sign()) {
this._emit(' ');
}
}
this._emitExpression(value4, info.precedence);
if (Skew.in_NodeKind.isUnaryPostfix(kind)) {
this._emit(info.text);
}
if (info.precedence < precedence) {
this._emit(')');
}
break;
}
default: {
if (Skew.in_NodeKind.isBinary(kind)) {
var left = node.binaryLeft();
var right = node.binaryRight();
// Some types stupidly don't implement operator "=="
if ((kind == Skew.NodeKind.EQUAL || kind == Skew.NodeKind.NOT_EQUAL) && left.resolvedType.isParameter() && right.resolvedType.isParameter()) {
if (kind == Skew.NodeKind.NOT_EQUAL) {
this._emit('!');
}
this._emit('EqualityComparer<');
this._emitType(left.resolvedType);
this._emit('>.Default.Equals(');
this._emitExpression(left, Skew.Precedence.COMMA);
this._emit(', ');
this._emitExpression(right, Skew.Precedence.COMMA);
this._emit(')');
in_StringMap.set(this._usingNames, 'System.Collections.Generic', 0);
}
else {
var info1 = in_IntMap.get1(Skew.operatorInfo, kind);
if (info1.precedence < precedence) {
this._emit('(');
}
this._emitExpression(left, info1.precedence + (info1.associativity == Skew.Associativity.RIGHT | 0) | 0);
this._emit(' ' + info1.text + ' ');
this._emitExpression(right, info1.precedence + (info1.associativity == Skew.Associativity.LEFT | 0) | 0);
if (info1.precedence < precedence) {
this._emit(')');
}
}
}
else {
assert(false);
}
break;
}
}
};
Skew.CSharpEmitter._isCompactNodeKind = function(kind) {
return kind == Skew.NodeKind.EXPRESSION || kind == Skew.NodeKind.VARIABLES || Skew.in_NodeKind.isJump(kind);
};
Skew.CSharpEmitter._fullName = function(symbol) {
var parent = symbol.parent;
if (parent != null && parent.kind != Skew.SymbolKind.OBJECT_GLOBAL && !Skew.in_SymbolKind.isParameter(symbol.kind)) {
var enclosingName = Skew.CSharpEmitter._fullName(parent);
if (symbol.kind == Skew.SymbolKind.FUNCTION_CONSTRUCTOR) {
return enclosingName;
}
return enclosingName + '.' + Skew.CSharpEmitter._mangleName(symbol);
}
return Skew.CSharpEmitter._mangleName(symbol);
};
Skew.CSharpEmitter._mangleName = function(symbol) {
symbol = symbol.forwarded();
if (symbol.kind == Skew.SymbolKind.FUNCTION_CONSTRUCTOR) {
symbol = symbol.parent;
}
if (!symbol.isImportedOrExported() && Skew.CSharpEmitter._isKeyword.has(symbol.name)) {
return '_' + symbol.name;
}
return symbol.name;
};
Skew.JavaScriptEmitter = function(_context, _options, _cache) {
Skew.Emitter.call(this);
this._context = _context;
this._options = _options;
this._cache = _cache;
this._isSpecialVariableNeeded = new Map();
this._loopLabels = new Map();
this._specialVariables = new Map();
this._global = null;
this._symbolsToExport = [];
this._allSpecialVariables = null;
this._exportsNamespace = null;
this._enclosingFunction = null;
this._enclosingLoop = null;
this._namespacePrefix = '';
this._previousNode = null;
this._previousSymbol = null;
this._parenthesizeInExpressions = 0;
this._currentColumn = 0;
this._currentLine = 0;
this._generator = new Skew.SourceMapGenerator();
this._previousSource = null;
this._previousStart = 0;
this._sourceMap = false;
this._allSymbols = [];
this._localVariableUnionFind = new Skew.UnionFind();
this._namingGroupIndexForSymbol = new Map();
this._symbolCounts = new Map();
this._nextSymbolName = 0;
this._mangle = false;
this._minify = false;
this._needsSemicolon = false;
this._newline = '\n';
this._space = ' ';
this._previousCodeUnit = 0;
this._currentSelf = null;
this._needsSelf = false;
};
__extends(Skew.JavaScriptEmitter, Skew.Emitter);
Skew.JavaScriptEmitter.prototype.visit = function(global) {
this._mangle = this._options.jsMangle;
this._minify = this._options.jsMinify;
this._sourceMap = this._options.jsSourceMap;
this._global = global;
if (this._minify) {
this._indentAmount = '';
this._newline = '';
this._space = '';
}
// Load special-cased variables
for (var i = 0, list = global.variables, count = list.length; i < count; i = i + 1 | 0) {
var variable = in_List.get(list, i);
var special = in_StringMap.get(Skew.JavaScriptEmitter._specialVariableMap, variable.name, Skew.JavaScriptEmitter.SpecialVariable.NONE);
if (special != Skew.JavaScriptEmitter.SpecialVariable.NONE) {
in_IntMap.set(this._specialVariables, special, variable);
}
}
assert(this._specialVariables.has(Skew.JavaScriptEmitter.SpecialVariable.AS_STRING));
assert(this._specialVariables.has(Skew.JavaScriptEmitter.SpecialVariable.CREATE));
assert(this._specialVariables.has(Skew.JavaScriptEmitter.SpecialVariable.EXTENDS));
assert(this._specialVariables.has(Skew.JavaScriptEmitter.SpecialVariable.IS_BOOL));
assert(this._specialVariables.has(Skew.JavaScriptEmitter.SpecialVariable.IS_DOUBLE));
assert(this._specialVariables.has(Skew.JavaScriptEmitter.SpecialVariable.IS_INT));
assert(this._specialVariables.has(Skew.JavaScriptEmitter.SpecialVariable.IS_STRING));
assert(this._specialVariables.has(Skew.JavaScriptEmitter.SpecialVariable.MULTIPLY));
assert(this._specialVariables.has(Skew.JavaScriptEmitter.SpecialVariable.PROTOTYPE));
// These don't need to be initialized
in_IntMap.get1(this._specialVariables, Skew.JavaScriptEmitter.SpecialVariable.PROTOTYPE).value = null;
// Sort these so their order is deterministic
this._allSpecialVariables = Array.from(this._specialVariables.values());
this._allSpecialVariables.sort(Skew.Symbol.SORT_VARIABLES_BY_ID);
// Preprocess the code
if (this._mangle) {
this._liftGlobals1(global);
}
if (this._options.inlineAllFunctions) {
this._maybeInlineFunctions(global);
}
Skew.shakingPass(global, this._cache.entryPointSymbol, Skew.ShakingMode.IGNORE_TYPES);
this._prepareGlobal(global);
this._convertLambdasToFunctions(global);
var objects = this._sortedObjects(global);
// Make sure the "__create" variable is inserted when used even if "__extends" isn't used
var create = in_IntMap.get1(this._specialVariables, Skew.JavaScriptEmitter.SpecialVariable.CREATE);
if (global.variables.indexOf(create) != -1) {
in_IntMap.set(this._isSpecialVariableNeeded, create.id, 0);
}
// The entire body of code is wrapped in a closure for safety
this._emit(this._indent + '(function(' + (this._exportsNamespace != null ? Skew.JavaScriptEmitter._mangleName(this._exportsNamespace) : '') + ')' + this._space + '{' + this._newline + '');
this._increaseIndent();
// Emit special-cased variables that must come first
for (var i1 = 0, list1 = this._allSpecialVariables, count1 = list1.length; i1 < count1; i1 = i1 + 1 | 0) {
var variable1 = in_List.get(list1, i1);
if (this._isSpecialVariableNeeded.has(variable1.id)) {
if (variable1.value != null && variable1.value.kind == Skew.NodeKind.LAMBDA) {
this._emitFunction(this._convertLambdaToFunction(variable1));
}
else {
this._emitVariable(variable1);
}
}
}
// Emit objects and functions
for (var i2 = 0, list2 = objects, count2 = list2.length; i2 < count2; i2 = i2 + 1 | 0) {
var object = in_List.get(list2, i2);
this._emitObject(object);
}
// Emit variables
var statement = new Skew.Node(Skew.NodeKind.VARIABLES);
for (var i4 = 0, list4 = objects, count4 = list4.length; i4 < count4; i4 = i4 + 1 | 0) {
var object1 = in_List.get(list4, i4);
this._namespacePrefix = '';
for (var o = object1; o.kind != Skew.SymbolKind.OBJECT_GLOBAL; o = o.parent.asObjectSymbol()) {
this._namespacePrefix = Skew.JavaScriptEmitter._mangleName(o) + '.' + this._namespacePrefix;
}
for (var i3 = 0, list3 = object1.variables, count3 = list3.length; i3 < count3; i3 = i3 + 1 | 0) {
var variable2 = in_List.get(list3, i3);
if (!(this._allSpecialVariables.indexOf(variable2) != -1)) {
if (this._mangle && this._namespacePrefix == '' && !variable2.isImportedOrExported()) {
statement.appendChild(Skew.Node.createVariable(variable2));
}
else {
this._emitVariable(variable2);
}
}
}
}
this._namespacePrefix = '';
// Group adjacent variables into a single statement during mangling
if (statement.hasChildren()) {
this._emitNewlineBeforeSymbol(statement.firstChild().symbol);
this._emitStatement(statement);
this._emitNewlineAfterSymbol(statement.firstChild().symbol);
for (var child = statement.firstChild(); child != null; child = child.nextSibling()) {
child.removeChildren();
}
}
// Emit entry point
var entryPointSymbol = this._cache.entryPointSymbol;
if (entryPointSymbol != null) {
var type = entryPointSymbol.resolvedType;
var callText = Skew.JavaScriptEmitter._fullName(entryPointSymbol) + (type.argumentTypes.length == 0 ? '()' : '(process.argv.slice(2))');
this._emitSemicolonIfNeeded();
this._emit(this._newline + this._indent + (type.returnType == this._cache.intType ? 'process.exit(' + callText + ')' : callText));
this._emitSemicolonAfterStatement();
}
// End the closure wrapping everything
this._decreaseIndent();
this._emit(this._indent + '})(' + (this._exportsNamespace != null ? 'this' : '') + ');\n');
var codeName = this._options.outputDirectory != null ? this._options.outputDirectory + '/compiled.js' : this._options.outputFile;
var mapName = codeName != null ? codeName + '.map' : null;
// Obfuscate the sourceMappingURL so it's not incorrectly picked up as the
// sourceMappingURL for the compiled JavaScript compiler file
if (this._sourceMap) {
this._emit('/');
this._emit('/# sourceMappingURL=' + Skew.splitPath(mapName).entry + '\n');
}
this._createSource(codeName, Skew.EmitMode.ALWAYS_EMIT);
// Create the source map
if (this._sourceMap) {
this._emit(this._generator.toString());
this._createSource(mapName, Skew.EmitMode.ALWAYS_EMIT);
}
};
Skew.JavaScriptEmitter.prototype._emit = function(text) {
if (this._minify || this._sourceMap) {
var n = text.length;
for (var i = 0, count = n; i < count; i = i + 1 | 0) {
if (in_string.get1(text, i) == 10) {
this._currentColumn = 0;
this._currentLine = this._currentLine + 1 | 0;
}
else {
this._currentColumn = this._currentColumn + 1 | 0;
}
}
if (n != 0) {
this._previousCodeUnit = in_string.get1(text, n - 1 | 0);
}
}
this._code.buffer += text;
};
Skew.JavaScriptEmitter.prototype._liftGlobals1 = function(global) {
var globalObjects = [];
var globalFunctions = [];
var globalVariables = [];
this._liftGlobals2(global, globalObjects, globalFunctions, globalVariables);
for (var i = 0, list = globalObjects, count = list.length; i < count; i = i + 1 | 0) {
var object = in_List.get(list, i);
object.parent = global;
}
for (var i1 = 0, list1 = globalFunctions, count1 = list1.length; i1 < count1; i1 = i1 + 1 | 0) {
var $function = in_List.get(list1, i1);
$function.parent = global;
}
for (var i2 = 0, list2 = globalVariables, count2 = list2.length; i2 < count2; i2 = i2 + 1 | 0) {
var variable = in_List.get(list2, i2);
variable.parent = global;
}
in_List.append1(global.objects, globalObjects);
in_List.append1(global.functions, globalFunctions);
in_List.append1(global.variables, globalVariables);
};
Skew.JavaScriptEmitter.prototype._liftGlobals2 = function(symbol, globalObjects, globalFunctions, globalVariables) {
var self = this;
var shouldLiftGlobals = symbol.parent != null;
// Scan over child objects
in_List.removeIf(symbol.objects, function(object) {
self._liftGlobals2(object, globalObjects, globalFunctions, globalVariables);
if (shouldLiftGlobals && !object.isImportedOrExported()) {
globalObjects.push(object);
return true;
}
return false;
});
in_List.removeIf(symbol.functions, function($function) {
if (shouldLiftGlobals && $function.kind == Skew.SymbolKind.FUNCTION_GLOBAL && !$function.isImportedOrExported()) {
globalFunctions.push($function);
return true;
}
return false;
});
// Scan over child variables
in_List.removeIf(symbol.variables, function(variable) {
if (shouldLiftGlobals && variable.kind == Skew.SymbolKind.VARIABLE_GLOBAL && !variable.isImportedOrExported()) {
globalVariables.push(variable);
return true;
}
return false;
});
};
Skew.JavaScriptEmitter.prototype._collectInlineableFunctions = function(symbol, listAppends, mapInserts) {
for (var i = 0, list = symbol.objects, count = list.length; i < count; i = i + 1 | 0) {
var object = in_List.get(list, i);
this._collectInlineableFunctions(object, listAppends, mapInserts);
}
for (var i3 = 0, list3 = symbol.functions, count3 = list3.length; i3 < count3; i3 = i3 + 1 | 0) {
var $function = in_List.get(list3, i3);
if ($function.block == null || !$function.block.hasTwoChildren()) {
continue;
}
var $arguments = $function.$arguments;
// "foo([], 0)" => "[0]" where "foo" is "def foo(a, b) { a.push(b); return a }"
if ($arguments.length == 2) {
var first = $function.block.firstChild();
var second = $function.block.lastChild();
if (first.kind == Skew.NodeKind.EXPRESSION && first.expressionValue().kind == Skew.NodeKind.CALL && second.kind == Skew.NodeKind.RETURN && second.returnValue() != null) {
var call = first.expressionValue();
var callValue = call.callValue();
if (call.hasTwoChildren() && callValue.kind == Skew.NodeKind.DOT && callValue.asString() == 'push' && Skew.JavaScriptEmitter._isReferenceTo(callValue.dotTarget(), in_List.get($arguments, 0)) && Skew.JavaScriptEmitter._isReferenceTo(call.lastChild(), in_List.get($arguments, 1)) && Skew.JavaScriptEmitter._isReferenceTo(second.returnValue(), in_List.get($arguments, 0))) {
for (var i1 = 0, list1 = this._context.callGraph.callInfoForSymbol($function).callSites, count1 = list1.length; i1 < count1; i1 = i1 + 1 | 0) {
var callSite = in_List.get(list1, i1);
if (callSite != null && callSite.callNode.kind == Skew.NodeKind.CALL) {
assert(callSite.callNode.symbol == $function);
listAppends.push(callSite.callNode);
}
}
}
}
}
// "foo({}, 0, 1)" => "{0: 1}" where "foo" is "def foo(a, b, c) { a[b] = c; return a }"
else if ($arguments.length == 3) {
var keyType = in_List.get($arguments, 1).resolvedType;
var first1 = $function.block.firstChild();
var second1 = $function.block.lastChild();
if ((keyType == Skew.Type.DYNAMIC || this._cache.isEquivalentToInt(keyType) || this._cache.isEquivalentToString(keyType)) && first1.kind == Skew.NodeKind.EXPRESSION && first1.expressionValue().kind == Skew.NodeKind.ASSIGN_INDEX && second1.kind == Skew.NodeKind.RETURN && second1.returnValue() != null) {
var assign = first1.expressionValue();
if (Skew.JavaScriptEmitter._isReferenceTo(assign.assignIndexLeft(), in_List.get($arguments, 0)) && Skew.JavaScriptEmitter._isReferenceTo(assign.assignIndexCenter(), in_List.get($arguments, 1)) && Skew.JavaScriptEmitter._isReferenceTo(assign.assignIndexRight(), in_List.get($arguments, 2)) && Skew.JavaScriptEmitter._isReferenceTo(second1.returnValue(), in_List.get($arguments, 0))) {
for (var i2 = 0, list2 = this._context.callGraph.callInfoForSymbol($function).callSites, count2 = list2.length; i2 < count2; i2 = i2 + 1 | 0) {
var callSite1 = in_List.get(list2, i2);
if (callSite1 != null && callSite1.callNode.kind == Skew.NodeKind.CALL) {
assert(callSite1.callNode.symbol == $function);
mapInserts.push(callSite1.callNode);
}
}
}
}
}
}
};
// This uses iteration until fixed point to avoid dependence on inlining order
Skew.JavaScriptEmitter.prototype._maybeInlineFunctions = function(global) {
var listAppends = [];
var mapInserts = [];
this._collectInlineableFunctions(global, listAppends, mapInserts);
// List append fixed point
var changed = true;
while (changed) {
changed = false;
for (var i = 0, count = listAppends.length; i < count; i = i + 1 | 0) {
var node = in_List.get(listAppends, i);
// This will be null if it was already inlined
if (node == null) {
continue;
}
var firstArgument = node.callValue().nextSibling();
var secondArgument = firstArgument.nextSibling();
// List expressions are sometimes casted
if (firstArgument.kind == Skew.NodeKind.CAST) {
firstArgument = firstArgument.castValue();
}
// Only check when the inputs are constants
if (firstArgument.kind == Skew.NodeKind.INITIALIZER_LIST) {
node.become(firstArgument.remove().appendChild(secondArgument.remove()));
in_List.set(listAppends, i, null);
changed = true;
}
}
}
// Map insert fixed point
changed = true;
while (changed) {
changed = false;
for (var i1 = 0, count1 = mapInserts.length; i1 < count1; i1 = i1 + 1 | 0) {
var node1 = in_List.get(mapInserts, i1);
// This will be null if it was already inlined
if (node1 == null) {
continue;
}
var firstArgument1 = node1.callValue().nextSibling();
var secondArgument1 = firstArgument1.nextSibling();
var thirdArgument = secondArgument1.nextSibling();
// Map expressions are sometimes casted
if (firstArgument1.kind == Skew.NodeKind.CAST) {
firstArgument1 = firstArgument1.castValue();
}
// Only check when the inputs are constants
if (firstArgument1.kind == Skew.NodeKind.INITIALIZER_MAP && (secondArgument1.isInt() || secondArgument1.isString())) {
node1.become(firstArgument1.remove().appendChild(Skew.Node.createPair(secondArgument1.remove(), thirdArgument.remove()).withType(Skew.Type.DYNAMIC)));
in_List.set(mapInserts, i1, null);
changed = true;
}
}
}
};
Skew.JavaScriptEmitter.prototype._prepareGlobal = function(global) {
// Lower certain stuff into JavaScript (for example, "x as bool" becomes "!!x")
this._patchObject(global);
this._exportSymbols();
// Skip everything below if we aren't mangling
if (!this._mangle) {
return;
}
// These will be culled by tree shaking regardless of whether they are needed
for (var i = 0, list = this._allSpecialVariables, count = list.length; i < count; i = i + 1 | 0) {
var variable = in_List.get(list, i);
if (this._isSpecialVariableNeeded.has(variable.id)) {
this._allocateNamingGroupIndex(variable);
this._patchNode(variable.value);
}
}
// Rename symbols based on frequency for better compression
this._renameSymbols();
};
Skew.JavaScriptEmitter.prototype._convertLambdaToFunction = function(variable) {
var $function = variable.value.symbol.asFunctionSymbol();
$function.kind = Skew.SymbolKind.FUNCTION_GLOBAL;
$function.parent = variable.parent;
$function.name = variable.name;
if ($function.block.parent() != null) {
$function.block.remove();
}
return $function;
};
Skew.JavaScriptEmitter.prototype._convertLambdasToFunctions = function(symbol) {
var self = this;
for (var i = 0, list = symbol.objects, count = list.length; i < count; i = i + 1 | 0) {
var object = in_List.get(list, i);
self._convertLambdasToFunctions(object);
}
in_List.removeIf(symbol.variables, function(variable) {
if (variable.kind == Skew.SymbolKind.VARIABLE_GLOBAL && variable.isConst() && !variable.isExported() && variable.value != null && variable.value.kind == Skew.NodeKind.LAMBDA) {
symbol.functions.push(self._convertLambdaToFunction(variable));
return true;
}
return false;
});
};
Skew.JavaScriptEmitter.prototype._allocateNamingGroupIndex = function(symbol) {
if (this._mangle && !this._namingGroupIndexForSymbol.has(symbol.id)) {
var index = this._localVariableUnionFind.allocate1();
in_IntMap.set(this._namingGroupIndexForSymbol, symbol.id, index);
this._allSymbols.push(symbol);
// Explicitly add function arguments since they won't be reached by
// normal tree traversal
if (Skew.in_SymbolKind.isFunction(symbol.kind)) {
var $this = symbol.asFunctionSymbol().$this;
if ($this != null) {
this._allocateNamingGroupIndex($this);
}
for (var i = 0, list = symbol.asFunctionSymbol().$arguments, count = list.length; i < count; i = i + 1 | 0) {
var argument = in_List.get(list, i);
this._allocateNamingGroupIndex(argument);
}
}
}
};
Skew.JavaScriptEmitter.prototype._renameSymbols = function() {
// This holds the groups used for naming. Unioning two labels using
// this object will cause both groups of symbols to have the same name.
var namingGroupsUnionFind = new Skew.UnionFind().allocate2(this._allSymbols.length);
// These are optional and only reduce the number of generated names
var order = [];
this._aliasLocalVariables(namingGroupsUnionFind, order);
this._aliasUnrelatedProperties(namingGroupsUnionFind, order);
// Ensure all overridden symbols have the same generated name. This is
// manditory for correctness, otherwise virtual functions break.
var namingGroupMap = new Map();
for (var i = 0, list = this._allSymbols, count1 = list.length; i < count1; i = i + 1 | 0) {
var symbol = in_List.get(list, i);
if (Skew.in_SymbolKind.isFunction(symbol.kind)) {
var $function = symbol.asFunctionSymbol();
assert(this._namingGroupIndexForSymbol.has($function.id));
var id = in_IntMap.get(namingGroupMap, $function.namingGroup, -1);
if (id == -1) {
in_IntMap.set(namingGroupMap, $function.namingGroup, in_IntMap.get1(this._namingGroupIndexForSymbol, $function.id));
}
else {
namingGroupsUnionFind.union(id, in_IntMap.get1(this._namingGroupIndexForSymbol, $function.id));
}
}
}
// Collect all reserved names together into one big set for querying
var reservedNames = new Map(Skew.JavaScriptEmitter._isKeyword);
for (var i1 = 0, list1 = this._allSymbols, count2 = list1.length; i1 < count2; i1 = i1 + 1 | 0) {
var symbol1 = in_List.get(list1, i1);
if (!Skew.JavaScriptEmitter._shouldRenameSymbol(symbol1)) {
in_StringMap.set(reservedNames, symbol1.name, 0);
}
}
// Everything that should have the same name is now grouped together.
// Generate and assign names to all internal symbols, but use shorter
// names for more frequently used symbols.
var sortedGroups = [];
for (var i3 = 0, list2 = this._extractGroups(namingGroupsUnionFind, Skew.JavaScriptEmitter.ExtractGroupsMode.ALL_SYMBOLS), count4 = list2.length; i3 < count4; i3 = i3 + 1 | 0) {
var group = in_List.get(list2, i3);
var count = 0;
for (var i2 = 0, count3 = group.length; i2 < count3; i2 = i2 + 1 | 0) {
var symbol2 = in_List.get(group, i2);
if (Skew.JavaScriptEmitter._shouldRenameSymbol(symbol2)) {
count = count + in_IntMap.get(this._symbolCounts, symbol2.id, 0) | 0;
}
}
sortedGroups.push(new Skew.JavaScriptEmitter.SymbolGroup(group, count));
}
// Create a total order to make builds deterministic when maps use hashing
sortedGroups.sort(function(a, b) {
var difference = in_int.compare(b.count, a.count);
if (difference == 0) {
difference = in_int.compare(b.symbols.length, a.symbols.length);
for (var i = 0; difference == 0 && i < a.symbols.length; i = i + 1 | 0) {
difference = in_int.compare(in_List.get(a.symbols, i).id, in_List.get(b.symbols, i).id);
}
}
return difference;
});
for (var i5 = 0, list4 = sortedGroups, count6 = list4.length; i5 < count6; i5 = i5 + 1 | 0) {
var group1 = in_List.get(list4, i5);
var name = '';
for (var i4 = 0, list3 = group1.symbols, count5 = list3.length; i4 < count5; i4 = i4 + 1 | 0) {
var symbol3 = in_List.get(list3, i4);
if (Skew.JavaScriptEmitter._shouldRenameSymbol(symbol3)) {
if (name == '') {
name = this._generateSymbolName(reservedNames);
}
symbol3.name = name;
}
}
}
};
// Merge local variables from different functions together in the order
// they were declared. This will cause every argument list to use the same
// variables in the same order, which should offer better gzip:
//
// function d(a, b) {}
// function e(a, b, c) {}
//
Skew.JavaScriptEmitter.prototype._aliasLocalVariables = function(unionFind, order) {
this._zipTogetherInOrder(unionFind, order, this._extractGroups(this._localVariableUnionFind, Skew.JavaScriptEmitter.ExtractGroupsMode.ONLY_LOCAL_VARIABLES));
};
// Merge all related types together into naming groups. This ensures names
// will be unique within a subclass hierarchy allowing names to be
// duplicated in separate subclass hierarchies.
Skew.JavaScriptEmitter.prototype._aliasUnrelatedProperties = function(unionFind, order) {
var relatedTypesUnionFind = new Skew.UnionFind().allocate2(this._allSymbols.length);
for (var i = 0, count1 = this._allSymbols.length; i < count1; i = i + 1 | 0) {
var symbol = in_List.get(this._allSymbols, i);
if (symbol.kind == Skew.SymbolKind.OBJECT_CLASS) {
var baseClass = symbol.asObjectSymbol().baseClass;
if (baseClass != null) {
relatedTypesUnionFind.union(i, in_IntMap.get1(this._namingGroupIndexForSymbol, baseClass.id));
}
for (var i1 = 0, list = symbol.asObjectSymbol().variables, count = list.length; i1 < count; i1 = i1 + 1 | 0) {
var variable = in_List.get(list, i1);
relatedTypesUnionFind.union(i, in_IntMap.get1(this._namingGroupIndexForSymbol, variable.id));
}
}
}
this._zipTogetherInOrder(unionFind, order, this._extractGroups(relatedTypesUnionFind, Skew.JavaScriptEmitter.ExtractGroupsMode.ONLY_INSTANCE_VARIABLES));
};
Skew.JavaScriptEmitter.prototype._zipTogetherInOrder = function(unionFind, order, groups) {
for (var i1 = 0, list = groups, count1 = list.length; i1 < count1; i1 = i1 + 1 | 0) {
var group = in_List.get(list, i1);
for (var i = 0, count = group.length; i < count; i = i + 1 | 0) {
var symbol = in_List.get(group, i);
var index = in_IntMap.get1(this._namingGroupIndexForSymbol, symbol.id);
if (i >= order.length) {
order.push(index);
}
else {
unionFind.union(index, in_List.get(order, i));
}
}
}
};
Skew.JavaScriptEmitter.prototype._generateSymbolName = function(reservedNames) {
while (true) {
var name = Skew.JavaScriptEmitter._numberToName(this._nextSymbolName);
this._nextSymbolName = this._nextSymbolName + 1 | 0;
if (!reservedNames.has(name)) {
return name;
}
}
};
Skew.JavaScriptEmitter.prototype._extractGroups = function(unionFind, mode) {
var labelToGroup = new Map();
for (var i = 0, list = this._allSymbols, count = list.length; i < count; i = i + 1 | 0) {
var symbol = in_List.get(list, i);
if (mode == Skew.JavaScriptEmitter.ExtractGroupsMode.ONLY_LOCAL_VARIABLES && !Skew.in_SymbolKind.isLocalOrArgumentVariable(symbol.kind) || mode == Skew.JavaScriptEmitter.ExtractGroupsMode.ONLY_INSTANCE_VARIABLES && symbol.kind != Skew.SymbolKind.VARIABLE_INSTANCE) {
continue;
}
assert(this._namingGroupIndexForSymbol.has(symbol.id));
var label = unionFind.find(in_IntMap.get1(this._namingGroupIndexForSymbol, symbol.id));
var group = in_IntMap.get(labelToGroup, label, null);
if (group == null) {
group = [];
in_IntMap.set(labelToGroup, label, group);
}
group.push(symbol);
}
// Sort each resulting group to make builds deterministic when maps use hashing
var groups = Array.from(labelToGroup.values());
for (var i1 = 0, list1 = groups, count1 = list1.length; i1 < count1; i1 = i1 + 1 | 0) {
var group1 = in_List.get(list1, i1);
group1.sort(Skew.Symbol.SORT_BY_ID);
}
return groups;
};
Skew.JavaScriptEmitter.prototype._addMapping = function(range) {
if (this._sourceMap && range != null) {
var source = range.source;
var start = range.start;
if (this._previousSource != source || this._previousStart != start) {
var location = source.indexToLineColumn(start);
this._generator.addMapping(source, location.line, location.column, this._currentLine, this._currentColumn);
this._previousStart = start;
this._previousSource = source;
}
}
};
Skew.JavaScriptEmitter.prototype._emitSemicolonAfterStatement = function() {
if (!this._minify) {
this._emit(';\n');
}
else {
this._needsSemicolon = true;
}
};
Skew.JavaScriptEmitter.prototype._emitSemicolonIfNeeded = function() {
if (this._needsSemicolon) {
this._emit(';');
this._needsSemicolon = false;
}
this._maybeEmitMinifedNewline();
};
// Lots of text editors choke up on long lines, so add a newline every now
// and then for usability's sake
Skew.JavaScriptEmitter.prototype._maybeEmitMinifedNewline = function() {
if (this._minify && this._currentColumn > 1024) {
this._emit('\n');
}
};
Skew.JavaScriptEmitter.prototype._emitNewlineBeforeSymbol = function(symbol) {
this._emitSemicolonIfNeeded();
if (!this._minify && this._previousSymbol != null && (!Skew.in_SymbolKind.isObject(this._previousSymbol.kind) || !Skew.in_SymbolKind.isObject(symbol.kind) || symbol.comments != null || Skew.in_SymbolKind.isEnumOrFlags(this._previousSymbol.kind) || Skew.in_SymbolKind.isEnumOrFlags(symbol.kind)) && (!Skew.in_SymbolKind.isVariable(this._previousSymbol.kind) || !Skew.in_SymbolKind.isVariable(symbol.kind) || symbol.comments != null)) {
this._emit('\n');
}
this._previousSymbol = null;
this._addMapping(symbol.range);
};
Skew.JavaScriptEmitter.prototype._emitNewlineAfterSymbol = function(symbol) {
this._previousSymbol = symbol;
};
Skew.JavaScriptEmitter.prototype._emitNewlineBeforeStatement = function(node) {
if (!this._minify && this._previousNode != null && (node.comments != null || !Skew.JavaScriptEmitter._isCompactNodeKind(this._previousNode.kind) || !Skew.JavaScriptEmitter._isCompactNodeKind(node.kind))) {
this._emit('\n');
}
else {
this._maybeEmitMinifedNewline();
}
this._previousNode = null;
};
Skew.JavaScriptEmitter.prototype._emitNewlineAfterStatement = function(node) {
this._previousNode = node;
};
Skew.JavaScriptEmitter.prototype._emitComments = function(comments) {
if (comments != null && !this._minify) {
for (var i1 = 0, list1 = comments, count1 = list1.length; i1 < count1; i1 = i1 + 1 | 0) {
var comment = in_List.get(list1, i1);
for (var i = 0, list = comment.lines, count = list.length; i < count; i = i + 1 | 0) {
var line = in_List.get(list, i);
this._emit(this._indent + '//' + line + '\n');
}
if (comment.hasGapBelow) {
this._emit('\n');
}
}
}
};
Skew.JavaScriptEmitter.prototype._emitObject = function(symbol) {
if (symbol.isImported()) {
return;
}
var foundPrimaryConstructor = false;
this._namespacePrefix = symbol.parent != null ? Skew.JavaScriptEmitter._computeNamespacePrefix(symbol.parent.asObjectSymbol()) : '';
switch (symbol.kind) {
case Skew.SymbolKind.OBJECT_NAMESPACE:
case Skew.SymbolKind.OBJECT_INTERFACE:
case Skew.SymbolKind.OBJECT_WRAPPED: {
if (symbol.forwardTo == null && symbol != this._exportsNamespace) {
this._emitNewlineBeforeSymbol(symbol);
this._emitComments(symbol.comments);
this._emit(this._indent + (this._namespacePrefix == '' ? 'var ' : this._namespacePrefix) + Skew.JavaScriptEmitter._mangleName(symbol) + this._space + '=' + this._space + '{}');
this._emitSemicolonAfterStatement();
this._emitNewlineAfterSymbol(symbol);
}
break;
}
case Skew.SymbolKind.OBJECT_ENUM:
case Skew.SymbolKind.OBJECT_FLAGS: {
this._emitNewlineBeforeSymbol(symbol);
this._emitComments(symbol.comments);
this._emit(this._indent + (this._namespacePrefix == '' ? 'var ' : this._namespacePrefix) + Skew.JavaScriptEmitter._mangleName(symbol) + this._space + '=' + this._space + '{');
this._increaseIndent();
var isFirst = true;
for (var i = 0, list = symbol.variables, count = list.length; i < count; i = i + 1 | 0) {
var variable = in_List.get(list, i);
if (variable.kind == Skew.SymbolKind.VARIABLE_ENUM_OR_FLAGS) {
if (isFirst) {
isFirst = false;
}
else {
this._emit(',');
}
this._emit(this._newline);
this._emitNewlineBeforeSymbol(variable);
this._emitComments(variable.comments);
this._emit(this._indent + Skew.JavaScriptEmitter._mangleName(variable) + ':' + this._space);
this._emitExpression(variable.value, Skew.Precedence.COMMA);
this._emitNewlineAfterSymbol(variable);
}
}
this._decreaseIndent();
if (!isFirst && !this._minify) {
this._emit('\n' + this._indent);
}
this._emit('}');
this._emitSemicolonAfterStatement();
this._emitNewlineAfterSymbol(symbol);
break;
}
case Skew.SymbolKind.OBJECT_CLASS: {
var variable1 = in_IntMap.get1(this._specialVariables, Skew.JavaScriptEmitter.SpecialVariable.EXTENDS);
for (var i1 = 0, list1 = symbol.functions, count1 = list1.length; i1 < count1; i1 = i1 + 1 | 0) {
var $function = in_List.get(list1, i1);
if ($function.isPrimaryConstructor()) {
if ($function.comments == null && symbol.comments != null) {
$function.comments = symbol.comments;
}
this._emitFunction($function);
if (symbol.baseClass != null || symbol.kind == Skew.SymbolKind.OBJECT_CLASS && symbol.$extends != null) {
if (!this._minify) {
this._emit('\n' + this._indent);
}
this._emitSemicolonIfNeeded();
this._addMapping(variable1.range);
this._emit(Skew.JavaScriptEmitter._mangleName(variable1) + '(' + Skew.JavaScriptEmitter._fullName(symbol) + ',' + this._space);
if (symbol.baseClass != null) {
this._emit(Skew.JavaScriptEmitter._fullName(symbol.baseClass));
}
else {
assert(symbol.kind == Skew.SymbolKind.OBJECT_CLASS && symbol.$extends != null);
this._emitExpression(symbol.$extends, Skew.Precedence.LOWEST);
}
this._emit(')');
this._emitSemicolonAfterStatement();
}
foundPrimaryConstructor = true;
break;
}
}
// Emit a namespace if the class is never constructed
if (!foundPrimaryConstructor) {
this._emitNewlineBeforeSymbol(symbol);
this._emit(this._indent + (this._namespacePrefix == '' && !symbol.isExported() ? 'var ' : this._namespacePrefix) + Skew.JavaScriptEmitter._mangleName(symbol) + this._space + '=' + this._space + '{}');
this._emitSemicolonAfterStatement();
}
break;
}
}
if (symbol.kind != Skew.SymbolKind.OBJECT_GLOBAL) {
this._namespacePrefix += Skew.JavaScriptEmitter._mangleName(symbol) + '.';
}
if (symbol.usePrototypeCache()) {
this._emitSemicolonIfNeeded();
this._emit(this._newline + this._indent + Skew.JavaScriptEmitter._mangleName(in_IntMap.get1(this._specialVariables, Skew.JavaScriptEmitter.SpecialVariable.PROTOTYPE)) + this._space + '=' + this._space + Skew.JavaScriptEmitter._fullName(symbol) + '.prototype');
this._emitSemicolonAfterStatement();
}
// Ignore instance functions if the class is never constructed
for (var i2 = 0, list2 = symbol.functions, count2 = list2.length; i2 < count2; i2 = i2 + 1 | 0) {
var function1 = in_List.get(list2, i2);
if (foundPrimaryConstructor ? !function1.isPrimaryConstructor() : function1.kind == Skew.SymbolKind.FUNCTION_GLOBAL) {
this._emitFunction(function1);
}
}
};
Skew.JavaScriptEmitter.prototype._emitArgumentList = function($arguments) {
for (var i = 0, list = $arguments, count = list.length; i < count; i = i + 1 | 0) {
var argument = in_List.get(list, i);
if (argument != in_List.first($arguments)) {
this._emit(',' + this._space);
}
this._addMapping(argument.range);
this._emit(Skew.JavaScriptEmitter._mangleName(argument));
}
};
Skew.JavaScriptEmitter.prototype._emitFunction = function(symbol) {
if (symbol.block == null) {
return;
}
this._emitNewlineBeforeSymbol(symbol);
this._emitComments(symbol.comments);
var isExpression = this._namespacePrefix != '' || symbol.isExported();
var name = Skew.JavaScriptEmitter._mangleName(symbol.isPrimaryConstructor() ? symbol.parent : symbol);
if (isExpression) {
this._emit(this._indent + (symbol.kind != Skew.SymbolKind.FUNCTION_INSTANCE ? this._namespacePrefix : symbol.parent.usePrototypeCache() ? Skew.JavaScriptEmitter._mangleName(in_IntMap.get1(this._specialVariables, Skew.JavaScriptEmitter.SpecialVariable.PROTOTYPE)) + '.' : this._namespacePrefix + 'prototype.') + name + this._space + '=' + this._space + 'function(');
}
else {
this._emit(this._indent + 'function ' + name + '(');
}
this._emitArgumentList(symbol.$arguments);
this._emit(')' + this._space + '{' + this._newline);
this._increaseIndent();
this._enclosingFunction = symbol;
this._emitStatements(symbol.block);
this._enclosingFunction = null;
this._decreaseIndent();
this._emit(this._indent + '}');
if (isExpression) {
this._emitSemicolonAfterStatement();
}
else {
this._needsSemicolon = false;
this._emit(this._newline);
}
this._emitNewlineAfterSymbol(symbol);
// Secondary constructors need the same prototype as the primary constructor
if (symbol.kind == Skew.SymbolKind.FUNCTION_CONSTRUCTOR && !symbol.isPrimaryConstructor()) {
this._emitSemicolonIfNeeded();
this._emit(this._newline + this._indent + Skew.JavaScriptEmitter._fullName(symbol) + '.prototype' + this._space + '=' + this._space + (symbol.parent.usePrototypeCache() ? Skew.JavaScriptEmitter._mangleName(in_IntMap.get1(this._specialVariables, Skew.JavaScriptEmitter.SpecialVariable.PROTOTYPE)) : Skew.JavaScriptEmitter._fullName(symbol.parent) + '.prototype'));
this._emitSemicolonAfterStatement();
}
};
Skew.JavaScriptEmitter.prototype._emitVariable = function(symbol) {
if (symbol.isImported()) {
return;
}
if (symbol.kind != Skew.SymbolKind.VARIABLE_INSTANCE && symbol.kind != Skew.SymbolKind.VARIABLE_ENUM_OR_FLAGS && (symbol.value != null || this._namespacePrefix == '' || Skew.in_SymbolKind.isLocalOrArgumentVariable(symbol.kind))) {
this._emitNewlineBeforeSymbol(symbol);
this._emitComments(symbol.comments);
this._emit(this._indent + (this._namespacePrefix == '' || Skew.in_SymbolKind.isLocalOrArgumentVariable(symbol.kind) ? 'var ' : this._namespacePrefix) + Skew.JavaScriptEmitter._mangleName(symbol));
if (symbol.value != null) {
this._emit(this._space + '=' + this._space);
this._emitExpression(symbol.value, Skew.Precedence.COMMA);
}
this._emitSemicolonAfterStatement();
this._emitNewlineAfterSymbol(symbol);
}
};
Skew.JavaScriptEmitter.prototype._emitStatements = function(node) {
this._previousNode = null;
for (var child = node.firstChild(); child != null; child = child.nextSibling()) {
this._emitSemicolonIfNeeded();
this._emitNewlineBeforeStatement(child);
this._addMapping(child.range);
this._emitComments(child.comments);
this._emitStatement(child);
this._emitNewlineAfterStatement(child);
}
this._previousNode = null;
};
Skew.JavaScriptEmitter.prototype._emitBlock = function(node, after, mode) {
var shouldMinify = mode == Skew.JavaScriptEmitter.BracesMode.CAN_OMIT_BRACES && this._minify;
this._addMapping(node.range);
if (shouldMinify && !node.hasChildren()) {
this._emit(';');
}
else if (shouldMinify && node.hasOneChild() && node.firstChild().kind != Skew.NodeKind.COMMENT_BLOCK) {
if (after == Skew.JavaScriptEmitter.AfterToken.AFTER_KEYWORD) {
this._emit(' ');
}
this._emitStatement(node.firstChild());
}
else {
this._emit(this._space + '{' + this._newline);
if (node.hasChildren()) {
this._increaseIndent();
this._emitStatements(node);
this._decreaseIndent();
}
this._emit(this._indent + '}');
this._needsSemicolon = false;
}
};
Skew.JavaScriptEmitter.prototype._emitVariables = function(node) {
this._emit('var ');
for (var child = node.firstChild(); child != null; child = child.nextSibling()) {
if (child.previousSibling() != null) {
this._emit(',' + this._space);
}
var symbol = child.symbol.asVariableSymbol();
this._emit(Skew.JavaScriptEmitter._mangleName(symbol));
if (symbol.value != null) {
this._emit(this._space + '=' + this._space);
this._emitExpression(symbol.value, Skew.Precedence.COMMA);
}
}
};
Skew.JavaScriptEmitter.prototype._canRemoveSpaceBeforeKeyword = function(node) {
var kind = node.kind;
return Skew.in_NodeKind.isUnary(kind) && !Skew.in_NodeKind.isUnaryPostfix(kind) || node.isString() || node.isNumberLessThanZero() || Skew.in_NodeKind.isInitializer(kind) || (kind == Skew.NodeKind.HOOK || kind == Skew.NodeKind.SEQUENCE) && this._canRemoveSpaceBeforeKeyword(node.firstChild());
};
Skew.JavaScriptEmitter.prototype._emitSpaceBeforeKeyword = function(node) {
if (!this._minify || !this._canRemoveSpaceBeforeKeyword(node)) {
this._emit(' ');
}
};
Skew.JavaScriptEmitter.prototype._emitStatement = function(node) {
switch (node.kind) {
case Skew.NodeKind.COMMENT_BLOCK: {
break;
}
case Skew.NodeKind.VARIABLES: {
this._emit(this._indent);
this._emitVariables(node);
this._emitSemicolonAfterStatement();
break;
}
case Skew.NodeKind.EXPRESSION: {
this._emit(this._indent);
this._emitExpression(node.expressionValue(), Skew.Precedence.LOWEST);
this._emitSemicolonAfterStatement();
break;
}
case Skew.NodeKind.BREAK: {
var label = in_IntMap.get(this._loopLabels, node.id, null);
this._emit(this._indent + 'break');
if (label != null) {
this._emit(' ' + Skew.JavaScriptEmitter._mangleName(label));
}
this._emitSemicolonAfterStatement();
break;
}
case Skew.NodeKind.CONTINUE: {
this._emit(this._indent + 'continue');
this._emitSemicolonAfterStatement();
break;
}
case Skew.NodeKind.RETURN: {
this._emit(this._indent + 'return');
var value = node.returnValue();
if (value != null) {
var comments = value.comments;
if (!this._minify && comments != null) {
// JavaScript needs parentheses here to avoid ASI issues
this._emit(' (\n');
this._increaseIndent();
this._emitComments(comments);
this._emit(this._indent);
this._emitExpression(value, Skew.Precedence.LOWEST);
this._decreaseIndent();
this._emit(')');
}
else {
this._emitSpaceBeforeKeyword(value);
this._emitExpression(value, Skew.Precedence.LOWEST);
}
}
this._emitSemicolonAfterStatement();
break;
}
case Skew.NodeKind.THROW: {
var value1 = node.throwValue();
this._emit(this._indent + 'throw');
this._emitSpaceBeforeKeyword(value1);
this._emitExpression(value1, Skew.Precedence.LOWEST);
this._emitSemicolonAfterStatement();
break;
}
case Skew.NodeKind.FOR: {
var setup = node.forSetup();
var test = node.forTest();
var update = node.forUpdate();
this._emit(this._indent);
this._emitLoopLabel(node);
this._emit('for' + this._space + '(');
if (!setup.isEmptySequence()) {
this._parenthesizeInExpressions = this._parenthesizeInExpressions + 1 | 0;
if (setup.kind == Skew.NodeKind.VARIABLES) {
this._emitVariables(setup);
}
else {
this._emitExpression(setup, Skew.Precedence.LOWEST);
}
this._parenthesizeInExpressions = this._parenthesizeInExpressions - 1 | 0;
}
this._emit(';');
if (!test.isEmptySequence()) {
this._emit(this._space);
this._emitExpression(test, Skew.Precedence.LOWEST);
}
this._emit(';');
if (!update.isEmptySequence()) {
this._emit(this._space);
this._emitExpression(update, Skew.Precedence.LOWEST);
}
this._emit(')');
this._emitBlock(node.forBlock(), Skew.JavaScriptEmitter.AfterToken.AFTER_PARENTHESIS, Skew.JavaScriptEmitter.BracesMode.CAN_OMIT_BRACES);
this._emit(this._newline);
break;
}
case Skew.NodeKind.FOREACH: {
this._emit(this._indent);
this._emitLoopLabel(node);
this._emit('for' + this._space + '(var ' + Skew.JavaScriptEmitter._mangleName(node.symbol) + ' in ');
this._emitExpression(node.foreachValue(), Skew.Precedence.LOWEST);
this._emit(')');
this._emitBlock(node.foreachBlock(), Skew.JavaScriptEmitter.AfterToken.AFTER_PARENTHESIS, Skew.JavaScriptEmitter.BracesMode.CAN_OMIT_BRACES);
this._emit(this._newline);
break;
}
case Skew.NodeKind.IF: {
this._emit(this._indent);
this._emitIf(node);
this._emit(this._newline);
break;
}
case Skew.NodeKind.SWITCH: {
var switchValue = node.switchValue();
this._emit(this._indent + 'switch' + this._space + '(');
this._emitExpression(switchValue, Skew.Precedence.LOWEST);
this._emit(')' + this._space + '{' + this._newline);
this._increaseIndent();
for (var child = switchValue.nextSibling(); child != null; child = child.nextSibling()) {
var block = child.caseBlock();
this._emitSemicolonIfNeeded();
if (child.previousSibling() != switchValue) {
this._emit(this._newline);
}
this._emitComments(child.comments);
if (child.hasOneChild()) {
this._emit(this._indent + 'default:');
}
else {
for (var value2 = child.firstChild(); value2 != block; value2 = value2.nextSibling()) {
if (value2.previousSibling() != null) {
this._emit(this._newline);
}
this._emitComments(value2.comments);
this._emit(this._indent + 'case');
this._emitSpaceBeforeKeyword(value2);
this._emitExpression(value2, Skew.Precedence.LOWEST);
this._emit(':');
}
}
if (!this._minify) {
this._emit(' {\n');
this._increaseIndent();
}
this._emitStatements(block);
if (block.hasControlFlowAtEnd()) {
this._emitSemicolonIfNeeded();
this._emit(this._indent + 'break');
this._emitSemicolonAfterStatement();
}
if (!this._minify) {
this._decreaseIndent();
this._emit(this._indent + '}\n');
}
}
this._decreaseIndent();
this._emit(this._indent + '}' + this._newline);
this._needsSemicolon = false;
break;
}
case Skew.NodeKind.TRY: {
var tryBlock = node.tryBlock();
var finallyBlock = node.finallyBlock();
this._emit(this._indent + 'try');
this._emitBlock(tryBlock, Skew.JavaScriptEmitter.AfterToken.AFTER_KEYWORD, Skew.JavaScriptEmitter.BracesMode.MUST_KEEP_BRACES);
this._emit(this._newline);
for (var child1 = tryBlock.nextSibling(); child1 != finallyBlock; child1 = child1.nextSibling()) {
this._emit(this._newline);
this._emitComments(child1.comments);
this._emit(this._indent + 'catch' + this._space + '(' + Skew.JavaScriptEmitter._mangleName(child1.symbol) + ')');
this._emitBlock(child1.catchBlock(), Skew.JavaScriptEmitter.AfterToken.AFTER_KEYWORD, Skew.JavaScriptEmitter.BracesMode.MUST_KEEP_BRACES);
this._emit(this._newline);
}
if (finallyBlock != null) {
this._emit(this._newline);
this._emitComments(finallyBlock.comments);
this._emit(this._indent + 'finally');
this._emitBlock(finallyBlock, Skew.JavaScriptEmitter.AfterToken.AFTER_KEYWORD, Skew.JavaScriptEmitter.BracesMode.MUST_KEEP_BRACES);
this._emit(this._newline);
}
break;
}
case Skew.NodeKind.WHILE: {
this._emit(this._indent);
this._emitLoopLabel(node);
this._emit('while' + this._space + '(');
this._emitExpression(node.whileTest(), Skew.Precedence.LOWEST);
this._emit(')');
this._emitBlock(node.whileBlock(), Skew.JavaScriptEmitter.AfterToken.AFTER_PARENTHESIS, Skew.JavaScriptEmitter.BracesMode.CAN_OMIT_BRACES);
this._emit(this._newline);
break;
}
default: {
assert(false);
break;
}
}
};
Skew.JavaScriptEmitter.prototype._emitLoopLabel = function(node) {
var label = in_IntMap.get(this._loopLabels, node.id, null);
if (label != null) {
this._emit(Skew.JavaScriptEmitter._mangleName(label) + ':' + this._space);
}
};
Skew.JavaScriptEmitter.prototype._emitIf = function(node) {
var trueBlock = node.ifTrue();
var falseBlock = node.ifFalse();
this._emit('if' + this._space + '(');
this._emitExpression(node.ifTest(), Skew.Precedence.LOWEST);
this._emit(')');
// Make sure to always keep braces to avoid the dangling "else" case
// "if (a) if (b) c; else d; else e;"
// "if (a) { if (b) if (c) d; else e; } else f;"
// "if (a) { if (b) c; else if (d) e; } else f;"
// "if (a) { while (true) if (b) break; } else c;"
var braces = Skew.JavaScriptEmitter.BracesMode.CAN_OMIT_BRACES;
if (falseBlock != null) {
var statement = trueBlock.blockStatement();
if (statement != null && (statement.kind == Skew.NodeKind.IF || statement.kind == Skew.NodeKind.FOR && statement.forBlock().blockStatement() != null || statement.kind == Skew.NodeKind.FOREACH && statement.foreachBlock().blockStatement() != null || statement.kind == Skew.NodeKind.WHILE && statement.whileBlock().blockStatement() != null)) {
braces = Skew.JavaScriptEmitter.BracesMode.MUST_KEEP_BRACES;
}
}
this._emitBlock(node.ifTrue(), Skew.JavaScriptEmitter.AfterToken.AFTER_PARENTHESIS, braces);
if (falseBlock != null) {
var singleIf = Skew.JavaScriptEmitter._singleIf(falseBlock);
this._emitSemicolonIfNeeded();
this._emit(this._newline + this._newline);
this._emitComments(falseBlock.comments);
if (singleIf != null) {
this._emitComments(singleIf.comments);
}
this._emit(this._indent + 'else');
if (singleIf != null) {
this._emit(' ');
this._emitIf(singleIf);
}
else {
this._emitBlock(falseBlock, Skew.JavaScriptEmitter.AfterToken.AFTER_KEYWORD, Skew.JavaScriptEmitter.BracesMode.CAN_OMIT_BRACES);
}
}
};
Skew.JavaScriptEmitter.prototype._emitContent = function(content) {
switch (content.kind()) {
case Skew.ContentKind.BOOL: {
this._emit(Skew.in_Content.asBool(content).toString());
break;
}
case Skew.ContentKind.INT: {
this._emit(Skew.in_Content.asInt(content).toString());
break;
}
case Skew.ContentKind.DOUBLE: {
var value = Skew.in_Content.asDouble(content);
var text = isNaN(value) ? 'NaN' : value == 1 / 0 ? 'Infinity' : value == -(1 / 0) ? '-Infinity' :
// The C# implementation of double.ToString() uses an uppercase "E"
TARGET == Target.CSHARP ? value.toString().toLowerCase() : value.toString();
// "0.123" => ".123"
// "-0.123" => "-.123"
if (this._minify) {
if (text.startsWith('0.') && text != '0.') {
text = in_string.slice1(text, 1);
}
else if (text.startsWith('-0.') && text != '-0.') {
text = '-' + in_string.slice1(text, 2);
}
}
this._emit(text);
break;
}
case Skew.ContentKind.STRING: {
this._emit(Skew.quoteString(Skew.in_Content.asString(content), Skew.QuoteStyle.SHORTEST, Skew.QuoteOctal.OCTAL_WORKAROUND));
break;
}
}
};
Skew.JavaScriptEmitter.prototype._emitCommaSeparatedExpressions = function(from, to) {
while (from != to) {
this._emitExpression(from, Skew.Precedence.COMMA);
from = from.nextSibling();
if (from != to) {
this._emit(',' + this._space);
this._maybeEmitMinifedNewline();
}
}
};
// Calling a function in an expression that starts with something like "function(){}()"
// must be wrapped in parentheses to avoid looking like a function statement
Skew.JavaScriptEmitter.prototype._lambdaMayNeedParentheses = function(node) {
var parent = node.parent();
if (parent == null) {
// Expression statements always have parents
return false;
}
switch (parent.kind) {
case Skew.NodeKind.CALL: {
return node == parent.callValue() && this._lambdaMayNeedParentheses(parent);
}
case Skew.NodeKind.DOT: {
return this._lambdaMayNeedParentheses(parent);
}
case Skew.NodeKind.INDEX: {
return node == parent.indexLeft() && this._lambdaMayNeedParentheses(parent);
}
case Skew.NodeKind.ASSIGN_INDEX: {
return node == parent.assignIndexLeft() && this._lambdaMayNeedParentheses(parent);
}
default: {
if (Skew.in_NodeKind.isBinary(parent.kind)) {
return node == parent.binaryLeft() && this._lambdaMayNeedParentheses(parent);
}
// Not sure, wrap to be safe
return true;
}
}
};
// Returns true if the provided call node must be parenthesized due to being inside a dot expression
Skew.JavaScriptEmitter.prototype._checkForDotParentOfCall = function(node) {
assert(node.kind == Skew.NodeKind.CALL);
var p = node.parent();
label: while (p != null) {
switch (p.kind) {
case Skew.NodeKind.CAST:
case Skew.NodeKind.PARAMETERIZE: {
p = p.parent();
break;
}
case Skew.NodeKind.DOT: {
return true;
}
default: {
break label;
}
}
}
return false;
};
Skew.JavaScriptEmitter.prototype._emitExpression = function(node, precedence) {
var kind = node.kind;
this._addMapping(node.range);
switch (kind) {
case Skew.NodeKind.TYPE: {
this._emit(Skew.JavaScriptEmitter._fullName(node.resolvedType.symbol));
break;
}
case Skew.NodeKind.NULL: {
this._emit('null');
break;
}
case Skew.NodeKind.NAME: {
var symbol = node.symbol;
this._emit(symbol != null ? Skew.JavaScriptEmitter._fullName(symbol) : node.asString());
break;
}
case Skew.NodeKind.DOT: {
this._emitExpression(node.dotTarget(), Skew.Precedence.MEMBER);
this._emit('.' + (node.symbol != null ? Skew.JavaScriptEmitter._mangleName(node.symbol) : node.asString()));
break;
}
case Skew.NodeKind.CONSTANT: {
var wrap = precedence == Skew.Precedence.MEMBER && (node.isInt() || node.isDouble() && (isFinite(node.asDouble()) || node.asDouble() < 0));
if (wrap) {
this._emit('(');
}
// Prevent "x - -1" from becoming "x--1"
if (this._minify && node.isNumberLessThanZero() && this._previousCodeUnit == 45) {
this._emit(' ');
}
this._emitContent(node.content);
if (wrap) {
this._emit(')');
}
break;
}
case Skew.NodeKind.CALL: {
var value = node.callValue();
var call = value.kind == Skew.NodeKind.SUPER;
var isKeyword = value.kind == Skew.NodeKind.NAME && value.symbol == null && Skew.JavaScriptEmitter._keywordCallMap.has(value.asString());
var parenthesize = isKeyword && Skew.Precedence.UNARY_POSTFIX < precedence;
var wrap1 = value.kind == Skew.NodeKind.LAMBDA && this._lambdaMayNeedParentheses(node);
var isNew = false;
if (parenthesize) {
this._emit('(');
}
if (wrap1) {
this._emit('(');
}
if (!call && node.symbol != null && node.symbol.kind == Skew.SymbolKind.FUNCTION_CONSTRUCTOR) {
this._emit('new ' + Skew.JavaScriptEmitter._fullName(node.symbol));
isNew = true;
}
else if (!call && value.kind == Skew.NodeKind.DOT && value.asString() == 'new') {
this._emit('new ');
this._emitExpression(value.dotTarget(), Skew.Precedence.MEMBER);
isNew = true;
}
else {
this._emitExpression(value, Skew.Precedence.UNARY_POSTFIX);
if (call) {
this._emit('.call');
}
}
if (wrap1) {
this._emit(')');
}
// Omit parentheses during mangling when possible
if (!isNew || !this._mangle || call || value.nextSibling() != null || this._checkForDotParentOfCall(node)) {
this._emit(isKeyword ? ' ' : '(');
if (call) {
this._emit(Skew.JavaScriptEmitter._mangleName(this._enclosingFunction.$this));
}
for (var child = value.nextSibling(); child != null; child = child.nextSibling()) {
if (call || child.previousSibling() != value) {
this._emit(',' + this._space);
this._maybeEmitMinifedNewline();
}
this._emitExpression(child, Skew.Precedence.COMMA);
}
if (!isKeyword) {
this._emit(')');
}
}
if (parenthesize) {
this._emit(')');
}
break;
}
case Skew.NodeKind.INITIALIZER_LIST:
case Skew.NodeKind.INITIALIZER_MAP: {
var useBraces = kind == Skew.NodeKind.INITIALIZER_MAP;
var isIndented = false;
if (!this._minify) {
for (var child1 = node.firstChild(); child1 != null; child1 = child1.nextSibling()) {
if (child1.comments != null) {
isIndented = true;
break;
}
}
}
this._emit(useBraces ? '{' : '[');
if (isIndented) {
this._increaseIndent();
}
for (var child2 = node.firstChild(); child2 != null; child2 = child2.nextSibling()) {
if (child2.previousSibling() != null) {
this._emit(',' + (isIndented ? '' : this._space));
this._maybeEmitMinifedNewline();
}
if (isIndented) {
this._emit('\n');
this._emitComments(child2.comments);
this._emit(this._indent);
}
this._emitExpression(child2, Skew.Precedence.COMMA);
}
if (isIndented) {
this._decreaseIndent();
this._emit('\n' + this._indent);
}
this._emit(useBraces ? '}' : ']');
break;
}
case Skew.NodeKind.PAIR: {
this._emitExpression(node.firstValue(), Skew.Precedence.LOWEST);
this._emit(':' + this._space);
this._emitExpression(node.secondValue(), Skew.Precedence.LOWEST);
break;
}
case Skew.NodeKind.INDEX: {
this._emitExpression(node.indexLeft(), Skew.Precedence.UNARY_POSTFIX);
this._emit('[');
this._emitExpression(node.indexRight(), Skew.Precedence.LOWEST);
this._emit(']');
break;
}
case Skew.NodeKind.ASSIGN_INDEX: {
if (Skew.Precedence.ASSIGN < precedence) {
this._emit('(');
}
this._emitExpression(node.assignIndexLeft(), Skew.Precedence.UNARY_POSTFIX);
this._emit('[');
this._emitExpression(node.assignIndexCenter(), Skew.Precedence.LOWEST);
this._emit(']' + this._space + '=' + this._space + '');
this._emitExpression(node.assignIndexRight(), Skew.Precedence.ASSIGN);
if (Skew.Precedence.ASSIGN < precedence) {
this._emit(')');
}
break;
}
case Skew.NodeKind.CAST: {
this._emitExpression(node.castValue(), precedence);
break;
}
case Skew.NodeKind.PARAMETERIZE: {
this._emitExpression(node.parameterizeValue(), precedence);
break;
}
case Skew.NodeKind.SEQUENCE: {
if (Skew.Precedence.COMMA <= precedence) {
this._emit('(');
}
this._emitCommaSeparatedExpressions(node.firstChild(), null);
if (Skew.Precedence.COMMA <= precedence) {
this._emit(')');
}
break;
}
case Skew.NodeKind.SUPER: {
this._emit(Skew.JavaScriptEmitter._fullName(node.symbol));
break;
}
case Skew.NodeKind.HOOK: {
if (Skew.Precedence.ASSIGN < precedence) {
this._emit('(');
}
this._emitExpression(node.hookTest(), Skew.Precedence.LOGICAL_OR);
this._emit(this._space + '?');
var left = node.hookTrue();
if (left.comments != null) {
this._emit(this._newline);
this._increaseIndent();
this._emitComments(left.comments);
this._emit(this._indent);
this._emitExpression(left, Skew.Precedence.ASSIGN);
this._decreaseIndent();
}
else {
this._emit(this._space);
this._emitExpression(left, Skew.Precedence.ASSIGN);
}
this._emit(this._space + ':');
var right = node.hookFalse();
if (right.comments != null) {
this._emit(this._newline);
this._increaseIndent();
this._emitComments(right.comments);
this._emit(this._indent);
this._emitExpression(right, Skew.Precedence.ASSIGN);
this._decreaseIndent();
}
else {
this._emit(this._space);
this._emitExpression(right, Skew.Precedence.ASSIGN);
}
if (Skew.Precedence.ASSIGN < precedence) {
this._emit(')');
}
break;
}
case Skew.NodeKind.LAMBDA: {
var symbol1 = node.symbol.asFunctionSymbol();
this._emit('function(');
this._emitArgumentList(symbol1.$arguments);
this._emit(')');
this._emitBlock(symbol1.block, Skew.JavaScriptEmitter.AfterToken.AFTER_PARENTHESIS, Skew.JavaScriptEmitter.BracesMode.MUST_KEEP_BRACES);
break;
}
case Skew.NodeKind.COMPLEMENT:
case Skew.NodeKind.NEGATIVE:
case Skew.NodeKind.NOT:
case Skew.NodeKind.POSITIVE:
case Skew.NodeKind.POSTFIX_DECREMENT:
case Skew.NodeKind.POSTFIX_INCREMENT:
case Skew.NodeKind.PREFIX_DECREMENT:
case Skew.NodeKind.PREFIX_INCREMENT: {
var value1 = node.unaryValue();
var info = in_IntMap.get1(Skew.operatorInfo, kind);
if (info.precedence < precedence) {
this._emit('(');
}
if (Skew.in_NodeKind.isUnaryPostfix(kind)) {
this._emitExpression(value1, info.precedence);
this._emit(info.text);
}
else {
// Prevent "x - -1" from becoming "x--1"
if (this._minify && (kind == Skew.NodeKind.POSITIVE || kind == Skew.NodeKind.NEGATIVE || kind == Skew.NodeKind.PREFIX_INCREMENT || kind == Skew.NodeKind.PREFIX_DECREMENT) && in_string.get1(info.text, 0) == this._previousCodeUnit) {
this._emit(' ');
}
this._emit(info.text);
this._emitExpression(value1, info.precedence);
}
if (info.precedence < precedence) {
this._emit(')');
}
break;
}
case Skew.NodeKind.TYPE_CHECK: {
var type = node.typeCheckType();
var resolvedType = type.resolvedType;
if (resolvedType.isWrapped()) {
resolvedType = this._cache.unwrappedType(resolvedType);
}
if (resolvedType.kind == Skew.TypeKind.SYMBOL || type.kind != Skew.NodeKind.TYPE) {
if (Skew.Precedence.COMPARE < precedence) {
this._emit('(');
}
this._emitExpression(node.typeCheckValue(), Skew.Precedence.COMPARE);
this._emit(' instanceof ');
if (resolvedType.kind == Skew.TypeKind.SYMBOL) {
this._emit(Skew.JavaScriptEmitter._fullName(resolvedType.symbol));
}
else {
this._emitExpression(type, Skew.Precedence.COMPARE);
}
if (Skew.Precedence.COMPARE < precedence) {
this._emit(')');
}
}
else {
this._emitExpression(node.typeCheckValue(), precedence);
}
break;
}
default: {
if (Skew.in_NodeKind.isBinary(kind)) {
var info1 = in_IntMap.get1(Skew.operatorInfo, kind);
var left1 = node.binaryLeft();
var right1 = node.binaryRight();
var extraEquals = left1.resolvedType == Skew.Type.DYNAMIC || right1.resolvedType == Skew.Type.DYNAMIC ? '=' : '';
var needsParentheses = info1.precedence < precedence || kind == Skew.NodeKind.IN && this._parenthesizeInExpressions != 0;
if (needsParentheses) {
this._emit('(');
}
this._emitExpression(node.binaryLeft(), info1.precedence + (info1.associativity == Skew.Associativity.RIGHT | 0) | 0);
// Always emit spaces around keyword operators, even when minifying
var comments = this._minify ? null : right1.comments;
this._emit(kind == Skew.NodeKind.IN ? (left1.isString() ? this._space : ' ') + 'in' + (comments != null ? '' : ' ') : this._space + (kind == Skew.NodeKind.EQUAL ? '==' + extraEquals : kind == Skew.NodeKind.NOT_EQUAL ? '!=' + extraEquals : info1.text));
if (comments != null) {
this._emit(this._newline);
this._increaseIndent();
this._emitComments(comments);
this._emit(this._indent);
this._emitExpression(right1, info1.precedence + (info1.associativity == Skew.Associativity.LEFT | 0) | 0);
this._decreaseIndent();
}
else {
if (kind != Skew.NodeKind.IN) {
this._emit(this._space);
}
this._emitExpression(right1, info1.precedence + (info1.associativity == Skew.Associativity.LEFT | 0) | 0);
}
if (needsParentheses) {
this._emit(')');
}
}
else {
assert(false);
}
break;
}
}
};
Skew.JavaScriptEmitter.prototype._patchObject = function(symbol) {
this._allocateNamingGroupIndex(symbol);
// Subclasses need the extension stub
if (!symbol.isImported() && (symbol.baseClass != null || symbol.kind == Skew.SymbolKind.OBJECT_CLASS && symbol.$extends != null)) {
this._specialVariable(Skew.JavaScriptEmitter.SpecialVariable.EXTENDS);
this._specialVariable(Skew.JavaScriptEmitter.SpecialVariable.CREATE);
}
// Scan over child objects
for (var i = 0, list = symbol.objects, count = list.length; i < count; i = i + 1 | 0) {
var object = in_List.get(list, i);
this._patchObject(object);
if (symbol == this._global && object.isExported()) {
this._symbolsToExport.push(object);
}
}
// Scan over child functions
var isPrimaryConstructor = true;
var prototypeCount = 0;
for (var i2 = 0, list2 = symbol.functions, count2 = list2.length; i2 < count2; i2 = i2 + 1 | 0) {
var $function = in_List.get(list2, i2);
var block = $function.block;
var $this = $function.$this;
this._allocateNamingGroupIndex($function);
// Check to see if we need an explicit "self" parameter while patching the block
this._needsSelf = false;
this._currentSelf = $this;
this._enclosingFunction = $function;
this._patchNode(block);
this._enclosingFunction = null;
// Only insert the "self" variable if required to handle capture inside lambdas
if (this._needsSelf) {
this._unionVariableWithFunction($this, $function);
if (block != null) {
$this.kind = Skew.SymbolKind.VARIABLE_LOCAL;
$this.value = new Skew.Node(Skew.NodeKind.NAME).withContent(new Skew.StringContent('this')).withType(Skew.Type.DYNAMIC);
var variable = Skew.Node.createVariable($this);
var merged = false;
// When mangling, add the "self" variable to an existing variable statement if present
if (this._mangle && block.hasChildren()) {
var firstChild = block.firstChild();
if (firstChild.kind == Skew.NodeKind.VARIABLES) {
firstChild.prependChild(variable);
merged = true;
}
else if (firstChild.kind == Skew.NodeKind.FOR) {
if (firstChild.forSetup().kind == Skew.NodeKind.VARIABLES) {
firstChild.forSetup().prependChild(variable);
merged = true;
}
else if (firstChild.forSetup().isEmptySequence()) {
firstChild.forSetup().replaceWith(new Skew.Node(Skew.NodeKind.VARIABLES).appendChild(variable));
merged = true;
}
}
}
if (!merged) {
block.prependChild(new Skew.Node(Skew.NodeKind.VARIABLES).appendChild(variable));
}
}
}
else if ($this != null) {
$this.name = 'this';
$this.flags |= Skew.SymbolFlags.IS_EXPORTED;
}
for (var i1 = 0, list1 = $function.$arguments, count1 = list1.length; i1 < count1; i1 = i1 + 1 | 0) {
var argument = in_List.get(list1, i1);
this._allocateNamingGroupIndex(argument);
this._unionVariableWithFunction(argument, $function);
}
// Rename extra constructors overloads so they don't conflict
if ($function.kind == Skew.SymbolKind.FUNCTION_CONSTRUCTOR && isPrimaryConstructor) {
$function.flags |= Skew.SymbolFlags.IS_PRIMARY_CONSTRUCTOR;
isPrimaryConstructor = false;
}
// Mark the prototype variable as needed when the prototype is used
else if (this._mangle && ($function.kind == Skew.SymbolKind.FUNCTION_INSTANCE || $function.kind == Skew.SymbolKind.FUNCTION_CONSTRUCTOR && !isPrimaryConstructor)) {
if ((prototypeCount = prototypeCount + 1 | 0) == 2) {
var variable1 = this._specialVariable(Skew.JavaScriptEmitter.SpecialVariable.PROTOTYPE);
in_IntMap.set(this._symbolCounts, variable1.id, in_IntMap.get(this._symbolCounts, variable1.id, 0) + 1 | 0);
symbol.flags |= Skew.SymbolFlags.USE_PROTOTYPE_CACHE;
}
}
if (symbol == this._global && $function.isExported()) {
this._symbolsToExport.push($function);
}
}
// Scan over child variables
for (var i3 = 0, list3 = symbol.variables, count3 = list3.length; i3 < count3; i3 = i3 + 1 | 0) {
var variable2 = in_List.get(list3, i3);
this._allocateNamingGroupIndex(variable2);
this._patchNode(variable2.value);
if (symbol == this._global && variable2.isExported()) {
this._symbolsToExport.push(variable2);
}
}
};
Skew.JavaScriptEmitter.prototype._exportSymbols = function() {
if (this._symbolsToExport.length == 0) {
return;
}
this._exportsNamespace = new Skew.ObjectSymbol(Skew.SymbolKind.OBJECT_NAMESPACE, this._global.scope.generateName('exports'));
this._exportsNamespace.resolvedType = new Skew.Type(Skew.TypeKind.SYMBOL, this._exportsNamespace);
this._exportsNamespace.state = Skew.SymbolState.INITIALIZED;
this._exportsNamespace.scope = new Skew.ObjectScope(this._global.scope, this._exportsNamespace);
this._exportsNamespace.parent = this._global;
this._global.objects.push(this._exportsNamespace);
this._allocateNamingGroupIndex(this._exportsNamespace);
for (var i = 0, list = this._symbolsToExport, count = list.length; i < count; i = i + 1 | 0) {
var symbol = in_List.get(list, i);
assert(symbol.parent != null);
assert(Skew.in_SymbolKind.isObject(symbol.parent.kind));
var oldParent = symbol.parent.asObjectSymbol();
symbol.parent = this._exportsNamespace;
if (Skew.in_SymbolKind.isObject(symbol.kind)) {
in_List.removeOne(oldParent.objects, symbol.asObjectSymbol());
this._exportsNamespace.objects.push(symbol.asObjectSymbol());
}
else if (Skew.in_SymbolKind.isFunction(symbol.kind)) {
in_List.removeOne(oldParent.functions, symbol.asFunctionSymbol());
this._exportsNamespace.functions.push(symbol.asFunctionSymbol());
}
else if (Skew.in_SymbolKind.isVariable(symbol.kind)) {
in_List.removeOne(oldParent.variables, symbol.asVariableSymbol());
this._exportsNamespace.variables.push(symbol.asVariableSymbol());
}
else {
assert(false);
}
}
};
Skew.JavaScriptEmitter.prototype._createIntBinary = function(kind, left, right) {
if (kind == Skew.NodeKind.MULTIPLY) {
return Skew.Node.createSymbolCall(this._specialVariable(Skew.JavaScriptEmitter.SpecialVariable.MULTIPLY)).appendChild(left).appendChild(right);
}
return this._wrapWithIntCast(Skew.Node.createBinary(kind, left, right).withType(this._cache.intType));
};
Skew.JavaScriptEmitter.prototype._wrapWithNot = function(node) {
return Skew.Node.createUnary(Skew.NodeKind.NOT, node).withType(this._cache.boolType).withRange(node.range);
};
Skew.JavaScriptEmitter.prototype._wrapWithIntCast = function(node) {
return Skew.Node.createBinary(Skew.NodeKind.BITWISE_OR, node, this._cache.createInt(0)).withType(this._cache.intType).withRange(node.range);
};
Skew.JavaScriptEmitter.prototype._removeIntCast = function(node) {
if (node.kind == Skew.NodeKind.BITWISE_OR && node.binaryRight().isInt() && node.binaryRight().asInt() == 0) {
node.replaceWith(node.binaryLeft().remove());
}
};
Skew.JavaScriptEmitter.prototype._patchUnaryArithmetic = function(node) {
if (node.resolvedType == this._cache.intType && !Skew.JavaScriptEmitter._alwaysConvertsOperandsToInt(node.parent())) {
var value = node.unaryValue();
if (value.resolvedType == this._cache.intType) {
if (value.isInt()) {
value.content = new Skew.IntContent(-value.asInt() | 0);
node.become(value.remove());
}
else {
node.become(this._wrapWithIntCast(node.cloneAndStealChildren()));
}
}
}
};
Skew.JavaScriptEmitter.prototype._patchBinaryArithmetic = function(node) {
// Make sure arithmetic integer operators don't emit doubles outside the
// integer range. Allowing this causes JIT slowdowns due to extra checks
// during compilation and potential deoptimizations during execution.
// Special-case the integer "%" operator where the right operand may be
// "0" since that generates "NaN" which is not representable as an int.
if (node.resolvedType == this._cache.intType && !Skew.JavaScriptEmitter._alwaysConvertsOperandsToInt(node.parent()) && (node.kind != Skew.NodeKind.REMAINDER && node.kind != Skew.NodeKind.UNSIGNED_SHIFT_RIGHT || !node.binaryRight().isInt() || node.binaryRight().asInt() == 0)) {
var left = node.binaryLeft();
var right = node.binaryRight();
if (left.resolvedType == this._cache.intType && right.resolvedType == this._cache.intType) {
node.become(this._createIntBinary(node.kind, left.remove(), right.remove()).withRange(node.range));
}
}
};
Skew.JavaScriptEmitter.prototype._patchTypeCheck = function(node) {
var value = node.typeCheckValue();
var type = this._cache.unwrappedType(node.typeCheckType().resolvedType);
if (type == this._cache.boolType) {
node.become(Skew.Node.createSymbolCall(this._specialVariable(Skew.JavaScriptEmitter.SpecialVariable.IS_BOOL)).appendChild(value.remove()));
}
else if (this._cache.isInteger(type)) {
node.become(Skew.Node.createSymbolCall(this._specialVariable(Skew.JavaScriptEmitter.SpecialVariable.IS_INT)).appendChild(value.remove()));
}
else if (type == this._cache.doubleType) {
node.become(Skew.Node.createSymbolCall(this._specialVariable(Skew.JavaScriptEmitter.SpecialVariable.IS_DOUBLE)).appendChild(value.remove()));
}
else if (type == this._cache.stringType) {
node.become(Skew.Node.createSymbolCall(this._specialVariable(Skew.JavaScriptEmitter.SpecialVariable.IS_STRING)).appendChild(value.remove()));
}
else if (type.kind == Skew.TypeKind.LAMBDA) {
node.typeCheckType().replaceWith(new Skew.Node(Skew.NodeKind.NAME).withContent(new Skew.StringContent('Function')).withType(Skew.Type.DYNAMIC));
}
};
// Group each variable inside the function with the function itself so that
// they can be renamed together and won't cause any collisions inside the
// function
Skew.JavaScriptEmitter.prototype._unionVariableWithFunction = function(symbol, $function) {
if (this._mangle && $function != null) {
assert(this._namingGroupIndexForSymbol.has(symbol.id));
assert(this._namingGroupIndexForSymbol.has($function.id));
this._localVariableUnionFind.union(in_IntMap.get1(this._namingGroupIndexForSymbol, symbol.id), in_IntMap.get1(this._namingGroupIndexForSymbol, $function.id));
}
};
Skew.JavaScriptEmitter.prototype._patchNode = function(node) {
if (node == null) {
return;
}
var oldEnclosingFunction = this._enclosingFunction;
var oldLoop = this._enclosingLoop;
var symbol = node.symbol;
var kind = node.kind;
if (this._mangle && symbol != null) {
this._allocateNamingGroupIndex(symbol);
in_IntMap.set(this._symbolCounts, symbol.id, in_IntMap.get(this._symbolCounts, symbol.id, 0) + 1 | 0);
}
if (kind == Skew.NodeKind.LAMBDA) {
this._enclosingFunction = symbol.asFunctionSymbol();
}
else if (Skew.in_NodeKind.isLoop(kind)) {
this._enclosingLoop = node;
}
if (kind == Skew.NodeKind.CAST) {
this._patchNode(node.castValue());
}
else {
for (var child = node.firstChild(); child != null; child = child.nextSibling()) {
this._patchNode(child);
}
}
if (kind == Skew.NodeKind.LAMBDA) {
this._enclosingFunction = oldEnclosingFunction;
}
else if (Skew.in_NodeKind.isLoop(kind)) {
this._enclosingLoop = oldLoop;
}
// Split this into a separate function because this function is hot and V8 doesn't
// optimize it otherwise (it's optimized "too many times" whatever that means)
this._patchNodeHelper(node);
};
Skew.JavaScriptEmitter.prototype._patchNodeHelper = function(node) {
switch (node.kind) {
case Skew.NodeKind.ADD:
case Skew.NodeKind.SUBTRACT:
case Skew.NodeKind.MULTIPLY:
case Skew.NodeKind.DIVIDE:
case Skew.NodeKind.REMAINDER:
case Skew.NodeKind.UNSIGNED_SHIFT_RIGHT: {
this._patchBinaryArithmetic(node);
break;
}
case Skew.NodeKind.BREAK: {
this._patchBreak(node);
break;
}
case Skew.NodeKind.CAST: {
this._patchCast(node);
break;
}
case Skew.NodeKind.FOREACH: {
this._unionVariableWithFunction(node.symbol, this._enclosingFunction);
break;
}
case Skew.NodeKind.LAMBDA: {
this._patchLambda(node);
break;
}
case Skew.NodeKind.NAME: {
this._patchName(node);
break;
}
case Skew.NodeKind.NEGATIVE: {
this._patchUnaryArithmetic(node);
break;
}
case Skew.NodeKind.TRY: {
this._patchTry(node);
break;
}
case Skew.NodeKind.TYPE_CHECK: {
this._patchTypeCheck(node);
break;
}
case Skew.NodeKind.VARIABLE: {
this._unionVariableWithFunction(node.symbol, this._enclosingFunction);
break;
}
}
if (this._mangle) {
switch (node.kind) {
case Skew.NodeKind.ASSIGN_INDEX: {
this._peepholeMangleAssignIndex(node);
break;
}
case Skew.NodeKind.BLOCK: {
this._peepholeMangleBlock(node);
break;
}
case Skew.NodeKind.CALL: {
this._peepholeMangleCall(node);
break;
}
case Skew.NodeKind.CONSTANT: {
this._peepholeMangleConstant(node);
break;
}
case Skew.NodeKind.FOR: {
this._peepholeMangleFor(node);
break;
}
case Skew.NodeKind.HOOK: {
this._peepholeMangleHook(node);
break;
}
case Skew.NodeKind.IF: {
this._peepholeMangleIf(node);
break;
}
case Skew.NodeKind.INDEX: {
this._peepholeMangleIndex(node);
break;
}
case Skew.NodeKind.PAIR: {
this._peepholeManglePair(node);
break;
}
case Skew.NodeKind.WHILE: {
this._peepholeMangleWhile(node);
break;
}
default: {
if (Skew.in_NodeKind.isBinary(node.kind)) {
this._peepholeMangleBinary(node);
}
break;
}
}
}
};
Skew.JavaScriptEmitter.prototype._peepholeManglePair = function(node) {
if (Skew.JavaScriptEmitter._isIdentifierString(node.firstValue())) {
node.firstValue().kind = Skew.NodeKind.NAME;
}
};
Skew.JavaScriptEmitter.prototype._peepholeMangleConstant = function(node) {
switch (node.content.kind()) {
case Skew.ContentKind.BOOL: {
node.become(this._wrapWithNot(this._cache.createInt(node.asBool() ? 0 : 1).withRange(node.range)));
break;
}
case Skew.ContentKind.INT: {
var value = node.asInt();
// "-2147483648" => "1 << 31"
if (value != 0) {
var count = value.toString().length;
var shift = 0;
// Count zero bits
while ((value & 1) == 0) {
value >>>= 1;
shift = shift + 1 | 0;
}
// Do the substitution if it makes sense
gitextract_luug_bnx/
├── .gitignore
├── .travis.yml
├── LICENSE
├── README.md
├── build.py
├── docs/
│ └── compiler.md
├── extras/
│ ├── Atom/
│ │ └── README.md
│ └── Sublime Text/
│ ├── README.md
│ └── Skew/
│ ├── Comments.tmPreferences
│ ├── Skew.sublime-completions
│ └── Skew.tmLanguage
├── npm/
│ ├── README
│ └── package.json
├── package.json
├── skewc.js
├── src/
│ ├── backend/
│ │ ├── cplusplus.sk
│ │ ├── csharp.sk
│ │ ├── emitter.sk
│ │ ├── javascript.sk
│ │ ├── lisptree.sk
│ │ ├── sourcemap.sk
│ │ └── typescript.sk
│ ├── core/
│ │ ├── content.sk
│ │ ├── node.sk
│ │ ├── operators.sk
│ │ ├── support.sk
│ │ └── symbol.sk
│ ├── cpp/
│ │ ├── fast.cpp
│ │ ├── skew.cpp
│ │ ├── skew.h
│ │ ├── support.cpp
│ │ └── support.h
│ ├── driver/
│ │ ├── jsapi.d.ts
│ │ ├── jsapi.sk
│ │ ├── options.sk
│ │ ├── terminal.sk
│ │ └── tests.sk
│ ├── frontend/
│ │ ├── flex.l
│ │ ├── flex.py
│ │ ├── lexer.py
│ │ ├── lexer.sk
│ │ ├── log.sk
│ │ ├── parser.sk
│ │ ├── pratt.sk
│ │ ├── range.sk
│ │ ├── source.sk
│ │ ├── token.sk
│ │ └── version.sk
│ ├── lib/
│ │ ├── build.sk
│ │ ├── io.sk
│ │ ├── terminal.sk
│ │ ├── timestamp.sk
│ │ └── unit.sk
│ └── middle/
│ ├── callgraph.sk
│ ├── compiler.sk
│ ├── controlflow.sk
│ ├── folding.sk
│ ├── globalizing.sk
│ ├── ide.sk
│ ├── inlining.sk
│ ├── interfaceremoval.sk
│ ├── lambdaconversion.sk
│ ├── library.sk
│ ├── librarycpp.sk
│ ├── librarycs.sk
│ ├── libraryjs.sk
│ ├── merging.sk
│ ├── motion.sk
│ ├── renaming.sk
│ ├── resolving.sk
│ ├── scope.sk
│ ├── shaking.sk
│ ├── type.sk
│ ├── typecache.sk
│ └── unicode.sk
├── tests/
│ ├── cplusplus.sk
│ ├── csharp.sk
│ ├── formatting.sk
│ ├── ide.sk
│ ├── javascript.mangle.sk
│ ├── javascript.minify.sk
│ ├── javascript.sk
│ ├── library.sk
│ ├── node.sk
│ ├── other.sk
│ ├── parsing.sk
│ ├── simple.sk
│ └── unicode.sk
└── www/
├── benchmark.html
├── index.html
├── index.js
└── style.css
SYMBOL INDEX (116 symbols across 11 files)
FILE: build.py
function job (line 69) | def job(fn):
function run (line 73) | def run(args, exit_on_failure=True, **kwargs):
function watch_folder (line 96) | def watch_folder(folder, callback):
function load_version (line 117) | def load_version():
function update_version (line 120) | def update_version(version):
function check_same (line 123) | def check_same(a, b):
function mkdir (line 126) | def mkdir(path):
function rmtree (line 132) | def rmtree(path):
function run_js (line 138) | def run_js(source, args, exit_on_failure=True):
function run_cs (line 146) | def run_cs(source, args):
function run_cpp (line 149) | def run_cpp(source, args):
function skewc_js (line 152) | def skewc_js(source, target, sources=SOURCES, build='SKEWC', release=Fal...
function skewc_cs (line 155) | def skewc_cs(source, target, sources=SOURCES, build='SKEWC', release=Fal...
function skewc_cpp (line 158) | def skewc_cpp(source, target, sources=SOURCES, build='SKEWC', release=Fa...
function compile_cs (line 161) | def compile_cs(sources, target):
function compile_cpp (line 164) | def compile_cpp(source, target, release=False, gc=False):
function default (line 170) | def default():
function clean (line 176) | def clean():
function replace (line 180) | def replace():
function check (line 191) | def check():
function check_js (line 197) | def check_js():
function check_cs (line 205) | def check_cs():
function check_cpp (line 219) | def check_cpp():
function check_determinism (line 238) | def check_determinism():
function test (line 261) | def test():
function test_js (line 267) | def test_js():
function test_cs (line 280) | def test_cs():
function test_cpp (line 297) | def test_cpp():
function benchmark (line 317) | def benchmark():
function watch (line 323) | def watch():
function flex (line 328) | def flex():
function publish (line 332) | def publish():
function main (line 350) | def main(args):
FILE: skewc.js
function __extends (line 6) | function __extends(derived, base) {
function assert (line 15) | function assert(truth) {
function StringBuilder (line 26) | function StringBuilder() {
function Box (line 30) | function Box(value) {
FILE: src/cpp/fast.cpp
function free (line 53) | void free(void *data) {}
FILE: src/cpp/skew.cpp
function __MurmurHash3 (line 288) | static uint64_t __MurmurHash3(uint64_t h) {
function __doubleToString (line 357) | Skew::string __doubleToString(double value) {
function __intToString (line 376) | Skew::string __intToString(int x) {
type Delete (line 391) | enum class Delete {
type Skew (line 397) | namespace Skew {
type Internal (line 398) | struct Internal {
method Object (line 402) | static Object *next(Object *object) { return object->__gc_next; }
type DeleteLater (line 411) | struct DeleteLater {
function startParallelCollection (line 424) | static void startParallelCollection() {
type Check (line 453) | enum class Check {
function checkParallelCollection (line 458) | static void checkParallelCollection(Check mode) {
FILE: src/cpp/skew.h
function namespace (line 5) | namespace Skew {
function UntypedRoot (line 38) | UntypedRoot(object) {}
function T (line 39) | T *get() const { return dynamic_cast<T *>(_object); }
function namespace (line 48) | namespace GC {
function namespace (line 63) | namespace Skew {
function namespace (line 94) | namespace Skew {
type Fn8 (line 180) | struct Fn8
type FnVoid9 (line 185) | struct FnVoid9
type Fn9 (line 190) | struct Fn9
type FnVoid10 (line 195) | struct FnVoid10
function namespace (line 207) | namespace Skew {
function namespace (line 260) | namespace std {
function namespace (line 271) | namespace Skew {
function namespace (line 289) | namespace Skew {
function bool (line 298) | struct CharInsteadOfBool<bool> {
function cast (line 302) | static const bool &cast(const char &x) { return reinterpret_cast<const b...
function count (line 390) | int count() const;
FILE: src/cpp/support.cpp
type stat (line 36) | struct stat
type __TerminalInfo (line 67) | struct __TerminalInfo {
function __TerminalInfo (line 80) | static __TerminalInfo &__getTerminalInfo() {
function parseDoubleLiteral (line 175) | double parseDoubleLiteral(const Skew::string &x) {
FILE: src/cpp/support.h
function namespace (line 1) | namespace Skew {
function namespace (line 8) | namespace IO {
function namespace (line 15) | namespace Terminal {
function namespace (line 24) | namespace Timestamp {
FILE: src/driver/jsapi.d.ts
type SymbolKind (line 2) | type SymbolKind =
type Source (line 30) | interface Source {
type Range (line 35) | interface Range {
type Location (line 41) | interface Location {
type CompilerOptions (line 46) | interface CompilerOptions {
type CompileReq (line 64) | interface CompileReq extends CompilerOptions {
type CompileRes (line 69) | interface CompileRes {
type Log (line 76) | interface Log {
type Diagnostic (line 81) | interface Diagnostic {
type Fix (line 88) | interface Fix {
type TooltipReq (line 98) | interface TooltipReq {
type TooltipRes (line 107) | interface TooltipRes {
type DefinitionQueryReq (line 118) | interface DefinitionQueryReq {
type DefinitionQueryRes (line 126) | interface DefinitionQueryRes {
type SymbolsQueryReq (line 137) | interface SymbolsQueryReq {
type SymbolsQueryRes (line 144) | interface SymbolsQueryRes {
type Symbol (line 150) | interface Symbol {
type RenameQueryReq (line 160) | interface RenameQueryReq {
type RenameQueryRes (line 168) | interface RenameQueryRes {
type CompletionQueryReq (line 177) | interface CompletionQueryReq extends CompilerOptions {
type CompletionQueryRes (line 185) | interface CompletionQueryRes {
type Completion (line 193) | interface Completion {
type SignatureQueryReq (line 202) | interface SignatureQueryReq {
type SignatureQueryRes (line 210) | interface SignatureQueryRes {
type Compiler (line 221) | interface Compiler {
type Req (line 232) | type Req =
type Res (line 241) | type Res =
FILE: src/frontend/flex.py
function _run_flex (line 7) | def _run_flex(source):
function _find_array (line 20) | def _find_array(source, name):
function _find_magic_number (line 24) | def _find_magic_number(source, pattern):
function _find_actions (line 28) | def _find_actions(source):
function compile (line 32) | def compile(source):
FILE: src/frontend/lexer.py
function create_table (line 28) | def create_table(result, name, type=None):
FILE: www/index.js
function configGetBool (line 40) | function configGetBool(name) {
function configGet (line 44) | function configGet(name) {
function configSet (line 48) | function configSet(name, index) {
function now (line 52) | function now() {
function handleResult (line 56) | function handleResult(result) {
function update (line 63) | function update() {
function createSelect (line 109) | function createSelect(values, name) {
function createCheckbox (line 124) | function createCheckbox(label, name) {
function main (line 138) | function main() {
Condensed preview — 92 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (2,557K chars).
[
{
"path": ".gitignore",
"chars": 102,
"preview": ".DS_Store\n*.pyc\n/node_modules/\n/out/\n/npm/skew.js\n/npm/skewc\n/npm/skew.cpp\n/npm/skew.h\n/npm/skew.d.ts\n"
},
{
"path": ".travis.yml",
"chars": 38,
"preview": "language: node_js\nnode_js:\n - stable\n"
},
{
"path": "LICENSE",
"chars": 1057,
"preview": "Copyright (c) 2015 Evan Wallace\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this so"
},
{
"path": "README.md",
"chars": 128,
"preview": "# Skew Programming Language\n\nVisit https://evanw.github.io/skew-lang.org/ for more information and a live demo of the co"
},
{
"path": "build.py",
"chars": 9683,
"preview": "#!/usr/bin/env python\n\nimport os\nimport sys\nimport glob\nimport gzip\nimport json\nimport time\nimport pipes\nimport base64\ni"
},
{
"path": "docs/compiler.md",
"chars": 5576,
"preview": "# Compiler\n\nThis documents the internals of the compiler.\n\n## Development\n\nDevelopment on the compiler itself is straigh"
},
{
"path": "extras/Atom/README.md",
"chars": 217,
"preview": "# Atom Syntax Definitions for Skew\n\nRun `apm install skew` to install syntax highlighting for the [Atom editor](https://"
},
{
"path": "extras/Sublime Text/README.md",
"chars": 705,
"preview": "# Sublime Text Syntax Definitions for Skew\n\n## Installing\nTo install, copy the \"Skew\" folder into the appropriate locati"
},
{
"path": "extras/Sublime Text/Skew/Comments.tmPreferences",
"chars": 526,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
},
{
"path": "extras/Sublime Text/Skew/Skew.sublime-completions",
"chars": 1508,
"preview": "{\n \"scope\": \"source.skew\",\n \"completions\": [\n { \"trigger\": \"as\", \"contents\": \"as\" },\n { \"trigger\": \"break\", \"con"
},
{
"path": "extras/Sublime Text/Skew/Skew.tmLanguage",
"chars": 3656,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
},
{
"path": "npm/README",
"chars": 71,
"preview": "See [http://skew-lang.org](http://skew-lang.org) for more information.\n"
},
{
"path": "npm/package.json",
"chars": 326,
"preview": "{\n \"name\": \"skew\",\n \"version\": \"0.9.19\",\n \"author\": \"Evan Wallace\",\n \"description\": \"A compiler for the Skew program"
},
{
"path": "package.json",
"chars": 61,
"preview": "{\n \"scripts\": {\n \"test\": \"python build.py test_js\"\n }\n}\n"
},
{
"path": "skewc.js",
"chars": 1008920,
"preview": "(function() {\n var __create = Object.create ? Object.create : function(prototype) {\n return {'__proto__': prototype}"
},
{
"path": "src/backend/cplusplus.sk",
"chars": 40581,
"preview": "namespace Skew {\n class CPlusPlusTarget : CompilerTarget {\n over name string { return \"C++\" }\n over extension str"
},
{
"path": "src/backend/csharp.sk",
"chars": 35166,
"preview": "namespace Skew {\n class CSharpTarget : CompilerTarget {\n over name string { return \"C#\" }\n over extension string "
},
{
"path": "src/backend/emitter.sk",
"chars": 5835,
"preview": "namespace Skew {\n enum PassKind {\n EMITTING\n }\n\n class EmittingPass : Pass {\n over kind PassKind {\n return"
},
{
"path": "src/backend/javascript.sk",
"chars": 104911,
"preview": "namespace Skew {\n class JavaScriptTarget : CompilerTarget {\n over name string { return \"JavaScript\" }\n over exten"
},
{
"path": "src/backend/lisptree.sk",
"chars": 3553,
"preview": "namespace Skew {\n class LispTreeTarget : CompilerTarget {\n over name string { return \"S-expression\" }\n over exten"
},
{
"path": "src/backend/sourcemap.sk",
"chars": 4215,
"preview": "namespace Skew {\n class SourceMapping {\n const sourceIndex int\n const originalLine int # 0-based\n const origin"
},
{
"path": "src/backend/typescript.sk",
"chars": 55643,
"preview": "namespace Skew {\n class TypeScriptTarget : CompilerTarget {\n over name string { return \"TypeScript\" }\n over exten"
},
{
"path": "src/core/content.sk",
"chars": 1358,
"preview": "namespace Skew {\n enum ContentKind {\n BOOL\n INT\n DOUBLE\n STRING\n }\n\n interface Content {\n def kind Con"
},
{
"path": "src/core/node.sk",
"chars": 43112,
"preview": "namespace Skew {\n enum NodeKind {\n # Other\n ANNOTATION\n BLOCK\n CASE\n CATCH\n VARIABLE\n\n # Statement"
},
{
"path": "src/core/operators.sk",
"chars": 6211,
"preview": "namespace Skew {\n class OperatorInfo {\n const text string\n const precedence Precedence\n const associativity As"
},
{
"path": "src/core/support.sk",
"chars": 6502,
"preview": "namespace Skew {\n const SORT_STRINGS = (a string, b string) => a <=> b\n\n def hashCombine(left int, right int) int {\n "
},
{
"path": "src/core/symbol.sk",
"chars": 14418,
"preview": "namespace Skew {\n enum SymbolKind {\n PARAMETER_FUNCTION\n PARAMETER_OBJECT\n\n OBJECT_CLASS\n OBJECT_ENUM\n O"
},
{
"path": "src/cpp/fast.cpp",
"chars": 1496,
"preview": "#include <assert.h>\n\n#if _WIN32\n #include <windows.h>\n#else\n #include <sys/mman.h>\n#endif\n\nstatic void *__fast_next;\ns"
},
{
"path": "src/cpp/skew.cpp",
"chars": 15683,
"preview": "#include <math.h>\n#include <string.h>\n\n#if _WIN32\n #include <windows.h>\n #undef max\n #undef min\n#else\n #include <sys"
},
{
"path": "src/cpp/skew.h",
"chars": 24637,
"preview": "#ifdef SKEW_GC_MARK_AND_SWEEP\n\n #include <type_traits>\n\n namespace Skew {\n struct Internal;\n\n struct Object {\n "
},
{
"path": "src/cpp/support.cpp",
"chars": 4972,
"preview": "#include <fstream>\n#include <iostream>\n#include <sstream>\n\n#ifdef _WIN32\n #include <windows.h>\n#else\n #include <dirent"
},
{
"path": "src/cpp/support.h",
"chars": 615,
"preview": "namespace Skew {\n struct string;\n\n template <typename T>\n struct List;\n}\n\nnamespace IO {\n Skew::string readFile(cons"
},
{
"path": "src/driver/jsapi.d.ts",
"chars": 5525,
"preview": "declare module \"skew\" {\n export type SymbolKind =\n | \"PARAMETER_FUNCTION\"\n | \"PARAMETER_OBJECT\"\n\n | \"OBJECT_CL"
},
{
"path": "src/driver/jsapi.sk",
"chars": 13029,
"preview": "namespace Skew.API {\n def sourcesToJSON(sources List<Source>) dynamic {\n return sources.map<dynamic>(source => {\n "
},
{
"path": "src/driver/options.sk",
"chars": 8414,
"preview": "namespace Skew {\n class Log {\n def commandLineWarningDuplicateFlagValue(range Range, name string, previous Range) {\n"
},
{
"path": "src/driver/terminal.sk",
"chars": 16401,
"preview": "namespace Skew {\n enum Option {\n DEFINE\n FIX_ALL\n FOLD_CONSTANTS\n GC_STRATEGY\n GLOBALIZE_FUNCTIONS\n H"
},
{
"path": "src/driver/tests.sk",
"chars": 11708,
"preview": "namespace Skew.Tests {\n class CompilerTest : Unit.Test {\n var _input string\n var _expected string\n var _option"
},
{
"path": "src/frontend/flex.l",
"chars": 4814,
"preview": "%%\n\n\\n[ \\t\\r]* NEWLINE;\n[ \\t\\r]+ WHITESPACE;\n#.*? "
},
{
"path": "src/frontend/flex.py",
"chars": 2078,
"preview": "import os\nimport re\nimport sys\nimport tempfile\nimport subprocess\n\ndef _run_flex(source):\n fd, path = tempfile.mkstemp()"
},
{
"path": "src/frontend/lexer.py",
"chars": 2356,
"preview": "import os\nimport flex\n\ntemplate = '''\n################################################################################\n#"
},
{
"path": "src/frontend/lexer.sk",
"chars": 11265,
"preview": "################################################################################\n#\n# This is a generated file, all edits"
},
{
"path": "src/frontend/log.sk",
"chars": 33786,
"preview": "namespace Skew {\n enum DiagnosticKind {\n ERROR\n WARNING\n }\n\n class Fix {\n const kind FixKind\n const range"
},
{
"path": "src/frontend/parser.sk",
"chars": 66842,
"preview": "namespace Skew {\n enum PassKind {\n PARSING\n }\n\n class ParsingPass : Pass {\n over kind PassKind {\n return ."
},
{
"path": "src/frontend/pratt.sk",
"chars": 6225,
"preview": "namespace Skew {\n # The same operator precedence as C for the most part\n enum Precedence {\n LOWEST\n COMMA\n AS"
},
{
"path": "src/frontend/range.sk",
"chars": 5068,
"preview": "namespace Skew {\n class FormattedRange {\n var line string\n var range string\n }\n\n class Range {\n const source"
},
{
"path": "src/frontend/source.sk",
"chars": 1971,
"preview": "namespace Skew {\n class LineColumn {\n var line int # 0-based index\n var column int # 0-based index\n }\n\n class S"
},
{
"path": "src/frontend/token.sk",
"chars": 16613,
"preview": "namespace Skew {\n enum PassKind {\n LEXING\n }\n\n class LexingPass : Pass {\n over kind PassKind {\n return .LE"
},
{
"path": "src/frontend/version.sk",
"chars": 46,
"preview": "namespace Skew {\n const VERSION = \"0.9.19\"\n}\n"
},
{
"path": "src/lib/build.sk",
"chars": 63,
"preview": "enum Build {\n SKEWC\n API\n TEST\n}\n\nconst BUILD = Build.SKEWC\n"
},
{
"path": "src/lib/io.sk",
"chars": 2293,
"preview": "if TARGET == .JAVASCRIPT {\n namespace IO {\n def isDirectory(path string) bool {\n try {\n return dynamic.r"
},
{
"path": "src/lib/terminal.sk",
"chars": 2320,
"preview": "namespace Terminal {\n enum Color {\n DEFAULT\n BOLD\n GRAY\n RED\n GREEN\n YELLOW\n BLUE\n MAGENTA\n "
},
{
"path": "src/lib/timestamp.sk",
"chars": 459,
"preview": "namespace Timestamp {\n if TARGET == .JAVASCRIPT {\n def seconds double {\n return (dynamic.typeof(dynamic.perform"
},
{
"path": "src/lib/unit.sk",
"chars": 6089,
"preview": "namespace Unit {\n enum Status {\n FAILURE\n SUCCESS\n SKIPPED\n }\n\n class Report {\n def begin(count int) {}\n "
},
{
"path": "src/middle/callgraph.sk",
"chars": 1944,
"preview": "namespace Skew {\n enum PassKind {\n CALL_GRAPH\n }\n\n class CallGraphPass : Pass {\n over kind PassKind {\n ret"
},
{
"path": "src/middle/compiler.sk",
"chars": 11900,
"preview": "namespace Skew {\n class CompilerTarget {\n def name string { return \"\" }\n def extension string { return \"\" }\n d"
},
{
"path": "src/middle/controlflow.sk",
"chars": 3143,
"preview": "namespace Skew {\n # This does a simple control flow analysis without constructing a full\n # control flow graph. The re"
},
{
"path": "src/middle/folding.sk",
"chars": 37757,
"preview": "namespace Skew {\n enum PassKind {\n FOLDING\n }\n\n class FoldingPass : Pass {\n over kind PassKind {\n return ."
},
{
"path": "src/middle/globalizing.sk",
"chars": 3129,
"preview": "namespace Skew {\n enum PassKind {\n GLOBALIZING\n }\n\n class GlobalizingPass : Pass {\n over kind PassKind {\n "
},
{
"path": "src/middle/ide.sk",
"chars": 17670,
"preview": "namespace Skew.IDE {\n class SymbolQuery {\n const source Source\n const index int\n\n var resolvedType Type = null"
},
{
"path": "src/middle/inlining.sk",
"chars": 12174,
"preview": "namespace Skew {\n enum PassKind {\n INLINING\n }\n\n class InliningPass : Pass {\n over kind PassKind {\n return"
},
{
"path": "src/middle/interfaceremoval.sk",
"chars": 2042,
"preview": "namespace Skew {\n enum PassKind {\n INTERFACE_REMOVAL\n }\n\n class InterfaceRemovalPass : Pass {\n const _interface"
},
{
"path": "src/middle/lambdaconversion.sk",
"chars": 20990,
"preview": "namespace Skew {\n enum PassKind {\n LAMBDA_CONVERSION\n }\n\n class LambdaConversionPass : Pass {\n over kind PassKi"
},
{
"path": "src/middle/library.sk",
"chars": 9593,
"preview": "namespace Skew {\n const NATIVE_LIBRARY = \"\nconst RELEASE = false\nconst ASSERTS = !RELEASE\n\nenum Target {\n NONE\n CPLUS"
},
{
"path": "src/middle/librarycpp.sk",
"chars": 1233,
"preview": "namespace Skew {\n const NATIVE_LIBRARY_CPP = \"\n@import {\n def __doubleToString(x double) string\n def __intToString(x "
},
{
"path": "src/middle/librarycs.sk",
"chars": 8409,
"preview": "namespace Skew {\n const NATIVE_LIBRARY_CS = \"\n@using(\\\"System.Diagnostics\\\")\ndef assert(truth bool) {\n dynamic.Debug.A"
},
{
"path": "src/middle/libraryjs.sk",
"chars": 11336,
"preview": "namespace Skew {\n const NATIVE_LIBRARY_JS = \"\nconst __create fn(dynamic) dynamic = dynamic.Object.create ? dynamic.Obje"
},
{
"path": "src/middle/merging.sk",
"chars": 6982,
"preview": "namespace Skew {\n enum PassKind {\n MERGING\n }\n\n class MergingPass : Pass {\n over kind PassKind {\n return ."
},
{
"path": "src/middle/motion.sk",
"chars": 3949,
"preview": "namespace Skew {\n enum PassKind {\n MOTION\n }\n\n class MotionPass : Pass {\n over kind PassKind {\n return .MO"
},
{
"path": "src/middle/renaming.sk",
"chars": 6527,
"preview": "namespace Skew {\n enum PassKind {\n RENAMING\n }\n\n class RenamingPass : Pass {\n over kind PassKind {\n return"
},
{
"path": "src/middle/resolving.sk",
"chars": 145702,
"preview": "namespace Skew {\n enum PassKind {\n RESOLVING\n }\n\n class ResolvingPass : Pass {\n over kind PassKind {\n retu"
},
{
"path": "src/middle/scope.sk",
"chars": 5865,
"preview": "namespace Skew {\n enum ScopeKind {\n FUNCTION\n LOCAL\n OBJECT\n VARIABLE\n }\n\n enum ScopeSearch {\n NORMAL\n"
},
{
"path": "src/middle/shaking.sk",
"chars": 9934,
"preview": "namespace Skew {\n enum ShakingMode {\n USE_TYPES\n IGNORE_TYPES\n }\n\n # Remove all code that isn't reachable from "
},
{
"path": "src/middle/type.sk",
"chars": 3302,
"preview": "namespace Skew {\n enum TypeKind {\n LAMBDA\n SPECIAL\n SYMBOL\n }\n\n class Type {\n const id = _createID\n va"
},
{
"path": "src/middle/typecache.sk",
"chars": 19097,
"preview": "namespace Skew {\n class TypeCache {\n var boolType Type = null\n var boxType Type = null\n var doubleType Type = "
},
{
"path": "src/middle/unicode.sk",
"chars": 5173,
"preview": "namespace Skew {\n const UNICODE_LIBRARY = \"\nnamespace Unicode {\n enum Encoding {\n UTF8\n UTF16\n UTF32\n }\n\n c"
},
{
"path": "tests/cplusplus.sk",
"chars": 32322,
"preview": "namespace Skew.Tests {\n def testCPlusPlus {\n\n# Test entry point\ntest(\"\n@entry\ndef test {}\n\", \"\nvoid main() {\n}\n\").cpp\n\n"
},
{
"path": "tests/csharp.sk",
"chars": 16141,
"preview": "namespace Skew.Tests {\n def testCSharp {\n\n# Test entry point\ntest(\"\n@entry\ndef test {}\n\", \"\npublic class Globals\n{\n "
},
{
"path": "tests/formatting.sk",
"chars": 1590,
"preview": "namespace Skew.Tests {\n def testFormatting {\n\ntestFormat(\"\n01234abcde56789\n\", \"\n01234abcde56789\n ~~~~~\n\", 5, 10, 15"
},
{
"path": "tests/ide.sk",
"chars": 23684,
"preview": "namespace Skew.Tests {\n def testIDE {\n\n# Tooltips: basic test of globals and formatting\ntestIDE(\"\ndef @annotation ( x i"
},
{
"path": "tests/javascript.mangle.sk",
"chars": 44077,
"preview": "namespace Skew.Tests {\n def testJavaScriptMangle {\n\n# Test falsy values\ntest(\"\nclass Foo {\n}\n\n@entry\ndef main {\n var i"
},
{
"path": "tests/javascript.minify.sk",
"chars": 5514,
"preview": "namespace Skew.Tests {\n def testJavaScriptMinify {\n\n# Strings should be emitted using the shortest representation\ntest("
},
{
"path": "tests/javascript.sk",
"chars": 59982,
"preview": "namespace Skew.Tests {\n def testJavaScript {\n\n# Check special cases for keyword operators\ntest(\"\n@entry\ndef main {\n dy"
},
{
"path": "tests/library.sk",
"chars": 33576,
"preview": "namespace Skew.Tests {\n def testLibrary {\n testExpect(\"sanity check\", => toString([1, 2, 3]), \"[1, 2, 3]\")\n testE"
},
{
"path": "tests/node.sk",
"chars": 13605,
"preview": "enum Skew.NodeKind {\n A\n B\n C\n D\n E\n F\n G\n}\n\nnamespace Skew.Tests {\n def testNode {\n var visit fn(Node)\n\n "
},
{
"path": "tests/other.sk",
"chars": 4248,
"preview": "namespace Skew.Tests {\n def testLevenshteinEditDistance {\n var check = (a string, b string, expected double) => {\n "
},
{
"path": "tests/parsing.sk",
"chars": 41022,
"preview": "namespace Skew.Tests {\n def testParsing {\n\ntest(\"\nvar x = ''\nvar y = '1'\nvar z = '12'\n\", \"\n<stdin>:1:9: error: Use doub"
},
{
"path": "tests/simple.sk",
"chars": 188800,
"preview": "namespace Skew.Tests {\n def testSimple {\n\ntest(\"\nvar foo Foo<dynamic> = null\n\", \"\n<stdin>:1:9: error: \\\"Foo\\\" is not de"
},
{
"path": "tests/unicode.sk",
"chars": 2673,
"preview": "namespace Skew.Tests {\n def testUnicodeText(text string, codePoints List<int>) {\n test(\"codePoints \" + text, expectS"
},
{
"path": "www/benchmark.html",
"chars": 4008,
"preview": "<canvas width=\"800\" height=\"600\" style=\"background:#EEE;\"></canvas>\n<script>\n\n(function() {\n\n function draw(context, ti"
},
{
"path": "www/index.html",
"chars": 597,
"preview": "<title>Skew Compiler</title>\n<link rel=\"stylesheet\" href=\"style.css\">\n<div>\n <h2>Input</h2>\n <textarea id=\"input\" rows"
},
{
"path": "www/index.js",
"chars": 5559,
"preview": "(function() {\n\n var compileTime = document.getElementById('compileTime');\n var input = document.getElementById('input'"
},
{
"path": "www/style.css",
"chars": 481,
"preview": "body {\n font: 12px/15px 'Lucida Grande', sans-serif;\n margin: 20px;\n}\n\ntextarea {\n font: 12px Monaco, monospace;\n wi"
}
]
About this extraction
This page contains the full source code of the evanw/skew GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 92 files (2.3 MB), approximately 615.0k tokens, and a symbol index with 116 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.