gecko-dev/js/tamarin/esc/parser.as

6122 строки
189 KiB
ActionScript
Исходник Ответственный История

/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version 1.1 (the
* "License"); you may not use this file except in compliance with the License. You may obtain
* a copy of the License at http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis, WITHOUT
* WARRANTY OF ANY KIND, either express or implied. See the License for the specific
* language governing rights and limitations under the License.
*
* The Original Code is [Open Source Virtual Machine.]
*
* The Initial Developer of the Original Code is Adobe System Incorporated. Portions created
* by the Initial Developer are Copyright (C)[ 2004-2006 ] Adobe Systems Incorporated. All Rights
* Reserved.
*
* Contributor(s): Adobe AS3 Team
*
* Alternatively, the contents of this file may be used under the terms of either the GNU
* General Public License Version 2 or later (the "GPL"), or the GNU Lesser General Public
* License Version 2.1 or later (the "LGPL"), in which case the provisions of the GPL or the
* LGPL are applicable instead of those above. If you wish to allow use of your version of this
* file only under the terms of either the GPL or the LGPL, and not to allow others to use your
* version of this file under the terms of the MPL, indicate your decision by deleting provisions
* above and replace them with the notice and other provisions required by the GPL or the
* LGPL. If you do not delete the provisions above, a recipient may use your version of this file
* under the terms of any one of the MPL, the GPL or the LGPL.
*
***** END LICENSE BLOCK ***** */
package es4
{
use namespace release
public const first_token = -1
public const eos_token = first_token-0
public const minus_token = first_token - 1
public const minusminus_token = minus_token - 1
public const not_token = minusminus_token - 1
public const notequals_token = not_token - 1
public const strictnotequals_token = notequals_token - 1
public const modulus_token = strictnotequals_token - 1
public const modulusassign_token = modulus_token - 1
public const bitwiseand_token = modulusassign_token - 1
public const logicaland_token = bitwiseand_token - 1
public const logicalandassign_token = logicaland_token - 1
public const bitwiseandassign_token = logicalandassign_token - 1
public const leftparen_token = bitwiseandassign_token - 1
public const rightparen_token = leftparen_token - 1
public const mult_token = rightparen_token - 1
public const multassign_token = mult_token - 1
public const comma_token = multassign_token - 1
public const dot_token = comma_token - 1
public const doubledot_token = dot_token - 1
public const tripledot_token = doubledot_token - 1
public const leftdotangle_token = tripledot_token - 1
public const div_token = leftdotangle_token - 1
public const divassign_token = div_token - 1
public const colon_token = divassign_token - 1
public const doublecolon_token = colon_token - 1
public const semicolon_token = doublecolon_token - 1
public const questionmark_token = semicolon_token - 1
public const at_token = questionmark_token - 1
public const leftbracket_token = at_token - 1
public const rightbracket_token = leftbracket_token - 1
public const bitwisexor_token = rightbracket_token - 1
public const logicalxor_token = bitwisexor_token - 1
public const logicalxorassign_token = logicalxor_token - 1
public const bitwisexorassign_token = logicalxorassign_token - 1
public const leftbrace_token = bitwisexorassign_token - 1
public const bitwiseor_token = leftbrace_token - 1
public const logicalor_token = bitwiseor_token - 1
public const logicalorassign_token = logicalor_token - 1
public const bitwiseorassign_token = logicalorassign_token - 1
public const rightbrace_token = bitwiseorassign_token - 1
public const bitwisenot_token = rightbrace_token - 1
public const plus_token = bitwisenot_token - 1
public const plusplus_token = plus_token - 1
public const plusassign_token = plusplus_token - 1
public const lessthan_token = plusassign_token - 1
public const leftshift_token = lessthan_token - 1
public const leftshiftassign_token = leftshift_token - 1
public const lessthanorequals_token = leftshiftassign_token - 1
public const assign_token = lessthanorequals_token - 1
public const minusassign_token = assign_token - 1
public const equals_token = minusassign_token - 1
public const strictequals_token = equals_token - 1
public const greaterthan_token = strictequals_token - 1
public const greaterthanorequals_token = greaterthan_token - 1
public const rightshift_token = greaterthanorequals_token - 1
public const rightshiftassign_token = rightshift_token - 1
public const unsignedrightshift_token = rightshiftassign_token - 1
public const unsignedrightshiftassign_token = unsignedrightshift_token - 1
public const as_token = unsignedrightshiftassign_token - 1
public const break_token = as_token - 1
public const call_token = break_token - 1
public const case_token = call_token - 1
public const cast_token = case_token - 1
public const catch_token = cast_token - 1
public const class_token = catch_token - 1
public const const_token = class_token - 1
public const continue_token = const_token - 1
public const debugger_token = continue_token - 1
public const default_token = debugger_token - 1
public const delete_token = default_token - 1
public const do_token = delete_token - 1
public const dynamic_token = do_token - 1
public const each_token = dynamic_token - 1
public const else_token = each_token - 1
public const enum_token = else_token - 1
public const extends_token = enum_token - 1
public const false_token = extends_token - 1
public const final_token = false_token - 1
public const finally_token = final_token - 1
public const for_token = finally_token - 1
public const function_token = for_token - 1
public const get_token = function_token - 1
public const goto_token = get_token - 1
public const if_token = goto_token - 1
public const implements_token = if_token - 1
public const import_token = implements_token - 1
public const in_token = import_token - 1
public const include_token = in_token - 1
public const instanceof_token = include_token - 1
public const interface_token = instanceof_token - 1
public const internal_token = interface_token - 1
public const intrinsic_token = internal_token - 1
public const is_token = intrinsic_token - 1
public const let_token = is_token - 1
public const namespace_token = let_token - 1
public const native_token = namespace_token - 1
public const new_token = native_token - 1
public const null_token = new_token - 1
public const override_token = null_token - 1
public const package_token = override_token - 1
public const private_token = package_token - 1
public const protected_token = private_token - 1
public const prototype_token = protected_token - 1
public const public_token = prototype_token - 1
public const return_token = public_token - 1
public const set_token = return_token - 1
public const static_token = set_token - 1
public const super_token = static_token - 1
public const switch_token = super_token - 1
public const this_token = switch_token - 1
public const throw_token = this_token - 1
public const to_token = throw_token - 1
public const true_token = to_token - 1
public const try_token = true_token - 1
public const type_token = try_token - 1
public const typeof_token = type_token - 1
public const use_token = typeof_token - 1
public const var_token = use_token - 1
public const void_token = var_token - 1
public const while_token = void_token - 1
public const with_token = while_token - 1
public const xml_token = with_token - 1
public const yield_token = xml_token - 1
public const identifier_token = yield_token - 1
public const numberliteral_token = identifier_token - 1
public const regexpliteral_token = numberliteral_token - 1
public const stringliteral_token = regexpliteral_token - 1
public const xmlliteral_token = stringliteral_token - 1
public const xmlpart_token = xmlliteral_token - 1
public const xmlmarkup_token = xmlpart_token - 1
public const xmltext_token = xmlmarkup_token - 1
public const xmltagendend_token = xmltext_token - 1
public const xmltagstartend_token = xmltagendend_token - 1
public const attributeidentifier_token = xmltagstartend_token - 1
public const doccomment_token = attributeidentifier_token - 1
public const blockcomment_token = doccomment_token - 1
public const slashslashcomment_token = blockcomment_token - 1
public const packageidentifier_token = slashslashcomment_token - 1
public const eol_token = packageidentifier_token - 1
public const whitespace_token = eol_token - 1
public const empty_token = whitespace_token - 1
public const error_token = empty_token - 1
public const last_token = empty_token - 1
public const tokenNames = [
"<unused index>",
"end of program",
"minus",
"minusminus",
"not",
"notequals",
"strictnotequals",
"modulus",
"modulusassign",
"bitwiseand",
"logicaland",
"logicalandassign",
"bitwiseandassign",
"leftparen",
"rightparen",
"mult",
"multassign",
"comma",
"dot",
"doubledot",
"tripledot",
"leftdotangle",
"div",
"divassign",
"colon",
"doublecolon",
"semicolon",
"questionmark",
"at",
"leftbracket",
"rightbracket",
"bitwisexor",
"logicalxor",
"logicalxorassign",
"bitwisexorassign",
"leftbrace",
"bitwiseor",
"logicalor",
"logicalorassign",
"bitwiseorassign",
"rightbrace",
"bitwisenot",
"plus",
"plusplus",
"plusassign",
"lessthan",
"leftshift",
"leftshiftassign",
"lessthanorequals",
"assign",
"minusassign",
"equals",
"strictequals",
"greaterthan",
"greaterthanorequals",
"rightshift",
"rightshiftassign",
"unsignedrightshift",
"unsignedrightshiftassign",
"as",
"break",
"call",
"case",
"cast",
"catch",
"class",
"const",
"continue",
"debugger",
"default",
"delete",
"do",
"dynamic",
"each",
"else",
"enum",
"extends",
"false",
"final",
"finally",
"for",
"function",
"get",
"goto",
"if",
"implements",
"import",
"in",
"include",
"instanceof",
"interface",
"internal",
"intrinsic",
"is",
"let",
"namespace",
"native",
"new",
"null",
"override",
"package",
"private",
"protected",
"prototype",
"public",
"return",
"set",
"static",
"super",
"switch",
"this",
"throw",
"to",
"true",
"try",
"type",
"typeof",
"use",
"var",
"void",
"while",
"with",
"xml",
"yield",
"identifier",
"numberliteral",
"regexpliteral",
"stringliteral",
"xmlliteral",
"xmlpart",
"xmlmarkup",
"xmltext",
"xmltagendend",
"xmltagstartend",
"attributeidentifier",
"docComment",
"blockComment",
"slashslashcomment",
"packageidentifier",
"<newline>",
"<ws>",
"<empty>",
"<error>",
"abbrev_mode",
"full_mode"
]
class Token
{
var kind
var utf8id
function Token(kind,utf8id)
{
this.kind = kind
this.utf8id = utf8id
}
}
class Scanner
{
private const lexemePattern = /<<=|>>=|>>>=|\^=|\^\^=|[|]=|[|][|]=|\/=|-=|\+=|\&\&=|\&=|\%=|\*=|===|\!==|\!=|==|>=|<=|&&|\^\^|\|\||[.][.][.]?|\+\+|--|>>>|<<|>>|::|\.<|[a-zA-Z_][a-zA-Z_0-9]*|-?[0-9]+|'[^']*'|"[^"]*"|\n|./g
private var lexemeSequence
private var index
private const tokenInstances = [null]
private var lastKind
const utf8Pool = []
const qualidPool = []
function equals(v1,v2)
{
if( v1 == v2 )
{
var result = true
}
else
if( v1 is Array && v1.length === v2.length )
{
var result = true
for( var n = v1.length-1; n>=0; --n )
{
if( v1[n] != v2[n] )
{
result = false
}
}
}
else
{
var result = false
}
return result
}
function poolIndexOf(pool,val)
{
Debug.enter("poolIndexOf",pool,val)
for( var index:int = pool.length-1; index>=0; --index )
{
if( equals(pool[index],val) )
{
//print("found",val)
break
}
}
if( index < 0 )
{
//print("adding",val)
index = pool.length
pool.push(val)
}
Debug.exit("poolIndexOf",index)
return index
}
function utf8IndexOf(val)
{
return poolIndexOf(utf8Pool,val)
}
function qualidIndexOf(qual,id)
{
Debug.enter("qualidIndexOf",qual,id)
var qualIndex = poolIndexOf(utf8Pool,qual) // "" means runtime qualified
var idIndex = poolIndexOf(utf8Pool,id)
var index = poolIndexOf(qualidPool,[qualIndex,idIndex])
Debug.exit("qualidIndexOf",index)
return index
}
function printSuffix()
{
print("suffix",lexemeSequence.slice(index))
}
const slash_context = [regexpliteral_token]
const package_names = {
toString:void 0,
valueOf:void 0,
hasOwnProperty:void 0,
constructor:void 0,
toLocaleString:void 0,
isPrototypeOf:void 0,
propertyIsEnumerable:void 0,
setPropertyIsEnumerable:void 0
} // zero out inherited prototype names
function addPackageName(str)
{
package_names[str]=true
}
private function addToken(kind,text)
{
var result = tokenInstances.length
switch(kind)
{
case stringliteral_token:
text = text.substring(1,text.length-1)
break
default:
break
}
var index = utf8IndexOf(text)
tokenInstances.push(new Token(kind,index))
return result
}
function Scanner(src)
{
this.lexemeSequence = src.match(lexemePattern)
//print("lexemes="+lexemeSequence)
this.index = 0
this.token(true) // prime the token stream
//print("source="+lexemeSequence.join(""))
}
function isSlashContext(kind)
{
return slash_context[slash_context.length-1] == kind
}
function count()
{
return this.lexemeSequence.length
}
function next()
{
do
{
index++
var kind = token(true)
}
while( kind == whitespace_token || kind == eol_token )
return kind
}
function isPackageNamePrefix(str)
{
if( isSlashContext(regexpliteral_token) )
for( var name in package_names )
{
if( name.indexOf(str) === 0 && package_names[name] != void 0 ) // the second condition is to avoid false postives for zeroed names
{
return true
}
}
return false
}
function isIdentifier(str)
{
return /^[a-zA-Z_][a-zA-Z_0-9]*$/.test(str)
}
function isPackageName(str)
{
return isSlashContext(regexpliteral_token) && package_names[str] != void 0
}
function token(next=false)
{
// if we already have a current token then just return it
if( !next )
{
return lastKind
}
var kind = 0
while( lexemeSequence[index] == ' ' || lexemeSequence[index] == '\n' || lexemeSequence[index] == '\t' ||
(lexemeSequence[index] == '/' && lexemeSequence[index+1] == '*') ||
(lexemeSequence[index] == '/' && lexemeSequence[index+1] == '/') )
{
// strip whitespace
while( lexemeSequence[index] == ' ' || lexemeSequence[index] == '\n' || lexemeSequence[index] == '\t' ) index++
// strip block comment
if( lexemeSequence[index] == '/' && lexemeSequence[index+1] == '*' )
{
while( !(lexemeSequence[index] == '*' && lexemeSequence[index+1] == '/') )
{
index++
if( index+1 == lexemeSequence.length )
{
throw "unterminated block comment"
}
}
index += 2 // move past '*/'
}
// strip line comment
if( lexemeSequence[index] == '/' && lexemeSequence[index+1] == '/' )
{
while( !(lexemeSequence[index] == '\n' || lexemeSequence[index] == void 0) )
{
index++
}
}
}
var lexeme = lexemeSequence[index]
// first, merge lexemes that need to be merged
if( isSlashContext(regexpliteral_token) )
{
switch(lexeme)
{
case '/':
var start_index = index
while( lexemeSequence[index+1] != '/' )
{
index++
lexemeSequence[start_index]+=lexemeSequence[index]
lexemeSequence[index]=' '
}
index = index + 1 // ** replace with index++ to get verifier error
lexemeSequence[start_index]+=lexemeSequence[index]
lexemeSequence[index]=' '
if( lexemeSequence[index+1] != undefined && /^[a-zA-Z][a-zA-Z]*$/.test(lexemeSequence[index+1]) ) // add flags
{
index = index + 1 // ** replace with index++ to get verifier error
lexemeSequence[start_index]+=lexemeSequence[index]
lexemeSequence[index]=' '
}
lexeme = lexemeSequence[start_index]
break
case '.':
var start_index = index
// see if we have an integer
if( lexemeSequence[index+1] != null && /-?[0-9]+/.test(lexemeSequence[index+1]) )
{
index++
lexemeSequence[start_index]+=lexemeSequence[index]
lexemeSequence[index]=' '
lexeme = lexemeSequence[start_index]
// todo: exponents
}
// check for package identifier or number literal
break
case '<': // xml intialiser
break
default:
var start_index = index
// see if we have an integer possibly followed by a dot possibly followed by another integer
if( lexeme != null && /-?[0-9]+/.test(lexeme) )
{
if( lexemeSequence[index+1] == '.' )
{
index++
lexemeSequence[start_index]+=lexemeSequence[index]
lexemeSequence[index]=' '
if( lexemeSequence[index+1] != null && /-?[0-9]+/.test(lexemeSequence[index+1]) )
{
index++
lexemeSequence[start_index]+=lexemeSequence[index]
lexemeSequence[index]=' '
}
}
lexeme = lexemeSequence[start_index]
// todo: exponents
}
else
if( isIdentifier(lexeme) ) // see if it is an identifier that is a prefix of a package name
{
// while lexeme is a prefix of a package name
// and the next two lexemes are dot and identifier
// concat these three lexems to make a temp lexeme
// if temp lexeme is a complete package name, then merge tokens and continue
//
// package p.q {}
// package p.q.r {}
// p.q.r.x
var start_index = index
var last_index = start_index
while( isPackageNamePrefix(lexeme) &&
lexemeSequence[last_index+1] == "." &&
isIdentifier(lexemeSequence[last_index+2]) )
{
lexeme = lexeme+"."+lexemeSequence[last_index+2]
if( isPackageName(lexeme) ) // if its a match, merge
{
lexemeSequence[last_index+2] = lexeme
index = last_index+2 // last match
}
last_index += 2
}
for( var i = start_index; i<index; ++i )
{
lexemeSequence[i]=' '
}
lexeme = lexemeSequence[index]
}
break
}
}
// next, select the token kind
switch(lexeme)
{
case void 0: kind = eos_token; break;
// punctuators
case '.': kind = dot_token; break
case '..': kind = doubledot_token; break
case '...': kind = tripledot_token; break
case '.<': kind = leftdotangle_token; break
case '!': kind = not_token; break
case '!=': kind = notequals_token; break
case '!==': kind = strictnotequals_token; break
case '%': kind = modulus_token; break
case '%=': kind = modulusassign_token; break
case '&': kind = bitwiseand_token; break
case '&=': kind = bitwiseandassign_token; break
case '&&': kind = logicaland_token; break
case '&&=': kind = logicalandassign_token; break
case '*': kind = mult_token; break
case '*=': kind = multassign_token; break
case '+': kind = plus_token; break
case '+=': kind = plusassign_token; break
case '++': kind = plusplus_token; break
case '-': kind = minus_token; break
case '--': kind = minusminus_token; break
case '-=': kind = minusassign_token; break
case '/': kind = div_token; break
case '/=': kind = divassign_token; break
case ',': kind = comma_token; break
case ':': kind = colon_token; break
case '::': kind = doublecolon_token; break
case ';': kind = semicolon_token; break
case '<': kind = lessthan_token; break
case '<=': kind = lessthanorequals_token; break
case '<<': kind = leftshift_token; break
case '<<=': kind = leftshiftassign_token; break
case '=': kind = assign_token; break
case '==': kind = equals_token; break
case '===': kind = strictequals_token; break
case '>': kind = greaterthan_token; break
case '>=': kind = greaterthanorequals_token; break
case '>>': kind = rightshift_token; break
case '>>=': kind = rightshiftassign_token; break
case '>>>': kind = unsignedrightshift_token; break
case '>>>=': kind = unsignedrightshiftassign_token; break
case '^': kind = bitwisexor_token; break
case '^=': kind = bitwisexorassign_token; break
case '^^': kind = logicalxor_token; break
case '^^=': kind = logicalxorassign_token; break
case '|': kind = bitwiseor_token; break
case '|=': kind = bitwiseorassign_token; break
case '||': kind = logicalor_token; break
case '||=': kind = logicalorassign_token; break
case '?': kind = questionmark_token; break
case '(': kind = leftparen_token; break
case ')': kind = rightparen_token; break
case '[': kind = leftbracket_token; break
case ']': kind = rightbracket_token; break
case '{': kind = leftbrace_token; break
case '}': kind = rightbrace_token; break
case '~': kind = bitwisenot_token; break
case '@': kind = at_token; break
case '</': kind = xmltagendend_token; break
case '/>': kind = xmltagstartend_token; break
// completely reserved words
case 'as': kind = as_token; break
case 'break': kind = break_token; break
case 'call': kind = call_token; break
case 'case': kind = case_token; break
case 'cast': kind = cast_token; break
case 'catch': kind = catch_token; break
case 'class': kind = class_token; break
case 'const': kind = const_token; break
case 'continue': kind = continue_token; break
case 'default': kind = default_token; break
case 'delete': kind = delete_token; break
case 'do': kind = do_token; break
case 'else': kind = else_token; break
case 'enum': kind = enum_token; break
case 'extends': kind = extends_token; break
case 'false': kind = false_token; break
case 'finally': kind = finally_token; break
case 'for': kind = for_token; break
case 'function': kind = function_token; break
case 'if': kind = if_token; break
case 'implements': kind = implements_token; break
case 'import': kind = import_token; break
case 'in': kind = in_token; break
case 'instanceof': kind = instanceof_token; break
case 'interface': kind = interface_token; break
case 'internal': kind = internal_token; break
case 'intrinsic': kind = intrinsic_token; break
case 'is': kind = is_token; break
case 'let': kind = let_token; break
case 'native': kind = native_token; break
case 'new': kind = new_token; break
case 'null': kind = null_token; break
case 'package': kind = package_token; break
case 'private': kind = private_token; break
case 'protected': kind = protected_token; break
case 'public': kind = public_token; break
case 'return': kind = return_token; break
case 'super': kind = super_token; break
case 'switch': kind = switch_token; break
case 'this': kind = this_token; break
case 'throw': kind = throw_token; break
case 'to': kind = to_token; break
case 'true': kind = true_token; break
case 'try': kind = try_token; break
case 'typeof': kind = typeof_token; break
case 'use': kind = use_token; break
case 'var': kind = var_token; break
case 'while': kind = while_token; break
case 'with': kind = with_token; break
case 'yield': kind = yield_token; break;
// contextually reserved words
case 'debugger': kind = debugger_token; break
case 'dynamic': kind = dynamic_token; break
case 'each': kind = each_token; break
case 'final': kind = final_token; break
case 'get': kind = get_token; break
case 'goto': kind = goto_token; break
case 'include': kind = include_token; break
case 'namespace': kind = namespace_token; break
case 'native': kind = native_token; break
case 'override': kind = override_token; break
case 'prototype': kind = prototype_token; break
case 'set': kind = set_token; break
case 'static': kind = static_token; break
case 'type': kind = type_token; break
case 'xml': kind = xml_token; break
// identifiers & literals
default:
var c0 = lexeme.charAt(0)
if(c0=="'" || c0=='"')
{
kind = addToken(stringliteral_token,lexeme)
}
else
if( isPackageName(lexeme) )
{
kind = addToken(packageidentifier_token,lexeme)
}
else
if( /^[a-zA-Z_][a-zA-Z_0-9]*$/.test(lexeme) )
{
kind = addToken(identifier_token,lexeme) // interns and returns index
}
else
if( /^\x2f[^\x2f.]*\x2f/.test(lexeme) )
{
kind = addToken(regexpliteral_token,lexeme) // interns and returns index
}
else
if( /-?[0-9]*\.?[0-9]+/.test(lexeme) )
{
kind = addToken(numberliteral_token,lexeme) // interns and returns index
}
else
{
throw "unrecognized lexeme: "+lexeme
}
}
lastKind = kind
//print("found "+tokenText(kind))
return kind
}
function tokenKind(n)
{
if( +n != n )
{
throw "bogus token kind"
}
if( +n <= 0 )
{
return n
}
else
{
return tokenInstances[n].kind
}
}
function tokenText(n)
{
if( n <= 0 )
{
return tokenNames[-n]
}
else
{
var utf8id = tokenInstances[n].utf8id
return utf8Pool[utf8id]
}
}
function followsNewline()
{
var follows = false
for( var i = index-1; i >= 0; --i )
{
//print("follows",lexemeSequence[i].charCodeAt(0))
if( lexemeSequence[i] == "\n" )
{
follows = true
break
}
else
if( lexemeSequence[i] != " " &&
lexemeSequence[i] != "\t" )
{
break
}
}
return follows
}
}
public class Parser
{
const abbrevIfElse_mode = else_token // lookahead uses this value. don't change.
const abbrevDoWhile_mode = while_token // ditto.
const abbrevFunction_mode = function_token
const abbrev_mode = last_token-1
const full_mode = abbrev_mode-1
const allowIn_mode = full_mode-1
const noIn_mode = allowIn_mode-1
const catch_parameter_error = 1
const syntax_xml_error = 2
const syntax_error = 7
const expression_syntax_error = 8
const syntax_eos_error = 9
var scan : Scanner
public function Parser(src)
{
this.scan = new Scanner(src)
}
function lookahead(kind)
{
return scan.tokenKind(scan.token()) === kind
}
function lookaheadSemicolon(mode)
{
if( lookahead(semicolon_token) ||
lookahead(eos_token) ||
lookahead(rightbrace_token) ||
scan.followsNewline() ||
mode === abbrev_mode )
{
// print("semicolon found")
var result = true
}
else
{
// print("semicolon not found")
var result = false
}
return result
}
function matchSemicolon(mode)
{
Debug.enter("matchSemicolon",mode)
if( lookahead(semicolon_token) )
{
//print("semicolon found")
var result = match(semicolon_token)
}
else
if( lookahead(eos_token) ||
lookahead(rightbrace_token) ||
scan.followsNewline() ||
mode == abbrev_mode )
{
//print("virtual semicolon found")
var result = semicolon_token
}
else
if( (mode == abbrevIfElse_mode || mode == abbrevDoWhile_mode) &&
lookahead(mode) )
{
var result = semicolon_token
}
else
{
match(semicolon_token)
}
Debug.exit("matchSemicolon",result)
return result
}
function lookaheadReservedWord()
{
var result = true
switch( scan.token() )
{
case as_token:
case break_token:
case case_token:
case cast_token:
case class_token:
case const_token:
case continue_token:
case debugger_token:
case default_token:
case delete_token:
case do_token:
case else_token:
case enum_token:
case extends_token:
case false_token:
case finally_token:
case for_token:
case function_token:
case goto_token:
case if_token:
case implements_token:
case import_token:
case in_token:
case instanceof_token:
case interface_token:
// case internal_token:
// case intrinsic_token:
case is_token:
case let_token:
case native_token:
case new_token:
case null_token:
case package_token:
// case private_token:
// case protected_token:
// case public_token:
case return_token:
case super_token:
case switch_token:
case this_token:
case throw_token:
case to_token:
case true_token:
case try_token:
case typeof_token:
case use_token:
case var_token:
case void_token:
case while_token:
case with_token:
case dynamic_token:
case debugger_token:
case each_token:
case final_token:
case get_token:
case goto_token:
case include_token:
case namespace_token:
case native_token:
case override_token:
case prototype_token:
case set_token:
case static_token:
case type_token:
case xml_token:
case yield_token:
break;
default: result = false
}
return result
}
function matchReservedWord()
{
var result
switch( scan.token() )
{
case as_token: result = match(as_token); break
case break_token: result = match(break_token); break
case case_token: result = match(case_token); break
case cast_token: result = match(cast_token); break
case class_token: result = match(class_token); break
case const_token: result = match(const_token); break
case continue_token: result = match(continue_token); break
case debugger_token: result = match(debugger_token); break
case default_token: result = match(default_token); break
case delete_token: result = match(delete_token); break
case do_token: result = match(do_token); break
case else_token: result = match(else_token); break
case enum_token: result = match(enum_token); break
case extends_token: result = match(extends_token); break
case false_token: result = match(false_token); break
case finally_token: result = match(finally_token); break
case for_token: result = match(for_token); break
case function_token: result = match(function_token); break
case goto_token: result = match(goto_token); break
case if_token: result = match(if_token); break
case implements_token: result = match(implements_token); break
case import_token: result = match(import_token); break
case in_token: result = match(in_token); break
case instanceof_token: result = match(instanceof_token); break
case interface_token: result = match(interface_token); break
case internal_token: result = match(internal_token); break
case intrinsic_token: result = match(intrinsic_token); break
case is_token: result = match(is_token); break
case let_token: result = match(let_token); break
case native_token: result = match(native_token); break
case new_token: result = match(new_token); break
case null_token: result = match(null_token); break
case package_token: result = match(package_token); break
case private_token: result = match(private_token); break
case protected_token: result = match(protected_token); break
case public_token: result = match(public_token); break
case return_token: result = match(return_token); break
case super_token: result = match(super_token); break
case switch_token: result = match(switch_token); break
case this_token: result = match(this_token); break
case throw_token: result = match(throw_token); break
case to_token: result = match(to_token); break
case true_token: result = match(true_token); break
case try_token: result = match(try_token); break
case typeof_token: result = match(typeof_token); break
case use_token: result = match(use_token); break
case with_token: result = match(with_token); break
case var_token: result = match(var_token); break
case void_token: result = match(void_token); break
case while_token: result = match(while_token); break
case with_token: result = match(with_token); break
case dynamic_token: result = match(dynamic_token); break
case debugger_token: result = match(debugger_token); break
case each_token: result = match(each_token); break
case final_token: result = match(final_token); break
case get_token: result = match(get_token); break
case goto_token: result = match(goto_token); break
case include_token: result = match(include_token); break
case namespace_token: result = match(namespace_token); break
case native_token: result = match(native_token); break
case override_token: result = match(override_token); break
case prototype_token: result = match(prototype_token); break
case set_token: result = match(set_token); break
case static_token: result = match(static_token); break
case type_token: result = match(type_token); break
case xml_token: result = match(xml_token); break
case yield_token: result = match(yield_token); break
default: result = false
}
return result
}
function match(kind)
{
var tid = scan.token()
if( kind == scan.tokenKind(tid) )
{
//print("match =",scan.tokenText(tid))
//scan.printSuffix()
scan.next()
return tid
}
throw "syntax error: expecting "+scan.tokenText(kind)+", found "+ scan.tokenText(scan.tokenKind(tid))
}
function enterSlashContext(goal)
{
scan.slash_context.push(goal);
//print("entering slash context "+scan.slash_context)
}
function exitSlashContext(goal)
{
if( scan.slash_context[scan.slash_context.length-1] != goal ) throw "slash context out of sync"
scan.slash_context.pop();
//print("exiting slash context "+scan.slash_context)
}
// Parse rountines
/*
Identifier
Identifier
call
debugger
dynamic
each
final
get
goto
include
namespace
native
override
prototype
set
static
type
xml
*/
public function parseIdentifier()
{
Debug.enter("parseIdentifier")
if( lookahead(call_token) ) var name = scan.tokenText(match(call_token))
else if( lookahead(debugger_token) ) var name = scan.tokenText(match(debugger_token))
else if( lookahead(dynamic_token) ) var name = scan.tokenText(match(dynamic_token))
else if( lookahead(each_token) ) var name = scan.tokenText(match(each_token))
else if( lookahead(final_token) ) var name = scan.tokenText(match(final_token))
else if( lookahead(get_token) ) var name = scan.tokenText(match(get_token))
else if( lookahead(goto_token) ) var name = scan.tokenText(match(goto_token))
else if( lookahead(include_token) ) var name = scan.tokenText(match(include_token))
else if( lookahead(namespace_token) ) var name = scan.tokenText(match(namespace_token))
else if( lookahead(native_token) ) var name = scan.tokenText(match(native_token))
else if( lookahead(override_token) ) var name = scan.tokenText(match(override_token))
else if( lookahead(prototype_token) ) var name = scan.tokenText(match(prototype_token))
else if( lookahead(set_token) ) var name = scan.tokenText(match(set_token))
else if( lookahead(static_token) ) var name = scan.tokenText(match(static_token))
else if( lookahead(type_token) ) var name = scan.tokenText(match(type_token))
else if( lookahead(xml_token) ) var name = scan.tokenText(match(xml_token))
else var name = scan.tokenText(match(identifier_token))
var result = <Identifier name={name}/>
Debug.exit("parseIdentifier",result)
return result
}
/*
PropertyIdentifier
Identifier
*
*/
function parsePropertyIdentifier()
{
Debug.enter("parsePropertyIdentifier")
var result
if( lookahead( mult_token ) )
{
match( mult_token );
result = <Identifier name="*"/>
}
else
{
result = parseIdentifier()
}
Debug.exit("parsePropertyIdentifier",result.toXMLString())
return result
}
/*
Qualifier
ReservedNamespace
PropertyIdentifier
*/
function parseQualifier()
{
Debug.enter("parseQualifier")
if( lookahead(internal_token) || lookahead(intrinsic_token) ||
lookahead(private_token) || lookahead(protected_token) ||
lookahead(public_token) )
{
var result = parseReservedNamespace()
}
else
{
var result = parsePropertyIdentifier()
}
Debug.exit("parseQualifier",result)
return result
}
/*
ReservedNamespace
internal
intrinsic
private
protected
public
*/
function parseReservedNamespace()
{
Debug.enter("parseReservedNamespace")
if( lookahead( internal_token ) )
{
match( internal_token )
var result = <Namespace kind="internal" name={current_package}/>
}
else
if( lookahead( intrinsic_token ) )
{
match( intrinsic_token )
var result = <Namespace kind="intrinsic" name=""/>
}
else
if( lookahead( private_token ) )
{
match( private_token )
var result = <Namespace kind="private" name={current_class}/>
}
else
if( lookahead( protected_token ) )
{
match( protected_token )
var result = <Namespace kind="protected" name={current_class}/>
}
else
if( lookahead( public_token ) )
{
match( public_token )
if( inClassBody() )
{
var public_namespace_name = ""
}
else
{
var public_namespace_name = current_package
}
var result = <Namespace kind="public" name={public_namespace_name}/>
}
Debug.exit("parseReservedNamespace",result)
return result
}
/*
SimpleQualifiedIdentifier
PropertyIdentifier
Qualifier :: PropertyIdentifier
Qualifier :: Brackets
*/
function parseSimpleQualifiedIdentifier()
{
Debug.enter("parseSimpleQualifiedIdentifier")
var first = parseQualifier()
if( first.name() == "ReservedNamespace" )
{
match(doublecolon_token);
if( lookahead(leftbracket_token) ) // @ns::[expr]
{
var second = parseBrackets();
var result = <QualifiedExpression><Qualifier>{first}</Qualifier><Expr>{second}</Expr></QualifiedExpression>
}
else
{
var second = parsePropertyIdentifier()
var result = <QualifiedIdentifier><Qualifier>{first}</Qualifier>{second}</QualifiedIdentifier>
}
}
else
if( lookahead(doublecolon_token) )
{
match(doublecolon_token);
first = <Get kind="lexical">{first}</Get>
if( lookahead(leftbracket_token) ) // @ns::[expr]
{
var second = parseBrackets();
var result = <QualifiedExpression><Qualifier>{first}</Qualifier><Expr>{second}</Expr></QualifiedExpression>
}
else
{
var second = parsePropertyIdentifier()
var result = <QualifiedIdentifier><Qualifier>{first}</Qualifier>{second}</QualifiedIdentifier>
}
}
else
{
var result = first;
}
Debug.exit("parseSimpleQualifiedIdentifier",result)
return result
}
/*
ExpressionQualifiedIdentifier
ParenListExpression :: PropertyIdentifier
ParenListExpression :: Brackets
*/
function parseExpressionQualifiedIdentifier()
{
Debug.enter("parseExpressionQualifiedIdentifier")
var first = parseParenListExpression()
match(doublecolon_token)
if( lookahead(leftbracket_token) )
{
var second = parseBrackets()
var result = <QualifiedExpression><Qualifier>{first}</Qualifier><Expr>{second}</Expr></QualifiedExpression>
}
else
{
var second = parsePropertyIdentifier()
var result = <QualifiedIdentifier><Qualifier>{first}</Qualifier>{second}</QualifiedIdentifier>
}
Debug.exit("parseExpressionQualifiedIdentifier",result)
return result
}
/*
NonAttributeQualifiedIdentifier
SimpleQualifiedIdentifier
ExpressionQualifiedIdentifier
*/
function parseNonAttributeQualifiedIdentifier()
{
Debug.enter("parseNonAttributeQualifiedIdentifier")
if( lookahead(leftparen_token) )
{
var result = parseExpressionQualifiedIdentifier()
}
else
{
var result = parseSimpleQualifiedIdentifier();
}
Debug.exit("parseNonAttributeQualifiedIdentifier",result)
return result
}
/*
AttributeQualifiedIdentifier
@ Brackets
@ NonAttributeQualifiedIdentifier
*/
function parseAttributeIdentifier()
{
Debug.enter("parseAttributeIdentifier")
match(at_token)
if( lookahead(leftbracket_token) )
{
var result = parseBrackets()
}
else
{
var result = parseNonAttributeQualifiedIdentifier()
}
result.@is_attr="true"
Debug.exit("parseAttributeIdentifier",result)
return result
}
/*
QualifiedIdentifier
PackageIdentifier . Identifier
NonAttributeQualifiedIdentifier
*/
function parseQualifiedIdentifier()
{
Debug.enter("parseQualifiedIdentifier")
var is_attr
if( lookahead(at_token) )
{
var result = parseAttributeIdentifier()
}
else
if( lookahead(packageidentifier_token) )
{
var pkg_name = scan.tokenText(match(packageidentifier_token))
var first = <PackageIdentifier name={pkg_name}/>
match(dot_token)
var second = parseIdentifier()
var def_name = second.@name
if( !isImported(pkg_name,def_name) )
{
throw "package qualified reference to unimported name "+pkg_name+"."+def_name
}
var result = <QualifiedIdentifier><Qualifier>{first}</Qualifier>{second}</QualifiedIdentifier>
}
else
{
var result = parseNonAttributeQualifiedIdentifier()
}
Debug.exit("parseQualifiedIdentifier",result)
return result
}
/*
SimpleTypeIdentifier
PackageIdentifier . Identifier
NonAttributeQualifiedIdentifier
ParameterisedTypeIdentifier
SimpleTypeIdentifier
SimpleTypeIdentifier .< TypeExpressionList >
TypeIdentifier
ParameterisedTypeIdentifier
ParameterisedTypeIdentifier !
ParameterisedTypeIdentifier ?
TypeIdentifer may occur wherever a PrimaryExpression may occur. This includes as a base of
a property reference, in a new expression, in a call expression. TypeIdentifiers shall not
be used as the identifier of an object reference (e.g. o.T)
*/
function parseSimpleTypeIdentifier()
{
Debug.enter("parseSimpleTypeIdentifier")
if( lookahead(packageidentifier_token) )
{
var pkg_name = scan.tokenText(match(packageidentifier_token))
var first = <PackageIdentifier name={pkg_name}/>
match(dot_token)
var second = parseIdentifier()
var def_name = second.@name
if( !isImported(pkg_name,def_name) )
{
throw "package qualified reference to unimported name "+pkg_name+"."+def_name
}
var result = <QualifiedIdentifier><Qualifier>{first}</Qualifier>{second}</QualifiedIdentifier>
}
else
{
var result = parseNonAttributeQualifiedIdentifier()
}
Debug.exit("parseSimpleTypeIdentifier",result)
return result
}
private var rightanglesseen : int = 0
private var rightanglesneeded : int = 0
function parseTypeIdentifier()
{
Debug.enter("parseTypeIdentifier")
var first = parseSimpleTypeIdentifier()
if( lookahead(leftdotangle_token) )
{
match(leftdotangle_token)
rightanglesneeded++
var second = parseTypeExpressionList()
if( lookahead(unsignedrightshift_token) )
{
match(unsignedrightshift_token)
rightanglesseen += 2
}
else
if( lookahead(rightshift_token) )
{
match(rightshift_token)
rightanglesseen += 1
}
else
if( lookahead(greaterthan_token) )
{
match(greaterthan_token)
}
else
if( rightanglesseen <= rightanglesneeded )
{
rightanglesseen--
}
rightanglesneeded--
if( rightanglesneeded < 0 )
{
throw "too few right angle braces in type identifier"
}
else
if( rightanglesseen > rightanglesneeded ||
(rightanglesneeded == 0 && (lookahead(greaterthan_token) || lookahead(rightshift_token) || lookahead(unsignedrightshift_token))) )
{
throw "too many right angle braces in type identifier"
}
var result = <TypeIdentifier>{first}<TypeArguments>{second}</TypeArguments></TypeIdentifier>
}
else
{
var result = first
}
Debug.exit("parseTypeIdentifier",result)
return result
}
function parseXMLLiteral()
{
throw "XMLLiteral not implemented"
}
function parseXMLElement()
{
}
function parseXMLName(first)
{
}
function parseXMLAttributes(first)
{
}
function parseXMLAttribute(first)
{
}
function parseXMLElementContent(first)
{
}
function parseParenExpression()
{
Debug.enter("parseParenExpression")
enterSlashContext(regexpliteral_token)
match(leftparen_token);
var result = parseAssignmentExpression(allowIn_mode)
exitSlashContext(regexpliteral_token)
match(rightparen_token)
Debug.exit("parseParenExpression",result)
return result
}
function parseParenListExpression()
{
Debug.enter("parseParenListExpression")
enterSlashContext(regexpliteral_token)
match( leftparen_token );
var result = <ParenList>{parseListExpression(allowIn_mode)}</ParenList>
exitSlashContext(regexpliteral_token)
match( rightparen_token )
Debug.exit("parseParenListExpression",result)
return result
}
/*
ParenListOrExpressionQualifiedIdentifier
ParenListExpression
ParenListExpression :: PropertyIdentifier
ParenListExpression :: Brackets
*/
function parseParenListOrExpressionQualifiedIdentifier()
{
Debug.enter("parseParenListOrExpressionQualifiedIdentifier")
var first = parseParenListExpression()
if( lookahead(doublecolon_token) )
{
match(doublecolon_token)
if( lookahead(leftbracket_token) )
{
var second = parseBrackets()
var result = <QualifiedExpression><Qualifier>{first}</Qualified><Expr>{second}</Expr></QualifiedExpression>
}
else
{
var second = parsePropertyIdentifier()
var result = <QualifiedIdentifier><Qualified>{first}</Qualified>{second}</QualifiedIdentifier>
}
}
else
{
var result = first
}
Debug.exit("parseParenListOrExpressionQualifiedIdentifier",result)
return result
}
/*
FunctionCommon
FunctionSignature
FunctionSignature Block
*/
function parseFunctionCommon(first)
{
Debug.enter("parseFunctionCommon",first)
var prologue = <Prologue/>
var second = parseFunctionSignature(prologue)
if( !inInterfaceBody() )
{
slot_context_stack.push("function")
var third = parseBlockStatement();
slot_context_stack.pop()
prologue.* += third.Prologue.*
var block = third.Block
}
else
{
var block = <></>
}
var node = <Function>{first}{second}{prologue}{block}</Function>
if( !inClassBody() )
{
node.@factory = "true"
}
Debug.exit("parseFunctionCommon",node)
return node
}
/*
FunctionSignature
TypeParameters ( Parameters ) Result
*/
function parseFunctionSignature(prologue)
{
Debug.enter("parseFunctionSignature")
var first = parseTypeParameters()
match(leftparen_token)
var second = parseParameters(prologue)
match(rightparen_token)
var third = parseResultType()
var result = <Signature>{first}{second}{third}</Signature>
Debug.exit("parseFunctionSignature",result)
return result
}
/*
TypeParameters
<20>empty<74>
.< TypeParameterList >
*/
function parseTypeParameters()
{
if( lookahead(leftdotangle_token) )
{
match(leftdotangle_token)
var first = parseTypeParameterList()
var result = <TypeParameters>{first}</TypeParameters>
match(greaterthan_token)
}
else
{
var result = <TypeParameters/>
}
return result
}
/*
TypeParameterList
Identifier
Identifier , TypeParameterList
*/
function parseTypeParameterList()
{
Debug.enter("parseTypeParameterList")
var list = <></>
list += parseIdentifier()
while( lookahead(comma_token) )
{
match(comma_token)
list += parseIdentifier()
}
var result = list
Debug.exit("parseTypeParameterList",result)
return result
}
/*
*/
function parseParameters(prologue)
{
Debug.enter("parseParameters")
if( lookahead(rightparen_token) )
{
var result = <Parameters/>
}
else
{
var result = parseNonemptyParameters(<></>,prologue)
}
Debug.exit("parseParameters",result)
return result
}
/*
NonemptyParameters
ParameterInit
ParameterInit , NonemptyParameters
RestParameters
*/
function isLet(node)
{
if( node.localName() == "LetExpression" ||
node.localName() == "YieldExpression" && node.*.length() > 0 ||
node.localName() == "ConditionalExpression" && isLet(node.*[2]) )
{
return true
}
return false
}
function parseNonemptyParameters(first,prologue)
{
Debug.enter("parseNonemptyParameters",first)
if( lookahead(tripledot_token) )
{
first += parseRestParameter()
var result = first
}
else
{
first += parseParameterInit(prologue)
if( lookahead(comma_token) )
{
if( isLet(first) )
{
throw "ambiguous syntax, use parens to associate"
}
match(comma_token)
var result = parseNonemptyParameters(first,prologue)
}
else
{
var result = first
}
}
Debug.exit("parseNonemptyParameters",result)
return result
}
/*
ParameterInit
Parameter
Parameter = NonAssignmentExpressionallowIn
*/
function parseParameterInit(prologue)
{
Debug.enter("parseParameterInit")
if( lookahead(const_token) )
{
var kind = match(const_token);
}
else
{
var kind = var_token;
}
var typedid = parseTypedIdentifier(allowIn_mode)
var result = <Parameter kind={scan.tokenText(kind)}>{typedid}</Parameter>
if( lookahead(assign_token) )
{
match(assign_token);
var init = parseNonAssignmentExpression(allowIn_mode);
result.Init = init
}
var temp = makeBinding(<Attributes><parameter/></Attributes>,var_token,typedid,init,prologue)
Debug.exit("parseParameterInit",result)
return result
}
/*
*/
function parseParameter()
{
Debug.enter("parseParameter")
Debug.exit("parseParameter",result)
return result
}
/*
RestParameter
...
... ParameterAttributes Identifier
*/
function parseRestParameter()
{
Debug.enter("parseRestParameter")
match(tripledot_token)
if( lookahead(const_token) )
{
var first = match(const_token);
}
else
{
var first = var_token;
}
var second = parseIdentifier()
var result = <RestParameter kind={scan.tokenText(first)}>{second}</RestParameter>
Debug.exit("parseRestParameter",result)
return result
}
/*
ResultType
<20>empty<74>
: void
: TypeExpression
*/
function parseResultType()
{
Debug.enter("parseResultType")
if( lookahead(colon_token) )
{
match(colon_token)
if( lookahead(void_token) )
{
match(void_token)
var first = <Void/>
}
else
{
var first = parseTypeExpression()
}
var result = <ResultType>{first}</ResultType>
}
else
{
var result = <ResultType/>
}
Debug.exit("parseResultType",result)
return result
}
/*
*/
function parseObjectLiteral()
{
Debug.enter("parseObjectLiteral")
enterSlashContext(regexpliteral_token)
match(leftbrace_token)
if( lookahead(rightbrace_token) )
{
var first = null
}
else
{
var first = parseFieldListPrime(<>{parseLiteralField()}</>)
}
exitSlashContext(regexpliteral_token)
match(rightbrace_token)
var result = <LiteralObject>{first}</LiteralObject>
Debug.exit("parseObjectLiteral",result)
return result
}
/*
*/
function parseFieldListPrime(first)
{
Debug.enter("parseFieldListPrime",first)
if( lookahead(comma_token) )
{
if( isLet(first) )
{
throw "ambiguous syntax, use parens to clarify list association"
}
match(comma_token)
var second = parseLiteralField()
var result = parseFieldListPrime(<>{first}{second}</>)
}
else
{
var result = first
}
Debug.exit("parseFieldListPrime",result)
return result
}
/*
LiteralField
FieldName : AssignmentExpressionallowIn
*/
function parseLiteralField()
{
Debug.enter("parseLiteralField")
var first = parseFieldName()
match(colon_token)
var second = parseAssignmentExpression(allowIn_mode)
var result = <LiteralField>{first}{second}</LiteralField>
Debug.exit("parseLiteralField",result)
return result
}
/*
FieldName
NonAttributeQualifiedIdentifier
String
Number
ParenExpression
ReservedIdentifier
ContextuallyReservedIdentifier
*/
function parseFieldName()
{
Debug.enter("parseFieldName")
if( lookahead(stringliteral_token) )
{
result = <LiteralString value={scan.tokenText(match(stringliteral_token))}/>
}
else if( lookahead(numberliteral_token) )
{
result = <LiteralNumber value={scan.tokenText(match(numberliteral_token))}/>
}
else if( lookahead(leftparen_token) )
{
var result = parseParenExpression();
}
else
if( lookahead( lookaheadReservedWord) )
{
var result = <Identifier>{scan.tokenText(matchReservedWord())}</Identifier>
}
else
{
var result = parseNonAttributeQualifiedIdentifier();
}
Debug.exit("parseFieldName",result)
return result
}
/*
ArrayLiteral
[ ElementList ]
ElementList
<20>empty<74>
LiteralElement
, ElementList
LiteralElement , ElementList
LiteralElement
AssignmentExpressionallowIn
*/
function parseArrayLiteral()
{
Debug.enter("parseArrayLiteral")
enterSlashContext(regexpliteral_token)
match(leftbracket_token)
if( lookahead(rightbracket_token) )
{
var first = <></>
}
else
{
var temp = parseLiteralElement()
var first = parseElementListPrime(<>{temp}</>)
}
exitSlashContext(regexpliteral_token)
match(rightbracket_token)
var result = <LiteralArray>{first}</LiteralArray>
Debug.exit("parseArrayLiteral",result)
return result
}
function parseElementListPrime(first)
{
Debug.enter("parseElementListPrime",first)
while( lookahead(comma_token) )
{
if( isLet(first) )
{
throw "ambiguous syntax, use parens to clarify list association"
}
match(comma_token)
var second = parseLiteralElement()
if( second == null )
{
// do nothing
}
else
{
var first = <>{first}{second}</>
}
}
var result = first
Debug.exit("parseElementListPrime",result)
return result
}
function parseLiteralElement()
{
Debug.enter("parseLiteralElement")
if( lookahead(comma_token) )
{
var result = <EmptyElement/>
}
else
if( lookahead(rightbracket_token) )
{
var result = null
}
else
{
var result = parseAssignmentExpression(allowIn_mode)
}
Debug.exit("parseLiteralElement",result)
return result
}
function parseCastExpression()
{
Debug.enter("parseCastExpression")
if( lookahead(cast_token) )
{
match(cast_token)
var first = parseTypeExpression()
var second = parseParenListExpression()
var result = <Cast>{first}<Expr>{second}</Expr></Cast>
}
else
if( lookahead(to_token) )
{
match(to_token)
var first = parseTypeExpression()
var second = parseParenListExpression()
var result = <to>{first}<Expr>{second}</Expr></to>
}
Debug.exit("parseCastExpression",result)
return result
}
/*
PrimaryExpression
null
true
false
Number
String
this
RegularExpression
TypeIdentifier
AttributeQualifiedIdentifier
XMLInitialiser
ParenListExpression
ArrayLiteral
ObjectLiteral
FunctionExpression
cast TypeExpression ParenListExpression
*/
function parsePrimaryExpression()
{
Debug.enter("parsePrimaryExpression")
if( lookahead(null_token) )
{
match(null_token)
var result = <LiteralNull/>
}
else
if( lookahead(true_token) )
{
match(true_token)
var result = <LiteralBoolean value="true"/>
}
else
if( lookahead(false_token) )
{
match(false_token)
var result = <LiteralBoolean value="false"/>
}
else
if( lookahead(numberliteral_token) )
{
var result = <LiteralNumber value={scan.tokenText(match(numberliteral_token))}/>
}
else
if( lookahead(stringliteral_token) )
{
var result = <LiteralString value={scan.tokenText(match(stringliteral_token))}/>
}
else
if( lookahead(this_token) )
{
match(this_token)
var result = <This/>
}
else
if( lookahead(regexpliteral_token) )
{
var result = <LiteralRegExp value={scan.tokenText(match(regexpliteral_token))}/>
}
else
if( lookahead(function_token) )
{
match(function_token);
var first = null
if( lookahead(identifier_token) )
{
first = parseIdentifier();
}
var result = parseFunctionCommon(first);
}
else
if( lookahead(leftparen_token) )
{
var result = parseParenListOrExpressionQualifiedIdentifier()
}
else
if( lookahead(leftbracket_token) )
{
var result = parseArrayLiteral()
}
else
if( lookahead(leftbrace_token) )
{
var result = parseObjectLiteral()
}
else
if( lookahead(cast_token) || lookahead(to_token) )
{
var result = parseCastExpression()
}
else
if( lookahead(at_token) )
{
var temp = parseAttributeIdentifier()
var result = <Get kind="lexical">{temp}</Get>
}
else
{
var temp = parseTypeIdentifier()
var result = <Get kind="lexical">{temp}</Get>
}
Debug.exit("parsePrimaryExpression",result)
return result
}
/*
SuperExpression
super
super Arguments
*/
function parseSuperExpression()
{
Debug.enter("parseSuperExpression")
match(super_token)
var first = <SuperExpression/>
if( lookahead(leftparen_token) )
{
var result = parseArguments(first)
}
else
{
var result = first
}
Debug.exit("parseSuperExpression",result)
return result
}
/*
MemberExpression
PrimaryExpression
new MemberExpression Arguments
SuperExpression PropertyOperator
MemberExpression PropertyOperator
Refactored:
MemberExpression :
PrimaryExpression MemberExpressionPrime
new MemberExpression Arguments MemberExpressionPrime
SuperExpression PropertyOperator MemberExpressionPrime
MemberExpressionPrime :
[ Expression ] MemberExpressionPrime
. Identifier MemberExpressionPrime
<20>empty<74>
*/
function parseMemberExpression()
{
Debug.enter("parseMemberExpression")
if( lookahead(new_token) )
{
match(new_token)
var first = parseMemberExpression()
if( lookahead(leftparen_token) )
{
var first = parseArguments(first)
if( first.name() == "Call" )
{
first.@is_new = true
}
else
{
first.Call.@is_new = true
}
var is_shortnew = false
}
else
{
if( first.name() == "Get" )
{
first.setLocalName("Call")
first.args = <Args/>
first.@is_new = true
}
else
{
first = <Call is_new="true">{first}<Args/></Call>
}
var is_shortnew = true
}
}
else
if( lookahead(super_token) )
{
var first = parseSuperExpression()
var first = parsePropertyOperator(first)
}
else
{
var first = parsePrimaryExpression()
}
if( !is_shortnew )
while( lookahead(leftbracket_token) ||
lookahead(dot_token) ||
lookahead(doubledot_token) )
{
var first = parsePropertyOperator(first)
}
var result = first
Debug.exit("parseMemberExpression",result)
return result
}
/*
NewExpression
MemberExpression
new NewExpression
*/
function parseNewExpression()
{
Debug.enter("parseNewExpression")
var result = parseMemberExpression()
Debug.exit("parseNewExpression",result)
return result
}
/*
CallExpressionPrime :
Arguments CallExpressionPrime
[ Expression ] CallExpressionPrime
. Identifier CallExpressionPrime
<20>empty<74>
*/
function parseCallExpressionPrime(first)
{
Debug.enter("parseCallExpressionPrime",first)
if( lookahead(leftparen_token) )
{
var second = parseArguments(first)
var result = parseCallExpressionPrime(second)
}
else
if( lookahead(leftbracket_token) ||
lookahead(dot_token) ||
lookahead(doubledot_token) )
{
var second = parsePropertyOperator(first)
var result = parseCallExpressionPrime(second)
}
else
{
var result = first
}
Debug.exit("parseCallExpressionPrime",result)
return result
}
/*
PropertyOperator
. QualifiedIdentifier
.. QualifiedIdentifier
. ParenListExpression
. ParenListExpression :: PropertyIdentifier
. ParenListExpression :: Brackets
Brackets
*/
function parsePropertyOperator(first)
{
Debug.enter("parsePropertyOperator",first)
if( lookahead(dot_token) )
{
match(dot_token)
if( lookahead(leftparen_token) )
{
var second = parseParenListExpression()
if( lookahead(doublecolon_token) )
{
match(doublecolon_token)
if( lookahead(leftbracket_token) )
{
var third = parseBrackets()
var result = <Get kind="bracket">{first}<QualifiedExpression><Qualifier>{second}</Qualifier>{third}</QualifiedExpression></Get>
}
else
{
var third = parsePropertyIdentifier()
var result = <Get kind="dot">{first}<QualifiedIdentifier><Qualifier>{second}</Qualifier>{third}</QualifiedIdentifier></Get>
}
}
else
{
var result = <FilterExpression>{first}{second}</FilterExpression>
}
}
else
if( lookaheadReservedWord() )
{
var second = <Identifier>{scan.tokenText(matchReservedWord())}</Identifier>
var result = <Get kind="dot">{first}{second}</Get>
}
else
{
var second = parseQualifiedIdentifier()
var result = <Get kind="dot">{first}{second}</Get>
}
}
else
if( lookahead(doubledot_token) )
{
match(doubledot_token)
var second = parseQualifiedIdentifier()
var result = <DescendExpression>{first}{second}</DescendExpression>
}
else
if( lookahead(leftbracket_token) )
{
var second = parseBrackets()
var result = <Get kind="bracket">{first}{second}</Get>
}
Debug.exit("parsePropertyOperator",result)
return result
}
/*
Brackets
[ ]
[ ListExpressionallowIn ]
[ ListExpressionallowIn : ]
[ ListExpressionallowIn : ListExpressionallowIn ]
[ : ListExpressionallowIn ]
*/
function parseBrackets()
{
Debug.enter("parseBrackets")
match(leftbracket_token)
if( lookahead(rightbracket_token) )
{
var first = null
var second = null
}
else
if( lookahead(colon_token) )
{
match(colon_token)
var first = null
var second = parseListExpression(allowIn_mode)
}
else
{
var first = parseListExpression(allowIn_mode)
if( lookahead(colon_token) )
{
match(colon_token)
if( lookahead(rightbracket_token) )
{
var second = null
}
else
{
var second = parseListExpression(allowIn_mode)
}
}
else
{
}
}
match(rightbracket_token);
var result = <Brackets>{first}{second}</Brackets>
Debug.exit("parseBrackets",result)
return result
}
/*
Arguments
( )
( ListExpressionALLOWIN )
*/
function parseArguments(first)
{
Debug.enter("parseArguments",first)
enterSlashContext(regexpliteral_token)
match(leftparen_token);
if( lookahead(rightparen_token) )
{
var second = <></>
}
else
{
var second = parseArgumentList()
}
exitSlashContext(regexpliteral_token)
match(rightparen_token);
if( first.name() == "Get" )
{
first.setLocalName("Call")
first.args = <Args>{second}</Args>
}
else
{
first = <Call>{first}<Args>{second}</Args></Call>
}
var result = first
Debug.exit("parseArguments",result)
return result
}
/*
ArgumentList
*/
function parseArgumentList()
{
Debug.enter("parseArgumentList")
var list = <></>
var first = parseAssignmentExpression(allowIn_mode)
list += <To>{first}<SlotTypeRef/></To>
while( lookahead( comma_token ) )
{
if( isLet(first) )
{
throw "ambiguous syntax, use parens to clarify list association"
}
match( comma_token );
list += <To>{parseAssignmentExpression(allowIn_mode)}<SlotTypeRef/></To>
}
var node = list
Debug.exit("parseArgumentList",node)
return node
}
/*
LeftHandSideExpression
NewExpression
CallExpression
Refactored:
LeftHandSideExpression
MemberExpression LeftHandSideExpressionPrime
new NewExpression
LeftHandSideExpressionPrime
Arguments CallExpressionPrime
<20>empty<74>
*/
function parseLeftHandSideExpression()
{
Debug.enter("parseLeftHandSideExpression")
if( lookahead(new_token) )
{
var first = parseNewExpression()
}
else
{
var first = parseMemberExpression()
}
if( lookahead(leftparen_token) )
{
var first = parseArguments(first)
var result = parseCallExpressionPrime(first)
}
else
{
var result = first
}
Debug.exit("parseLeftHandSideExpression",result)
return result
}
/*
PostfixExpression
LeftHandSideExpression
LeftHandSideExpression [no line break] ++
LeftHandSideExpression [no line break] --
*/
function parsePostfixExpression()
{
Debug.enter("parsePostfixExpression")
var first = parseLeftHandSideExpression()
if( lookahead(plusplus_token) )
{
match(plusplus_token)
var result = <Postfix kind="increment">{first}</Postfix>
}
else
if( lookahead(minusminus_token) )
{
match(minusminus_token)
var result = <Postfix kind="decrement">{first}</Postfix>
}
else
{
var result = first
}
Debug.exit("parsePostfixExpression",result)
return result
}
/*
UnaryExpression
PostfixExpression
delete PostfixExpression
void UnaryExpression
typeof UnaryExpression
++ PostfixExpression
-- PostfixExpression
+ UnaryExpression
- UnaryExpression
~ UnaryExpression
! UnaryExpression
*/
function parseUnaryExpression()
{
Debug.enter("parseUnaryExpression")
if( lookahead(delete_token) )
{
enterSlashContext(regexpliteral_token)
match(delete_token)
var first = parsePostfixExpression()
if( first.name() == "Get" )
{
first.setLocalName("Delete")
}
else
{
first = <Delete>{first}</Delete>
}
var result = first
exitSlashContext(regexpliteral_token)
}
else
if( lookahead(void_token) )
{
enterSlashContext(regexpliteral_token)
match(void_token)
var first = parsePostfixExpression()
exitSlashContext(regexpliteral_token)
var result = <Unary kind={scan.tokenText(void_token)}>{first}</Unary>
}
else
if( lookahead(typeof_token) )
{
enterSlashContext(regexpliteral_token)
match(typeof_token)
var first = parsePostfixExpression()
exitSlashContext(regexpliteral_token)
var result = <Unary kind={scan.tokenText(typeof_token)}>{first}</Unary>
}
else
if( lookahead(plusplus_token) )
{
enterSlashContext(regexpliteral_token)
match(plusplus_token)
var first = parsePostfixExpression()
exitSlashContext(regexpliteral_token)
var result = <Unary kind={scan.tokenText(plusplus_token)}>{first}</Unary>
}
else
if( lookahead(minusminus_token) )
{
enterSlashContext(regexpliteral_token)
match(minusminus_token)
var first = parsePostfixExpression()
exitSlashContext(regexpliteral_token)
var result = <Unary kind={scan.tokenText(minusminus_token)}>{first}</Unary>
}
else
if( lookahead(plus_token) )
{
enterSlashContext(regexpliteral_token)
match(plus_token)
var first = parsePostfixExpression()
exitSlashContext(regexpliteral_token)
var result = <Unary kind={scan.tokenText(plus_token)}>{first}</Unary>
}
else
if( lookahead(minus_token) )
{
enterSlashContext(regexpliteral_token)
match(minus_token)
var first = parsePostfixExpression()
exitSlashContext(regexpliteral_token)
var result = <Unary kind={scan.tokenText(minus_token)}>{first}</Unary>
}
else
if( lookahead(bitwisenot_token) )
{
enterSlashContext(regexpliteral_token)
match(bitwisenot_token)
var first = parsePostfixExpression()
exitSlashContext(regexpliteral_token)
var result = <Unary kind={scan.tokenText(bitwisenot_token)}>{first}</Unary>
}
else
if( lookahead(not_token) )
{
enterSlashContext(regexpliteral_token)
match(not_token)
var first = parsePostfixExpression()
exitSlashContext(regexpliteral_token)
var result = <Unary kind={scan.tokenText(not_token)}>{first}</Unary>
}
else
{
var result = parsePostfixExpression()
}
Debug.exit("parseUnaryExpression",result)
return result
}
/*
YieldExpression
UnaryExpression
yield UnaryExpression
*/
function parseYieldExpression()
{
Debug.enter("parseYieldExpression")
if( lookahead(yield_token) )
{
enterSlashContext(regexpliteral_token)
match(yield_token)
if( !(lookaheadSemicolon(full_mode) || lookahead(rightparen_token) || lookahead(rightbrace_token) || lookahead(comma_token)) )
{
var first = parseUnaryExpression()
var result = <YieldExpression>{first}</YieldExpression>
}
else
{
var result = <YieldExpression/>
}
exitSlashContext(regexpliteral_token)
}
else
{
var result = parseUnaryExpression()
}
Debug.exit("parseYieldExpression",result)
return result
}
/*
MultiplicativeExpression
UnaryExpression
MultiplicativeExpression * UnaryExpression
MultiplicativeExpression / UnaryExpression
MultiplicativeExpression % UnaryExpression
*/
function parseMultiplicativeExpression()
{
Debug.enter("parseMultiplicativeExpression")
enterSlashContext(div_token)
var first = parseYieldExpression()
exitSlashContext(div_token)
while( true )
{
if( lookahead(mult_token) )
{
match(mult_token)
enterSlashContext(div_token)
var second = parseYieldExpression()
exitSlashContext(div_token)
var first = <Binary kind="multiply">{first}{second}</Binary>
}
else
if( lookahead(div_token) )
{
match(div_token)
enterSlashContext(div_token)
var second = parseYieldExpression()
exitSlashContext(div_token)
var first = <Binary kind="divide">{first}{second}</Binary>
}
else
if( lookahead(modulus_token) )
{
match(modulus_token)
enterSlashContext(div_token)
var second = parseYieldExpression()
exitSlashContext(div_token)
var first = <Binary kind="modulus">{first}{second}</Binary>
}
else
{
break // okay, none found
}
}
var result = first
Debug.exit("parseMultiplicativeExpression",result)
return result
}
/*
AdditiveExpression
MultiplicativeExpression
AdditiveExpression + MultiplicativeExpression
AdditiveExpression - MultiplicativeExpression
*/
function parseAdditiveExpression()
{
Debug.enter("parseAdditiveExpression")
var first = parseMultiplicativeExpression()
while( true )
{
if( lookahead(plus_token) )
{
match(plus_token)
var second = parseMultiplicativeExpression()
var first = <Binary kind="plus">{first}{second}</Binary>
}
else
if( lookahead(minus_token) )
{
match(minus_token)
var second = parseMultiplicativeExpression()
var first = <Binary kind="minus">{first}{second}</Binary>
}
else
{
break // okay, none found
}
}
var result = first
Debug.exit("parseAdditiveExpression",result)
return result
}
/*
ShiftExpression
AdditiveExpression
ShiftExpression << AdditiveExpression
ShiftExpression >> AdditiveExpression
ShiftExpression >>> AdditiveExpression
*/
function parseShiftExpression()
{
Debug.enter("parseShiftExpression")
var first = parseAdditiveExpression()
while( true )
{
if( lookahead(leftshift_token) )
{
match(leftshift_token)
var second = parseAdditiveExpression()
var first = <Binary kind="leftshift">{first}{second}</Binary>
}
else
if( lookahead(rightshift_token) )
{
match(rightshift_token)
var second = parseAdditiveExpression()
var first = <Binary kind="rightshift">{first}{second}</Binary>
}
else
if( lookahead(unsignedrightshift_token) )
{
match(unsignedrightshift_token)
var second = parseAdditiveExpression()
var first = <Binary kind="unsignedrightshift">{first}{second}</Binary>
}
else
{
break // okay, none found
}
}
var result = first
Debug.exit("parseShiftExpression",result)
return result
}
/*
RelationalExpressionallowIn
ShiftExpression
RelationalExpressionallowIn < ShiftExpression
RelationalExpressionallowIn > ShiftExpression
RelationalExpressionallowIn <= ShiftExpression
RelationalExpressionallowIn >= ShiftExpression
RelationalExpressionallowIn in ShiftExpression
RelationalExpressionallowIn instanceof ShiftExpression
RelationalExpressionallowIn is ShiftExpression
RelationalExpressionallowIn to ShiftExpression
RelationalExpressionallowIn cast ShiftExpression
*/
function parseRelationalExpression(mode)
{
Debug.enter("parseRelationalExpression")
var first = parseShiftExpression()
while( true )
{
if( lookahead(lessthan_token) )
{
match(lessthan_token)
var second = parseShiftExpression()
var first = <Binary kind="lessthan">{first}{second}</Binary>
}
else
if( lookahead(greaterthan_token) )
{
match(greaterthan_token)
var second = parseShiftExpression()
var first = <Binary kind="greaterthan">{first}{second}</Binary>
}
else
if( lookahead(lessthanorequals_token) )
{
match(lessthanorequals_token)
var second = parseShiftExpression()
var first = <Binary kind="lessthanorequals">{first}{second}</Binary>
}
else
if( lookahead(greaterthanorequals_token) )
{
match(greaterthanorequals_token)
var second = parseShiftExpression()
var first = <Binary kind="greaterthanorequals">{first}{second}</Binary>
}
else
if( mode === allowIn_mode && lookahead(in_token) )
{
match(in_token)
var second = parseShiftExpression()
var first = <Binary kind="in">{first}{second}</Binary>
}
else
if( lookahead(instanceof_token) )
{
match(instanceof_token)
var second = parseShiftExpression()
var first = <Binary kind="instanceof">{first}{second}</Binary>
}
else
if( lookahead(is_token) )
{
match(is_token)
var second = parseShiftExpression()
var first = <Binary kind="is">{first}{second}</Binary>
}
else
if( lookahead(to_token) )
{
match(to_token)
var second = parseShiftExpression()
var first = <Binary kind="to">{first}{second}</Binary>
}
else
if( lookahead(cast_token) )
{
match(cast_token)
var second = parseShiftExpression()
var first = <Binary kind="cast">{first}{second}</Binary>
}
else
{
break // okay, none found
}
}
var result = first
Debug.exit("parseRelationalExpression",result)
return result
}
/*
EqualityExpressionb
RelationalExpressionb
EqualityExpressionb == RelationalExpressionb
EqualityExpressionb != RelationalExpressionb
EqualityExpressionb === RelationalExpressionb
EqualityExpressionb !== RelationalExpressionb
*/
function parseEqualityExpression(mode)
{
Debug.enter("parseEqualityExpression")
var first = parseRelationalExpression(mode)
while( true )
{
if( lookahead(equals_token) )
{
match(equals_token)
var second = parseRelationalExpression(mode)
var first = <Binary kind="equals">{first}{second}</Binary>
}
else
if( lookahead(notequals_token) )
{
match(notequals_token)
var second = parseRelationalExpression(mode)
var first = <Binary kind="notequals">{first}{second}</Binary>
}
else
if( lookahead(strictequals_token) )
{
match(strictequals_token)
var second = parseRelationalExpression(mode)
var first = <Binary kind="strictequals">{first}{second}</Binary>
}
else
if( lookahead(strictnotequals_token) )
{
match(strictnotequals_token)
var second = parseRelationalExpression(mode)
var first = <Binary kind="strictnotequals">{first}{second}</Binary>
}
else
{
break // okay, none found
}
}
var result = first
Debug.exit("parseEqualityExpression",result)
return result
}
/*
BitwiseAndExpressionb
EqualityExpressionb
BitwiseAndExpressionrb & EqualityExpressionb
*/
function parseBitwiseAndExpression(mode)
{
Debug.enter("parseBitwiseAndExpression")
var first = parseEqualityExpression(mode)
while( lookahead(bitwiseand_token) )
{
match(bitwiseand_token)
var second = parseEqualityExpression(mode)
var first = <Binary kind="bitwiseand">{first}{second}</Binary>
}
var result = first
Debug.exit("parseBitwiseAndExpression",result)
return result
}
/*
BitwiseXorExpressionb
BitwiseAndExpressionb
BitwiseXorExpressionb ^ BitwiseAndExpressionb
*/
function parseBitwiseXorExpression(mode)
{
Debug.enter("parseBitwiseXorExpression")
var first = parseBitwiseAndExpression(mode)
while( lookahead(bitwisexor_token) )
{
match(bitwisexor_token)
var second = parseBitwiseAndExpression(mode)
var first = <Binary kind="bitwisexor">{first}{second}</Binary>
}
var result = first
Debug.exit("parseBitwiseXorExpression",result)
return result
}
/*
BitwiseOrExpressionb
BitwiseXorExpressionb
BitwiseOrExpressionb | BitwiseXorExpressionb
*/
function parseBitwiseOrExpression(mode)
{
Debug.enter("parseBitwiseOrExpression")
var first = parseBitwiseXorExpression(mode)
while( lookahead(bitwiseor_token) )
{
match(bitwiseor_token)
var second = parseBitwiseXorExpression(mode)
var first = <Binary kind="bitwiseor">{first}{second}</Binary>
}
var result = first
Debug.exit("parseBitwiseOrExpression",result)
return result
}
/*
LogicalAndExpressionb
BitwiseOrExpressionb
LogicalAndExpressionb && BitwiseOrExpressionb
*/
function parseLogicalAndExpression(mode)
{
Debug.enter("parseLogicalAndExpression")
var first = parseBitwiseOrExpression(mode)
while( lookahead(logicaland_token) )
{
match(logicaland_token)
var second = parseBitwiseOrExpression(mode)
var first = <Binary kind="bitwiseand">{first}{second}</Binary>
}
var result = first
Debug.exit("parseLogicalAndExpression",result)
return result
}
/*
LogicalXorExpressionb
LogicalAndExpressionb
LogicalXorExpressionb ^^ LogicalAndExpressionb
*/
function parseLogicalXorExpression(mode)
{
Debug.enter("parseLogicalXorExpression")
var first = parseLogicalAndExpression(mode)
while( lookahead(logicalxor_token) )
{
match(logicalxor_token)
var second = parseLogicalAndExpression(mode)
var first = <Binary kind="logicalxor">{first}{second}</Binary>
}
var result = first
Debug.exit("parseLogicalXorExpression",result)
return result
}
/*
LogicalOrExpressionb
LogicalXorExpressionb
LogicalOrExpressionallowIn || LogicalXorExpressionb
*/
function parseLogicalOrExpression(mode)
{
Debug.enter("parseLogicalOrExpression")
var first = parseLogicalXorExpression(mode)
while( lookahead(logicalor_token) )
{
match(logicalor_token)
var second = parsePostfixExpression() //parseLogicalXorExpression(mode)
var first = <Binary kind="logicalor">{first}{second}</Binary>
}
var result = first
Debug.exit("parseLogicalOrExpression",result)
return result
}
/*
*/
function parseConditionalExpression(mode)
{
Debug.enter("parseConditionalExpression",mode)
var result
var first
first = parseLogicalOrExpression(mode)
if( lookahead(questionmark_token) )
{
match(questionmark_token);
var second;
var third;
second = parseAssignmentExpression(mode);
match(colon_token);
third = parseAssignmentExpression(mode);
result = <ConditionalExpression>{first}{second}{third}</ConditionalExpression>
}
else
{
result = first
}
Debug.exit("parseConditionalExpression",result)
return result
}
/*
*/
function parseNonAssignmentExpression(mode)
{
Debug.enter("parseNonAssignmentExpression",mode)
//var first = parseLogicalOrExpression(mode)
var first = parsePostfixExpression()
if( lookahead(questionmark_token) )
{
match(questionmark_token);
var second = parseNonAssignmentExpression(mode);
match(colon_token);
var third = parseNonAssignmentExpression(mode);
var result = <ConditionalExpression>{first}{second}{third}</ConditionalExpression>
}
else
{
var result = first
}
Debug.exit("parseNonAssignmentExpression",result)
return result
}
/*
AssignmentExpressionb
ConditionalExpressionb
LetExpressionb
YieldExpressionb
PostfixExpression = AssignmentExpressionb
PostfixExpression CompoundAssignment AssignmentExpressionb
PostfixExpression LogicalAssignment AssignmentExpressionb
CompoundAssignment
*=
/=
%=
+=
-=
<<=
>>=
>>>=
&=
^=
|=
LogicalAssignment
&&=
^^=
||=
*/
function parseAssignmentExpression(mode)
{
Debug.enter("parseAssignmentExpression",mode)
if( lookahead(let_token) )
{
var result = parseLetExpression(mode)
}
else
{
var first = parseConditionalExpression(mode)
var found = lookahead(assign_token) ? match(assign_token) :
lookahead(multassign_token) ? match(multassign_token) :
lookahead(divassign_token) ? match(divassign_token) :
lookahead(modulusassign_token) ? match(modulusassign_token) :
lookahead(plusassign_token) ? match(plusassign_token) :
lookahead(minusassign_token) ? match(minusassign_token) :
lookahead(leftshiftassign_token) ? match(leftshiftassign_token) :
lookahead(rightshiftassign_token) ? match(rightshiftassign_token) :
lookahead(unsignedrightshiftassign_token) ? match(unsignedrightshiftassign_token) :
lookahead(bitwiseandassign_token) ? match(bitwiseandassign_token) :
lookahead(bitwisexorassign_token) ? match(bitwisexorassign_token) :
lookahead(bitwiseorassign_token) ? match(bitwiseorassign_token) :
lookahead(logicalandassign_token) ? match(logicalandassign_token) :
lookahead(logicalxorassign_token) ? match(logicalxorassign_token) :
lookahead(logicalorassign_token) ? match(logicalorassign_token) : empty_token;
if( found != empty_token )
{
if( first.name() != "Get" &&
first.name() != "Call" &&
first.name() != "Set" )
{
throw "invalid expression on left side of assignment"
}
var second = parseAssignmentExpression(mode)
if( first.name() == "Get" )
{
first.setLocalName("Set")
first.value = <To>{second}<SlotTypeRef/></To>
}
else
{
first = <Set kind="lexical">{first}<To>{second}<SlotTypeRef/></To></Set>
}
var result = first
}
else
{
var result = first
}
}
Debug.exit("parseAssignmentExpression",result)
return result
}
function parseAssignmentExpressionSuffix(mode, first)
{
}
/*
LetExpressionb
let ( LetBindingList ) AssignmentExpressionb
LetBindingList
<20>empty<74>
NonemptyLetBindingList
NonemptyLetBindingList
VariableBinding
VariableBinding , NonemptyLetBindingList
*/
function parseLetExpression(mode)
{
Debug.enter("parseLetExpression")
var prologue = <Prologue/>
match(let_token)
match(leftparen_token)
if( lookahead(rightparen_token) )
{
var first = <></>
}
else
{
var first = <></>
first += parseVariableBinding(<Attributes><Let/></Attributes>,var_token,allowIn_mode,prologue)
while( lookahead(comma_token) )
{
match(comma_token)
first += parseVariableBinding(<Attributes><Let/></Attributes>,var_token,allowIn_mode,prologue)
}
prologue.* += first
}
match(rightparen_token)
var second = parseAssignmentExpression(mode)
var result = <LetExpression>{prologue}{second}</LetExpression>
Debug.exit("parseLetExpression",result)
return result
}
/*
YieldExpressionb
yield AssignmentExpressionb
*/
/*
function parseYieldExpression(mode)
{
Debug.enter("parseYieldExpression")
Debug.exit("parseYieldExpression",result)
return result
}
*/
/*
DestructuringAssignmentExpression
DestructuringPattern = AssignmentExpressionb
*/
function parseDestructuringAssignmentExpression(mode)
{
Debug.enter("parseDestructuringAssignmentExpression",mode)
var first = parseDestructuringPattern()
match(assign_token)
var second = parseAssignmentExpression(mode)
var result = <AssignmentExpression>{first}{second}</AssignmentExpression>
Debug.exit("parseDestructuringAssignmentExpression",result)
return result
}
/*
DestructuringPattern
DestructuringObjectPattern
DestructuringArrayPattern
*/
function parseDestructuringPattern()
{
Debug.enter("parseDestructuringPattern")
if( lookahead(leftbrace_token) )
{
var result = parseDestructuringObjectPattern()
}
else
if( lookahead(leftbracket_token ) )
{
var result = parseDestructuringArrayPattern()
}
else
{
throw "expecting destrcturing pattern"
}
Debug.exit("parseDestructuringPattern",result)
return result
}
/*
DestructuringObjectPattern
{ DestructuringFieldList }
DestructuringFieldList
DestructuringField
DestructuringFieldList , DestructuringField
*/
function parseDestructuringObjectPattern()
{
Debug.enter("parseDestructuringObjectPattern")
enterSlashContext(regexpliteral_token)
match(leftbrace_token)
var first = <></>
first += parseDestructuringField()
while( lookahead(comma_token) )
{
match(comma_token)
first += parseDestructuringField()
}
match(rightbrace_token)
exitSlashContext(regexpliteral_token)
var result = <DestructuringObjectPattern>{first}</DestructuringObjectPattern>
Debug.exit("parseDestructuringObjectPattern",result)
return result
}
/*
DestructuringField
NonAttributeQualifiedIdentifier : DestructuringPattern
NonAttributeQualifiedIdentifier : PostfixExpression
*/
function parseDestructuringField()
{
Debug.enter("parseDestructuringField")
var first = parseNonAttributeQualifiedIdentifier()
match(colon_token)
if( lookahead(leftbrace_token) || lookahead(leftbracket_token) )
{
var second = parseDestructuringPattern()
var result = <DestructuringField>{first}{second}</DestructuringField>
}
else
{
var second = parsePostfixExpression()
var result = <DestructuringField>{first}{second}</DestructuringField>
}
Debug.exit("parseDestructuringField",result)
return result
}
/*
DestructuringArrayPattern
[ DestructuringElementList ]
DestructuringElementList
<20>empty<74>
DestructuringElement
, DestructuringElementList
DestructuringElement , DestructuringElementList
*/
function parseDestructuringArrayPattern()
{
Debug.enter("parseDestructuringArrayPattern")
enterSlashContext(regexpliteral_token)
match(leftbracket_token)
if( lookahead(rightbracket_token) )
{
var first = <></>
}
else
{
var first = <></>
first += parseDestructuringElement()
while( lookahead(comma_token) )
{
match(comma_token)
if( lookahead(rightbracket_token) )
{
// do nothing, we're done
}
else
{
first += parseDestructuringElement()
}
}
}
match(rightbracket_token)
exitSlashContext(regexpliteral_token)
var result = <DestructuringArrayPattern>{first}</DestructuringArrayPattern>
Debug.exit("parseDestructuringArrayPattern",result)
return result
}
/*
DestructuringElement
<20>empty<74>
DestructuringPattern
PostfixExpression
*/
function parseDestructuringElement()
{
Debug.enter("parseDestructuringElement")
if( lookahead(comma_token) )
{
var result = <EmptyElement/>
}
else
if( lookahead(leftbrace_token) || lookahead(leftbracket_token) )
{
var result = parseDestructuringPattern()
}
else
{
var result = parseAssignmentExpression(allowIn_mode)
}
Debug.exit("parseDestructuringElement",result)
return result
}
/*
ListExpression
*/
function parseListExpression(mode)
{
Debug.enter("parseListExpression",mode)
var list = <></>
list += parseAssignmentExpression(mode)
while( lookahead( comma_token ) )
{
match( comma_token );
list += parseAssignmentExpression(mode)
}
var node = list
Debug.exit("parseListExpression",node)
return node
}
function parseListExpressionPrime(first,mode)
{
Debug.enter("parseListExpressionPrime",mode)
var list = <></>
list += first
while( lookahead( comma_token ) )
{
match( comma_token );
list += parseAssignmentExpression(mode)
}
var node = list
Debug.exit("parseListExpressionPrime",node)
return node
}
// TYPE EXPRESSIONS
/*
TypeExpression
TypeIdentifier
function FunctionSignature
( TypeExpressionList )
{ FieldTypeList }
[ ElementTypeList ]
*/
function parseTypeExpression()
{
Debug.enter("parseTypeExpression")
var prologue = <Prologue/>
if( lookahead(function_token) )
{
match(function_token)
var result = parseFunctionSignature(prologue)
}
else
if( lookahead(leftparen_token) )
{
var result = parseUnionType()
}
else
if( lookahead(leftbrace_token) )
{
var result = parseRecordType()
}
else
if( lookahead(leftbracket_token) )
{
var result = parseArrayType()
}
else
{
var result = parseTypeIdentifier()
if( lookahead(not_token) )
{
match(not_token)
result.@nullable="false"
}
else
if( lookahead(questionmark_token) )
{
match(questionmark_token)
result.@nullable="true"
}
}
Debug.exit("parseTypeExpression",result.toXMLString())
return result
}
/*
UnionType
( TypeExpressionList )
*/
function parseUnionType()
{
Debug.enter("parseUnionType")
match(leftparen_token)
var first = parseTypeExpressionList()
var result = <UnionType>{first}</UnionType>
match(rightparen_token)
Debug.exit("parseUnionType",result)
return result
}
/*
RecordType
{ FieldTypeList }
*/
function parseRecordType()
{
Debug.enter("parseRecordType")
match(leftbrace_token)
if( lookahead(rightbrace_token) )
{
var first = <></>
}
else
{
var first = parseFieldTypeListPrime(<>{parseFieldType()}</>)
}
var result = <RecordType>{first}</RecordType>
match(rightbrace_token)
Debug.exit("parseRecordType",result)
return result
}
/*
NonemptyFieldTypeList
FieldType
FieldType , NonemptyFieldTypeList
*/
function parseFieldTypeListPrime(first)
{
Debug.enter("parseNonemptyFieldTypeList",first)
if( lookahead(comma_token) )
{
match(comma_token)
var second = parseFieldType()
var result = parseFieldTypeListPrime(<>{first}{second}</>)
}
else
{
var result = first
}
Debug.exit("parseFieldListPrime",result)
return result
}
/*
FieldType
FieldName : TypeExpression
*/
function parseFieldType()
{
Debug.enter("parseFieldType")
var first = parseFieldName()
match(colon_token)
var second = parseTypeExpression()
var result = <FieldType>{first}{second}</FieldType>
Debug.exit("parseFieldType",result)
return result
}
/*
ArrayType
[ ElementTypeList ]
ElementTypeList
<20>empty<74>
TypeExpression
, ElementTypeList
TypeExpression , ElementTypeList
*/
function parseArrayType()
{
Debug.enter("parseArrayType")
enterSlashContext(regexpliteral_token)
match(leftbracket_token)
if( lookahead(rightbracket_token) )
{
var first = <></>
}
else
{
var temp = parseElementType()
var first = parseElementTypeListPrime(<>{temp}</>)
}
exitSlashContext(regexpliteral_token)
match(rightbracket_token)
var result = <LiteralType>{first}</LiteralType>
Debug.exit("parseArrayLiteral",result)
return result
}
function parseElementTypeListPrime(first)
{
Debug.enter("parseElementTypeListPrime",first)
while( lookahead(comma_token) )
{
match(comma_token)
var second = parseElementType()
if( second == null )
{
// do nothing
}
else
{
var first = <>{first}{second}</>
}
}
var result = first
Debug.exit("parseElementTypeListPrime",result)
return result
}
function parseElementType()
{
Debug.enter("parseElementType")
if( lookahead(comma_token) )
{
var result = <EmptyElementType/>
}
else
if( lookahead(rightbracket_token) )
{
var result = null
}
else
{
var result = parseTypeExpression()
}
Debug.exit("parseElementType",result)
return result
}
// STATEMENTS
/*
Statement
*/
function parseStatement(mode)
{
Debug.enter("parseStatement",mode)
if( lookahead(super_token) )
{
var node = parseSuperStatement()
matchSemicolon(mode)
}
else
if( lookahead(leftbrace_token) )
{
var node = parseBlockStatement()
}
else
if( lookahead(if_token) )
{
var node = parseIfStatement(mode)
}
else
if( lookahead(switch_token) )
{
var node = parseSwitchStatement() //includes 'switch type'
}
else
if( lookahead(do_token) )
{
var node = parseDoStatement()
matchSemicolon(mode)
}
else
if( lookahead(while_token) )
{
var node = parseWhileStatement(mode)
}
else
if( lookahead(for_token) )
{
var node = parseForStatement(mode)
}
else
if( lookahead(let_token) )
{
match(let_token) // because other context do
var node = parseLetStatement(mode)
}
else
if( lookahead(with_token) )
{
var node = parseWithStatement(mode)
}
else
if( lookahead(continue_token) )
{
var node = parseContinueStatement()
matchSemicolon(mode)
}
else
if( lookahead(break_token) )
{
var node = parseBreakStatement()
matchSemicolon(mode)
}
else
if( lookahead(return_token) )
{
var node = parseReturnStatement()
matchSemicolon(mode)
}
else
if( lookahead(throw_token) )
{
var node = parseThrowStatement()
matchSemicolon(mode)
}
else
if( lookahead(try_token) )
{
var node = parseTryStatement()
}
else
if( lookahead(default_token) )
{
var node = parseDefaultXMLNamespaceStatement()
matchSemicolon(mode)
}
else
{
var node = parseLabeledOrExpressionStatement(mode)
matchSemicolon(mode)
}
Debug.exit("parseStatement",node)
return node
}
/*
*/
function parseSubstatement(mode)
{
Debug.enter("parseSubstatement")
var node = parseStatement(mode)
Debug.exit("parseSubstatement",node)
return node
}
function parseBlockStatement()
{
Debug.enter("parseSubstatement")
var prologue = <Prologue/>
var stmts = parseBlock(prologue)
//var slots = stmts.Slot // hoist let slots
//delete stmts.Slot
var node = <BlockStatement>{prologue}{stmts}</BlockStatement>
Debug.exit("parseBlockStatement",node)
return node
}
/*
SuperExpression
super
super Arguments
*/
function parseSuperStatement()
{
Debug.enter("parseSuperStatement")
match(super_token)
var first = <SuperStatement/>
if( lookahead(leftparen_token) )
{
var result = parseArguments(first)
}
else
{
var result = first
}
Debug.exit("parseSuperStatement",result)
return result
}
function parseLabeledOrExpressionStatement(mode)
{
Debug.enter("parseLabeledOrExpressionStatement",mode)
var first = parseListExpression(allowIn_mode)
if( lookahead(colon_token) )
{
if( first.length() == 1 || first.Get.identifier != void 0 )
{
first = first.Get.identifier
}
else
{
throw "invalid label"
}
match(colon_token)
var second = parseSubstatement(mode)
var result = <LabeledStatement>{first}{second}</LabeledStatement>
}
else
{
var result = <ExpressionStatement>{first}</ExpressionStatement>
// leave matchSemicolon(mode) for caller
}
Debug.exit("parseLabeledOrExpressionStatement",result)
return result
}
function parseBlock(prologue)
{
Debug.exit("parseBlock")
match(leftbrace_token)
var node = parseDirectives(void 0,prologue)
match(rightbrace_token)
Debug.exit("parseBlock",node)
return node
}
function parseMetaData()
{
}
function parseIfStatement(mode)
{
}
function parseSwitchStatement()
{
}
function parseCaseStatement(mode)
{
}
function parseCaseLabel()
{
}
function parseCaseStatements()
{
}
function parseCaseStatementsPrefix(first)
{
}
function parseDoStatement()
{
}
function parseWhileStatement(mode)
{
}
function parseForStatement(mode)
{
}
function parseLetStatement(mode)
{
Debug.enter("parseLetStatement")
// already ate 'let'
var prologue = <Prologue/>
var block = <Block/>
match(leftparen_token)
if( lookahead(rightparen_token) )
{
}
else
{
block.* += parseVariableBinding(<Attributes><Let/></Attributes>,var_token,allowIn_mode,prologue)
while( lookahead(comma_token) )
{
match(comma_token)
block.* += parseVariableBinding(<Attributes><Let/></Attributes>,var_token,allowIn_mode,prologue)
}
}
match(rightparen_token)
var second = parseSubstatement(mode)
if( second.name() == "BlockStatement" )
{
prologue.* += second.Prologue.*
block.* += second.Block.*
}
else
{
block.* += second
}
var node = <BlockStatement kind="let">{prologue}{block}</BlockStatement>
Debug.exit("parseLetStatement",node)
return node
}
function parseWithStatement(mode)
{
throw "WithStatement not implemented"
}
function parseContinueStatement()
{
throw "ContinueStatement not implemented"
}
function parseBreakStatement()
{
throw "BreakStatement not implemented"
}
/*
ReturnStatement
return
return [no line break] ListExpressionallowIn
*/
function parseReturnStatement()
{
Debug.enter("parseReturnStatement")
match(return_token)
if( !inFunctionBody(true) )
{
throw "return statement is not allowed outside of function body"
}
var node = <Return/>
if( !lookaheadSemicolon(full_mode) )
{
node.* = parseListExpression(allowIn_mode)
}
Debug.exit("parseReturnStatement",node)
return node
}
function parseThrowStatement()
{
throw "ThrowStatement not implemented"
}
function parseTryStatement()
{
throw "TryStatement not implemented"
}
function parseCatchClauses()
{
throw "CatchClauses not implemented"
}
function parseCatchClause()
{
throw "CatchClause not implemented"
}
function parseFinallyClause()
{
throw "FinallyClause not implemented"
}
function parseDefaultXMLNamespaceStatement()
{
throw "DefaultXMLNamespaceStatement not implemented"
}
function parseAnnotatedDirective(mode)
{
throw "AnnotatedDirective not implemented"
}
function parseAnnotatedSubstatementsOrStatement(mode)
{
throw "not implemented"
}
function parseAnnotatableDirective(attrs,mode,prologue)
{
Debug.enter("parseAnnotatableDirective",attrs,mode)
if( lookahead(let_token) )
{
match(let_token)
attrs.* += <Let/> // the let attribute
if( lookahead(function_token) )
{
var node = parseFunctionDefinition(attrs,prologue)
}
else
{
var node = parseVariableDefinition(attrs,allowIn_mode,prologue)
matchSemicolon(mode)
}
}
else
if( lookahead(var_token) )
{
match(var_token) // eat 'var' before calling parseVar...
var node = parseVariableDefinition(attrs,allowIn_mode,prologue)
}
else
if( lookahead(const_token) )
{
var node = parseVariableDefinition(attrs,allowIn_mode,prologue)
}
else
if( lookahead(function_token) )
{
var node = parseFunctionDefinition(attrs,prologue)
}
else
if( lookahead(class_token) )
{
var node = parseClassDefinition(attrs,prologue)
}
else
if( lookahead(interface_token) )
{
var node = parseInterfaceDefinition(attrs,prologue)
}
else
if( lookahead(namespace_token) )
{
var node = parseNamespaceDefinition(attrs,prologue)
}
else
if( lookahead(type_token) )
{
var node = parseTypeDefinition(attrs,prologue)
}
else
{
throw "not implemented yet"
}
Debug.exit("parseAnnotatableDirective",node)
return node
}
function parseAnnotatableDirectiveOrLetStatement(attrs,mode,prologue) // actually only need to handle let bindings and let statements
{
Debug.enter("parseAnnotatableDirectiveOrLetStatement",attrs,mode)
match(let_token)
if( lookahead(leftparen_token ) ) // Let statement
{
var node = parseLetStatement(mode)
}
else // Let binding
{
attrs.* += <Let/> // the let attribute
if( lookahead(function_token) )
{
var node = parseFunctionDefinition(attrs,prologue)
}
else
{
var node = parseVariableDefinition(attrs,allowIn_mode,prologue)
}
}
Debug.exit("parseAnnotatableDirectiveOrLetStatement",node)
return node
}
function parseIncludeDirective()
{
}
function parseVariableDefinition(first,mode,prologue)
{
Debug.enter("parseVariableDefinition",first,mode)
// already ate 'let' if there was one, so will see 'const' or nothing (which means 'var')
// if there is no 'let' then caller must eat 'var' before calling to avoid 'let var'
var second = lookahead(const_token) ? match(const_token) : var_token
if( inInterfaceBody() )
{
throw "variable definition is not allowed in an interface"
}
var first = parseVariableBindingList(first,second,mode,prologue);
var node = first
Debug.exit("parseVariableDefinition",node)
return node
}
function parseVariableBindingList(attrs,kind,mode,prologue)
{
Debug.enter("parseVariableBindingList",attrs,kind,mode)
var node = <></>
node += parseVariableBinding(attrs,kind,mode,prologue)
while( lookahead( comma_token ) )
{
match( comma_token );
node += parseVariableBinding(attrs,kind,mode,prologue);
}
Debug.exit("parseVariableBindingList",node)
return node
}
/*
VariableBindingb
TypedIdentifierb VariableInitialisationb
DestructuringPattern VariableInitialisationb
VariableInitialisationb
<20>empty<74>
= VariableInitialiserb
VariableInitialiserb
AssignmentExpressionb
*/
function isNamespaceAttribute(attr)
{
Debug.enter("isNamespaceAttribute",attr.toXMLString())
var result =
( attr.name()=="Get" &&
attr.Identifier != undefined ) ? true :
attr.name()=="Namespace" ? true : false
Debug.exit("isNamespaceAttribute",result)
return result
}
function inFunctionBody(recurse=false)
{
Debug.enter("inFunctionBody")
if( recurse )
{
var result = false
for each( var item in slot_context_stack )
{
if( item=="function" )
{
result = true
break
}
}
}
else
{
var context = slot_context_stack[slot_context_stack.length-1]
var result = context=="function"
}
Debug.exit("inFunctionBody",result)
return result
}
function inClassBody()
{
Debug.enter("inClassBody")
var context = slot_context_stack[slot_context_stack.length-1]
var result = context=="class"
Debug.exit("inClassBody",result)
return result
}
function inInterfaceBody()
{
Debug.enter("inInterfaceBody")
var context = slot_context_stack[slot_context_stack.length-1]
var result = context=="interface"
Debug.exit("inInterfaceBody",result)
return result
}
function inClassOrInterfaceBody()
{
Debug.enter("inClassOrInterfaceBody")
var context = slot_context_stack[slot_context_stack.length-1]
var result = context=="class" || context=="interface"
Debug.exit("inClassOrInterfaceBody",result)
return result
}
function parseVariableBinding(attrs,kind,mode,prologue)
{
Debug.enter("parseVariableBinding",attrs,kind,mode)
if( lookahead(leftbrace_token) || lookahead(leftbracket_token) )
{
var first = parseDestructuringPattern()
match(assign_token)
var second = parseAssignmentExpression(mode)
}
else
{
var first = parseTypedIdentifier(mode)
if( lookahead(assign_token) )
{
match(assign_token)
var second = parseAssignmentExpression(mode);
}
else
{
var second
}
var node = makeBinding(attrs,kind,first,second,prologue)
}
Debug.exit("parseVariableBinding",node)
return node
}
/*
Make a slot
For some kinds of bindings we hoist the intialiser to the prologue along with
the slot (instance slots, function slots). The value of a function slot
initialiser is moved by the Definer to derive an ExpressionStatement inserted
at the beginning of the corresponding Block. The Definer also hoists some
slots (var,const,function) to the inner most enclosing variable object
(global,class,function)
*/
function makeBinding(attrs,kind,typedid,value,prologue)
{
Debug.enter("makeBinding",attrs,kind,typedid,value)
// See if there is one namespace attribute
var ns = null
for each( var attr in attrs.* )
{
if( isNamespaceAttribute(attr) )
{
if( ns === null )
{
ns = attr
}
else
{
throw "only one namespace attribute allowed"
}
}
}
// Make a qualified identifier
if( ns != null )
{
var name =
<QualifiedIdentifier>
<Qualifier>{ns}</Qualifier>
{typedid.Identifier}
</QualifiedIdentifier>
}
else // use the default namespace
{
var name =
<QualifiedIdentifier>
<Qualifier>
{default_namespace}
</Qualifier>
{typedid.Identifier}
</QualifiedIdentifier>
}
// Get the type if it has one
if( typedid.name() == "TypedIdentifier" )
{
var type = typedid.Type.*
}
else
if( kind == class_token )
{
var type = <Identifier name="Class"/>
}
else
{
var type = <Identifier name="Object"/>
}
// Make the slot and initialiser
if( kind == class_token ||
kind == interface_token ||
kind == function_token ||
kind == namespace_token ||
kind == type_token ||
inClassBody() && attrs.Let == void 0 && attrs.Static == void 0 )
{
var slot =
<Slot kind={scan.tokenText(kind)}>
<Name>{name}</Name>
<Type>{type}</Type>
<Init>{value}</Init>
</Slot>
if( kind == function_token && inClassOrInterfaceBody() )
{
slot.@method="true"
}
var init = <></>
}
else
{
var slot =
<Slot kind={scan.tokenText(kind)}>
<Name>{name}</Name>
<Type>{type}</Type>
</Slot>
if( value != void 0 )
{
var init = <>
<ExpressionStatement>
<Set kind="lexical">
{name}<To>{value}{typedid.Type}</To>
</Set>
</ExpressionStatement></>
}
else
{
var init = <></>
}
}
// Apply attributes to the slot
applyAttributesToSlot(attrs,slot)
// Return the results
var node = init
if( slot.@static == "true" )
{
prologue.Static.* += slot
}
else
if( inClassBody() && slot.@let != "true" )
{
prologue.Instance.* += slot
}
else
{
prologue.* += slot
}
Debug.exit("makeBinding",node,slot,prologue)
return node
}
var slot_context_stack = ["global"]
function applyAttributesToSlot(attrs,slot)
{
Debug.enter("applyAttributesToSlot",attrs.toXMLString(),slot)
var slot_context = slot_context_stack[slot_context_stack.length-1]
var slot_kind = slot.@kind
if( attrs.Let != void 0 )
{
slot.@let = true
}
if( attrs.Dynamic != void 0 )
{
if( slot_kind == "class" )
{
slot.@dynamic = true
}
else
{
throw "'dynamic' must only be used on class definitions"
}
}
if( attrs.Final != void 0 )
{
if( slot_kind == "class" ||
(slot_context == "class" && slot_kind == "function" && attrs.Static == void 0 ) )
{
slot.@final = true
}
else
{
throw "'final' must only be used on class and non-static method definitions"
}
}
if( attrs.Native != void 0 )
{
if( slot_kind == "function" && slot_context != "function" )
{
slot.@native = true
}
else
{
throw "'native' must only be used on non-nested function definitions"
}
}
if( attrs.Override != void 0 )
{
if( slot_context == "class" && slot_kind == "function" && attrs.Static == void 0 )
{
slot.@override = true
}
else
{
throw "'override' must only be used on non-static method definitions"
}
}
if( attrs.Prototype != void 0 )
{
if( slot_context == "class" && attrs.Static == void 0 )
{
slot.@prototype = true
}
else
{
throw "'prototype' must only be used on non-static class variable and method definitions"
}
}
if( attrs.Static != void 0 )
{
if( slot_context == "class" )
{
slot.@static = true
}
else
{
throw "'static' must only be used on non-static class variable and method definitions"
}
}
if( attrs.get != void 0 )
{
if( slot.@kind == "function" )
{
slot.@kind = "function get"
}
else
{
throw "'get' must be used on function bindings only"
}
}
if( attrs.set != void 0 )
{
if( slot.@kind == "function" )
{
slot.@kind = "function set"
}
else
{
throw "'set' must be used on function bindings only"
}
}
if( attrs.call != void 0 )
{
if( slot.@kind == "function" )
{
slot.@kind = "function call"
}
else
{
throw "'call' must be used on function bindings only"
}
}
if( attrs.to != void 0 )
{
if( slot.@kind == "function" )
{
slot.@kind = "function to"
}
else
{
throw "'to' must be used on function bindings only"
}
}
if( attrs.operator != void 0 )
{
if( slot.@kind == "function" )
{
slot.@kind = "function operator"
}
else
{
throw "internal error"
}
}
if( attrs.parameter != void 0 )
{
if( slot.@kind == "var" || slot.@kind == "const" )
{
slot.@is_param = "true"
print("parameter slot found",slot)
}
else
{
throw "internal error"
}
}
Debug.exit("applyAttributesToSlot",slot)
return
}
function parseTypedIdentifier(mode)
{
Debug.enter("parseTypedIdentifier",mode)
var first = parseIdentifier()
if( lookahead(colon_token) )
{
match(colon_token)
if( lookahead(mult_token) )
{
match(mult_token);
var second = <Type><Identifier name="*"/></Type> // same as no annotation
}
else
if( lookahead(multassign_token) )
{
var nexttoken=assign_token; // morph into an assign token
var second = <Type><Identifier name="*"/></Type> // same as no annotation
}
else
{
var second = <Type>{parseTypeExpression()}</Type>
}
var result = <TypedIdentifier>{first}{second}</TypedIdentifier>
}
else
{
var result = <TypedIdentifier>{first}<Type><Identifier name="*"/></Type></TypedIdentifier>
}
Debug.exit("parseTypedIdentifier",result)
return result
}
function parseSimpleVariableDefinition()
{
}
function parseUntypedVariableBindingList()
{
}
function parseUntypedVariableBinding()
{
}
function parseFunctionDefinition(attrs,prologue)
{
Debug.enter("parseFunctionDefinition",attrs)
var kind = match(function_token)
var name = parseFunctionName()
var value = parseFunctionCommon(<></>)
attrs.* += <{name.@kind}/> // add functionname kind to attrs
var node = makeBinding(attrs,kind,name,value,prologue)
Debug.exit("parseFunctionDefinition",node)
return node
}
function parseFunctionName()
{
Debug.enter("parseFunctionName")
if( lookahead(identifier_token) )
{
var kind = "empty"
var first = parseIdentifier()
}
else
if( lookahead(to_token) )
{
var kind = scan.tokenText(match(to_token))
var first = parseIdentifier()
}
else
if( lookahead(get_token) )
{
var kind = scan.tokenText(match(get_token))
var first = parsePropertyIdentifier()
}
else
if( lookahead(set_token) )
{
var kind = scan.tokenText(match(set_token))
var first = parsePropertyIdentifier()
}
else
if( lookahead(call_token) )
{
var kind = scan.tokenText(match(call_token))
var first = parsePropertyIdentifier()
}
else
{
var found = lookahead(mult_token) ? match(mult_token) :
lookahead(div_token) ? match(div_token) :
lookahead(modulus_token) ? match(modulus_token) :
lookahead(plus_token) ? match(plus_token) :
lookahead(minus_token) ? match(minus_token) :
lookahead(leftshift_token) ? match(leftshift_token) :
lookahead(rightshift_token) ? match(rightshift_token) :
lookahead(unsignedrightshift_token) ? match(unsignedrightshift_token) :
lookahead(bitwiseand_token) ? match(bitwiseand_token) :
lookahead(bitwisexor_token) ? match(bitwisexor_token) :
lookahead(bitwiseor_token) ? match(bitwiseor_token) :
lookahead(strictequals_token) ? match(strictequals_token) :
lookahead(notequals_token) ? match(notequals_token) :
lookahead(strictnotequals_token) ? match(strictnotequals_token) : empty_token
if( found != empty_token )
{
var kind = "operator"
var first = <Identifier name={scan.tokenText(found)}/>
}
}
var node = <FunctionName kind={kind}>{first}</FunctionName>
Debug.exit("parseFunctionName",node)
return node
}
var current_class = null
/*
class A { function A(){} var x = 10; function m() {}; print("hello") }
class 'A'
prologue
slot 'iinit' function
prologue
slot 'construct' function ...
slot 'x' 10
slot 'm' function ...
block
block
print("hello")
bindings: class field initialisers are not hoisted
with their slots but instance var initialisers are
*/
function parseClassDefinition(attrs,hoisted)
{
Debug.enter("parseClassDefinition",attrs)
match(class_token)
var name = parseClassName()
current_class = name
slot_context_stack.push("class") // use to determine if inits are hoisted
var inherits = parseInheritance()
var stmt = parseBlockStatement()
// Move the static and instance slots out of the embedded block statement
var prologue = <Prologue>{stmt.Prologue.Static.*}<Instance>{stmt.Prologue.Instance.*}</Instance></Prologue>
delete stmt.Prologue.Static
delete stmt.Prologue.Instance
slot_context_stack.pop()
current_class = null
var value = <Class>{name}{inherits}{prologue}<Block>{stmt}</Block></Class>
delete value.Block.BlockStatement.Prologue.Static
var node = makeBinding(attrs,class_token,name,value,hoisted)
Debug.exit("parseClassDefinition",node)
return node
}
function parseClassName()
{
var first = parseIdentifier()
if( lookahead(leftdotangle_token) )
{
var second = parseTypeParameters()
}
else
{
var second = <></>
}
if( lookahead(not_token) )
{
match(not_token)
var node = <ClassName not_nullable="true">{first}{second}</ClassName>
}
else
{
var node = <ClassName>{first}{second}</ClassName>
}
return node
}
/*
Inheritance
<20>empty<74>
extends TypeName
implements TypeNameList
extends TypeName implements TypeNameList
*/
function parseInheritance()
{
Debug.enter("parseInheritance")
var node = <Inheritance/>
if( lookahead(extends_token) )
{
match(extends_token)
var first = parseTypeName()
node.Extends.* = first
if( lookahead(implements_token) )
{
match(implements_token)
var second = parseTypeNameList()
node.Implements.* = second
}
}
else
if( lookahead(implements_token) )
{
match(implements_token)
var second = parseTypeNameList()
node.Implements.* = second
}
Debug.exit("parseInheritance",node)
return node
}
function parseTypeName()
{
return parseTypeIdentifier()
}
function parseTypeNameList()
{
var node = <></>
node += parseTypeIdentifier()
while( lookahead(comma_token) )
{
match(comma_token)
node += parseTypeIdentifier()
}
return node
}
function parseInterfaceDefinition(attrs,hoisted)
{
Debug.enter("parseInterfaceDefinition",attrs)
match(interface_token)
var name = parseClassName()
current_class = name
slot_context_stack.push("interface")
var inherits = parseExtendsList()
var last_default_namespace = default_namespace
default_namespace = <Namespace kind="interface" name={name.Identifier.@name}/>
var stmt = parseBlockStatement()
default_namespace = last_default_namespace
slot_context_stack.pop()
current_class = null
var value = <Interface>{name}{inherits}{stmt.Prologue}{stmt.Block}</Interface>
var node = makeBinding(attrs,interface_token,name,value,hoisted)
Debug.exit("parseInterfaceDefinition",node)
return node
}
/*
ExtendsList
<20>empty<74>
extends TypeNameList
*/
function parseExtendsList()
{
Debug.enter("parseExtendsList")
var node = <Inheritance/>
if( lookahead(extends_token) )
{
match(extends_token)
var first = parseTypeNameList()
node.Extends.* = first
}
Debug.exit("parseExtendsList",node)
return node
}
/*
TypeExpressionList
TypeExpression
TypeExpressionList , TypeExpression
*/
function parseTypeExpressionList()
{
Debug.enter("parseTypeExpressionList")
var list = <></>
list += parseTypeExpression()
while( lookahead( comma_token ) )
{
match( comma_token );
list += parseTypeExpression()
}
var result = list
Debug.exit("parseTypeExpressionList",result)
return result
}
function parseNamespaceDefinition(attrs,prologue)
{
Debug.enter("parseNamespaceDefinition",attrs)
match(namespace_token)
var first = parseTypedIdentifier(allowIn_mode)
if( lookahead(assign_token) )
{
match(assign_token)
if( lookahead(stringliteral_token) )
{
var second = <LiteralString value={scan.tokenText(match(stringliteral_token))}/>
}
else
{
var second = <Get kind="lexical">{parseSimpleTypeIdentifier()}</Get>
}
}
else
{
var second = <UniqueNamespaceName/>
}
if( inClassBody() )
{
attrs.* += <Static/>
}
var node = makeBinding(attrs,namespace_token,first,second,prologue)
Debug.exit("parseNamespaceDefinition",node)
return node
}
/*
*/
function parseTypeDefinition(attrs,hoisted)
{
Debug.enter("parseTypeDefinition",attrs)
match(type_token)
var first = parseTypedIdentifier(allowIn_mode)
match(assign_token)
var second = parseTypeExpression()
var node = makeBinding(attrs,type_token,first,second,hoisted)
Debug.exit("parseTypeDefinition",node)
return node
}
/*
PackageDefinition
PackageAttributes package PackageNameOpt Block
PackageAttributes
private
<20>empty<74>
PackageNameOpt
<20>empty<74>
PackageName
PackageName [create a lexical PackageIdentifier with the sequence of characters that make a PackageName]
Identifier
PackageName . Identifier
*/
var current_package
function parsePackageDefinition(attr)
{
Debug.enter("parsePackageDefinition")
enterSlashContext(div_token)
match(package_token)
var name = parsePackageName()
exitSlashContext(div_token)
current_package = name
default_namespace = <Namespace kind="internal" name={name}/>
var stmt = parseBlockStatement()
var block = stmt.Block
var prologue = stmt.Prologue
current_package = null
stmt.@name=name
stmt.@kind="package"
var node = stmt
// prologue.insertChildBefore(prologue.*[0],
stmt.Prologue.* +=
<OpenNamespaces ident="*">
<Namespace kind="public" name={name}/>
<Namespace kind="internal" name={name}/>
</OpenNamespaces>
Debug.exit("parsePackageDefinition",node)
return node
}
function parsePackageName()
{
Debug.enter("parsePackageName")
var name = ""
if( lookahead(leftbrace_token) )
{
}
else
{
name += scan.tokenText(match(identifier_token))
while( lookahead(dot_token) )
{
match(dot_token)
name += "."
name += scan.tokenText(match(identifier_token))
}
scan.addPackageName(name)
}
Debug.exit("parsePackageName",name)
return name
}
/*
Attributes
Attribute
Attribute [no line break] Attributes
Attribute
SimpleTypeIdentifier
ReservedNamespace
dynamic
final
native
override
prototype
static
[ AssignmentExpressionallowIn ]
*/
function parseAttributes(first)
{
Debug.enter("parseAttributes",first)
while( !lookaheadSemicolon(full_mode) &&
( lookahead(public_token) ||
lookahead(private_token) ||
lookahead(internal_token) ||
lookahead(intrinsic_token) ||
lookahead(protected_token) ||
lookahead(dynamic_token) ||
lookahead(final_token) ||
lookahead(native_token) ||
lookahead(override_token) ||
lookahead(prototype_token) ||
lookahead(static_token) ||
lookahead(leftbracket_token) ||
lookahead(packageidentifier_token) ||
lookahead(identifier_token) ) )
{
first += parseAttribute()
}
var node = <Attributes>{first}</Attributes>
// todo: check for duplicates
Debug.exit("parseAttributes",node)
return node
}
function parseAttribute()
{
Debug.enter("parseAttribute")
var found = lookahead(public_token) ? match(public_token) :
lookahead(private_token) ? match(private_token) :
lookahead(internal_token) ? match(internal_token) :
lookahead(intrinsic_token) ? match(intrinsic_token) :
lookahead(protected_token) ? match(protected_token) :
lookahead(dynamic_token) ? match(dynamic_token) :
lookahead(final_token) ? match(final_token) :
lookahead(native_token) ? match(native_token) :
lookahead(override_token) ? match(override_token) :
lookahead(prototype_token) ? match(prototype_token) :
lookahead(static_token) ? match(static_token) : empty_token
if( found != empty_token )
{
if( lookahead(doublecolon_token) ) // todo: look for other tokens that indicate an expression
{
throw "attribute names cannot start a labeled or expression statement"
}
var slot_context = slot_context_stack[slot_context_stack.length-1]
switch(found)
{
case internal_token:
if( slot_context == "function" )
{
throw "'internal' shall not be used in local definitions"
}
var node = <Namespace kind="internal" name={current_package}/>
break
case intrinsic_token:
throw "'intrinsic' shall only be used by implementations"
var node = <Namespace kind={scan.tokenText(found)}/>
break
case private_token:
if( slot_context != "class" )
{
throw "'private' must only be used on class variable and method definitions"
}
var node = <Namespace kind="private" name={current_class}/>
break
case protected_token:
if( slot_context != "class" )
{
throw "'protected' must only be used on class variable and method definitions"
}
var node = <Namespace kind="protected" name={current_class}/>
break
case public_token:
if( slot_context == "function" )
{
throw "'public' shall not be used in local definitions"
}
if( inClassBody() )
{
var public_namespace_name = ""
}
else
{
var public_namespace_name = current_package
}
var node = <Namespace kind="public" name={public_namespace_name}/>
break
case dynamic_token:
var node = <Dynamic/>
break
case final_token:
var node = <Final/>
break
case native_token:
var node = <Native/>
break
case override_token:
var node = <Override/>
break
case prototype_token:
var node = <Prototype/>
break
case static_token:
var node = <Static/>
break
default:
throw "invalid attribute kind"
}
}
else
if( lookahead(leftbracket_token) )
{
var node = parseArrayLiteral() // not quite right but close enough for now
}
else
{
var node = parseSimpleTypeIdentifier()
}
Debug.exit("parseAttribute",node.toXMLString())
return node
}
/*
Directivew
EmptyStatement
Statementw
AnnotatableDirectivew
Attributes [no line break] AnnotatableDirectivew
IncludeDirective Semicolonw
AnnotatableDirectivew
VariableDefinitionallowIn Semicolonw
FunctionDefinition
ClassDefinition
InterfaceDefinition
NamespaceDefinition Semicolonw
TypeDefinition Semicolonw
*/
public function parseDirective(attr,mode,prologue)
{
Debug.enter("parseDirective",mode)
if( lookahead(semicolon_token) )
{
match(semicolon_token)
node = <></>
}
else
if( lookahead(include_token) )
{
// var node = parseIncludeDirective()
}
else
if( lookahead(public_token) ||
lookahead(private_token) ||
lookahead(internal_token) ||
lookahead(intrinsic_token) ||
lookahead(protected_token) ||
lookahead(dynamic_token) ||
lookahead(final_token) ||
lookahead(native_token) ||
lookahead(override_token) ||
lookahead(prototype_token) ||
lookahead(static_token) ||
lookahead(leftbracket_token) ||
attr != null )
{
if( attr != null )
{
var first = attr // passed in from parseDirectives
}
else
{
var first = parseAttribute()
}
if( !lookaheadSemicolon(abbrev_mode) )
{
var first = parseAttributes(<>{first}</>)
}
else
{
throw "attributes cannot be used at expression statements"
}
if( lookahead(var_token) ||
lookahead(const_token) ||
lookahead(let_token) ||
lookahead(function_token) ||
lookahead(class_token) ||
lookahead(interface_token) ||
lookahead(namespace_token) ||
lookahead(type_token) )
{
var node = parseAnnotatableDirective(first,mode,prologue)
}
else
{
var node = first
}
}
else
if( lookahead(var_token) ||
lookahead(const_token) ||
lookahead(function_token) ||
lookahead(class_token) ||
lookahead(interface_token) ||
lookahead(namespace_token) ||
lookahead(type_token) )
{
var first = <Attributes/>
var node = parseAnnotatableDirective(first,mode,prologue)
}
else
if( lookahead(let_token) )
{
var first = <Attributes/>
var node = parseAnnotatableDirectiveOrLetStatement(first,mode,prologue)
}
else
if( lookahead(identifier_token) ) // labeled, attribute or expression
{
var first = parseAssignmentExpression(mode)
if( lookaheadSemicolon(abbrev_mode) )
{
matchSemicolon(abbrev_mode)
var node = <ExpressionStatement>{first}</ExpressionStatement>
}
else
if( lookahead(colon_token) ) // labeled statement
{
match(colon_token)
if( first.name() != "Get" ||
first.Get.Identifier == undefined ) // don't allow qualified identifiers
{
throw "invalid label identifier"
}
else
{
first = first.Get.Identifier.@name
}
var second = parseSubstatement(mode)
var node = <Label label={first}>{second}</Label>
}
else
if( first.name() == "Get" &&
( lookahead(public_token) ||
lookahead(private_token) ||
lookahead(internal_token) ||
lookahead(intrinsic_token) ||
lookahead(protected_token) ||
lookahead(dynamic_token) ||
lookahead(final_token) ||
lookahead(native_token) ||
lookahead(override_token) ||
lookahead(prototype_token) ||
lookahead(static_token) ||
lookahead(leftbracket_token) ||
lookahead(identifier_token) ) ) // attribute list
{
var first = parseAttributes(first)
if( lookahead(var_token) ||
lookahead(const_token) ||
lookahead(let_token) ||
lookahead(function_token) ||
lookahead(class_token) ||
lookahead(interface_token) ||
lookahead(namespace_token) ||
lookahead(type_token) )
{
var node = parseAnnotatableDirective(first,mode,prologue)
}
else
{
throw "looks like an attribute list but there's no definition to go with it"
}
}
else
if( lookahead(var_token) ||
lookahead(const_token) ||
lookahead(let_token) ||
lookahead(function_token) ||
lookahead(class_token) ||
lookahead(interface_token) ||
lookahead(namespace_token) ||
lookahead(type_token) )
{
var first = <Attributes>{first}</Attributes>
var node = parseAnnotatableDirective(first,mode,prologue)
}
else // must be a list expression resume parsing as such
{
var node = <ExpressionStatement>{parseListExpressionPrime(first,mode)}</ExpressionStatement>
}
}
else
{
var node = parseStatement(mode)
}
Debug.exit("parseDirective",node)
return node
}
/*
Directives
<20>empty<74>
DirectivesPrefix Directiveabbrev
DirectivesPrefix
<20>empty<74>
Pragmas
DirectivesPrefix Directivefull
*/
public function parseDirectives(attr,prologue)
{
Debug.enter("parseDirectives")
// look for pragmas
var node = <Block/>
if( !lookahead(eos_token) &&
(lookahead(use_token) || lookahead(import_token)) )
{
prologue.* += parsePragmas()
}
// look for statements and definitions
while( !lookahead(eos_token) && !lookahead(rightbrace_token) )
{
node.* += parseDirective(attr,full_mode,prologue)
}
Debug.exit("parseDirectives",node)
return node
}
public function parsePragmas()
{
Debug.enter("parsePragmas")
var node = <></>
while( !lookahead(eos_token) &&
(lookahead(use_token) || lookahead(import_token)) )
{
node += parsePragma()
}
Debug.exit("parsePragmas",node)
return node
}
public function parsePragma()
{
Debug.enter("parsePragma")
var node = <></>
if( lookahead(use_token) )
{
node += parseUsePragma()
matchSemicolon(full_mode)
}
else
if( lookahead(import_token) )
{
node += parseImportPragma()
matchSemicolon(full_mode)
}
Debug.exit("parsePragma",node)
return node
}
public function parseImportPragma()
{
Debug.enter("parseImportPragma")
match(import_token)
if( lookahead(identifier_token) )
{
var first = parseIdentifier()
if( lookahead(assign_token) )
{
match(assign_token)
}
else
{
throw "import name '"+first.@name+"' is not a known package identifier"
}
var second = parseImportName()
if( second.@def == "*" )
{
throw "wildcard not allowed in aliasing import pragmas"
}
second.@alias=first.@name
var node = second
}
else
if( lookahead(packageidentifier_token) )
{
var second = parseImportName()
var node = second
}
else
{
throw "invalid import name"
}
var pkg_name = node.@pkg
var def_name = node.@def
if( def_name == "*" )
{
scopes[scopes.length-1].Imports.*+=node
}
else
{
scopes[scopes.length-1].Imports[def_name].*+=node
}
Debug.exit("parseImportPragma",node.toXMLString())
return node
}
var scopes = [<Scope/>]
function isImported(pkg_name,def_name)
{
var scope = scopes[scopes.length-1]
for each( var def in scope.Imports[def_name] )
{
if( def.Import.@pkg == pkg_name )
{
return true
}
}
for each( var def in scope.Imports.* )
{
if( def.@pkg == pkg_name )
{
return true
}
}
return false
}
function parseImportName()
{
Debug.enter("parseImportName")
var pkg_part = scan.tokenText(match(packageidentifier_token))
match(dot_token)
if( lookahead(mult_token) )
{
match(mult_token)
var def_part = "*"
}
else
if( lookaheadReservedWord() )
{
var def_part = scan.tokenText(matchReservedWord())
}
else
{
var def_part = scan.tokenText(match(identifier_token))
}
var node = <Import pkg={pkg_part} def={def_part}/>
Debug.exit("parseImportName",node.toXMLString())
return node
}
public function parseUsePragma()
{
Debug.enter("parseUsePragma")
match(use_token)
var node = <></>
node += parsePragmaItem()
while( lookahead(comma_token) )
{
match(comma_token)
node += parsePragmaItem()
}
Debug.exit("parseUsePragma",node)
return node
}
function parsePragmaItem()
{
Debug.enter("parsePragmaItem")
if( lookaheadReservedWord() ||
lookahead(identifier_token) )
{
if( lookaheadReservedWord() )
{
var first = matchReservedWord()
}
else
{
var first = match(identifier_token)
}
var ident = scan.tokenText(first)
switch(ident)
{
case 'decimal':
case 'double':
case 'int':
case 'rounding':
case 'standard':
case 'strict':
case 'uint':
var node = <{ident}/>
break
case 'default':
match(namespace_token)
var node = <DefaultNamespace/>
node.* = <Get kind="lexical">{parseSimpleTypeIdentifier()}</Get>
break
case 'namespace':
var node = <UseNamespace/>
node.* = <Get kind="lexical">{parseSimpleTypeIdentifier()}</Get>
break
default:
throw "invalid pragma identifier:"+ident
break
}
}
Debug.exit("parsePragmaItem",node)
return node
}
var default_namespace
public function parseProgram()
{
Debug.enter("parseProgram")
var blocks = <></>
while( lookahead(internal_token) || lookahead(package_token) )
{
if( lookahead(internal_token) )
{
var attr = parseAttribute()
}
if( lookahead(package_token) )
{
blocks += parsePackageDefinition(attr)
attr = null // clear it
}
else
{
break
}
}
current_package = "global"
var prologue = <Prologue/>
default_namespace = <Namespace kind="internal" name="global"/>
var block = parseDirectives(attr,prologue)
var global = <BlockStatement kind="package" name="">{prologue}{block}</BlockStatement>
blocks += global
var node = <Program><Prologue/><Block>{blocks}</Block></Program>
node.Prologue.OpenNamespaces =
<OpenNamespaces ident="*">
<Namespace kind="public" name=""/>
<Namespace kind="internal" name="global"/>
</OpenNamespaces>
Debug.exit("parseProgram",node)
return node
}
}
function testParser()
{
var programs =
[
//primary expressions
"x",
"q::id",
"q::[expr]",
"(expr)::id",
"(expr)::[expr]",
"@a",
"@q::id",
"@q::[expr]",
"@(expr)::id",
"@(expr)::[expr]",
"@[expr]",
"/abcdefg/g",
"/abcdefg/",
"/abcdefg/i",
"/abcdefg/x",
"true",
"false",
"null",
"(a)::x",
"(function(a,b,c){})",
"{x:a,y:b,z:c}",
"[a,b,c]",
"{(x):y}",
"(function(){})",
"(function f(a:A,b:B){})",
"(function f.<T,U,V>(a:T,b:U,c:V){})",
// type expressions
"T",
"?T",
"T!",
"T~",
"T.<U>",
"T.<U.<V>>",
"T.<{a:A,t:{i:I,s:S}}>",
"T.<{x:[A,B,C]}>",
"T.<{x:(A,B,C)}>",
"T.<U.<V.<W.<[,,,]>>>>",
"T.<U>!",
"?T.<U>",
// Postfix expressions
"x.y",
"new x",
"new x()",
"x()",
"x.y()",
"x++",
"x--",
"x.y++",
"x.y()++",
"new x.y++",
]
var n = 0
for each ( var p in programs )
{
n++
try {
var parser = new Parser(p)
var node = parser.parseProgram()
print("> "+p)
print(node.toXMLString())
//print("---")
}
catch(x)
{
print(x)
}
}
}
// testParser()
}