зеркало из https://github.com/mozilla/gecko-dev.git
6128 строки
189 KiB
ActionScript
6128 строки
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
|
||
* the Initial Developer. 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 the 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()
|
||
}
|
||
|