瀏覽代碼

* Initial check-in

git-svn-id: trunk@14859 -
michael 15 年之前
父節點
當前提交
59bd32b7ea

+ 15 - 0
.gitattributes

@@ -1980,6 +1980,21 @@ packages/fcl-image/src/pngcomn.pp svneol=native#text/plain
 packages/fcl-image/src/pscanvas.pp svneol=native#text/plain
 packages/fcl-image/src/targacmn.pp svneol=native#text/plain
 packages/fcl-image/src/xwdfile.pp svneol=native#text/plain
+packages/fcl-js/Makefile svneol=native#text/plain
+packages/fcl-js/Makefile.fpc svneol=native#text/plain
+packages/fcl-js/README.TXT svneol=native#text/plain
+packages/fcl-js/fpmake.pp svneol=native#text/plain
+packages/fcl-js/src/jsbase.pp svneol=native#text/plain
+packages/fcl-js/src/jsparser.pp svneol=native#text/plain
+packages/fcl-js/src/jsscanner.pp svneol=native#text/plain
+packages/fcl-js/src/jstree.pp svneol=native#text/plain
+packages/fcl-js/tests/tcparser.pp svneol=native#text/plain
+packages/fcl-js/tests/tcscanner.pp svneol=native#text/plain
+packages/fcl-js/tests/testjs.ico -text
+packages/fcl-js/tests/testjs.lpi svneol=native#text/plain
+packages/fcl-js/tests/testjs.lpr svneol=native#text/plain
+packages/fcl-js/tests/testjs.manifest svneol=native#text/plain
+packages/fcl-js/tests/testjs.rc svneol=native#text/plain
 packages/fcl-json/Makefile svneol=native#text/plain
 packages/fcl-json/Makefile.fpc svneol=native#text/plain
 packages/fcl-json/examples/confdemo.lpi svneol=native#text/plain

+ 2354 - 0
packages/fcl-js/Makefile

@@ -0,0 +1,2354 @@
+#
+# Don't edit, this file is generated by FPCMake Version 2.0.0 [2009/11/06]
+#
+default: all
+MAKEFILETARGETS=i386-linux i386-go32v2 i386-win32 i386-os2 i386-freebsd i386-beos i386-haiku i386-netbsd i386-solaris i386-qnx i386-netware i386-openbsd i386-wdosx i386-darwin i386-emx i386-watcom i386-netwlibc i386-wince i386-embedded i386-symbian m68k-linux m68k-freebsd m68k-netbsd m68k-amiga m68k-atari m68k-openbsd m68k-palmos m68k-embedded powerpc-linux powerpc-netbsd powerpc-amiga powerpc-macos powerpc-darwin powerpc-morphos powerpc-embedded sparc-linux sparc-netbsd sparc-solaris sparc-embedded x86_64-linux x86_64-freebsd x86_64-darwin x86_64-win64 x86_64-embedded arm-linux arm-palmos arm-darwin arm-wince arm-gba arm-nds arm-embedded arm-symbian powerpc64-linux powerpc64-darwin powerpc64-embedded avr-embedded armeb-linux armeb-embedded
+BSDs = freebsd netbsd openbsd darwin
+UNIXs = linux $(BSDs) solaris qnx
+LIMIT83fs = go32v2 os2 emx watcom
+OSNeedsComspecToRunBatch = go32v2 watcom
+FORCE:
+.PHONY: FORCE
+override PATH:=$(patsubst %/,%,$(subst \,/,$(PATH)))
+ifneq ($(findstring darwin,$(OSTYPE)),)
+inUnix=1 #darwin
+SEARCHPATH:=$(filter-out .,$(subst :, ,$(PATH)))
+else
+ifeq ($(findstring ;,$(PATH)),)
+inUnix=1
+SEARCHPATH:=$(filter-out .,$(subst :, ,$(PATH)))
+else
+SEARCHPATH:=$(subst ;, ,$(PATH))
+endif
+endif
+SEARCHPATH+=$(patsubst %/,%,$(subst \,/,$(dir $(MAKE))))
+PWD:=$(strip $(wildcard $(addsuffix /pwd.exe,$(SEARCHPATH))))
+ifeq ($(PWD),)
+PWD:=$(strip $(wildcard $(addsuffix /pwd,$(SEARCHPATH))))
+ifeq ($(PWD),)
+$(error You need the GNU utils package to use this Makefile)
+else
+PWD:=$(firstword $(PWD))
+SRCEXEEXT=
+endif
+else
+PWD:=$(firstword $(PWD))
+SRCEXEEXT=.exe
+endif
+ifndef inUnix
+ifeq ($(OS),Windows_NT)
+inWinNT=1
+else
+ifdef OS2_SHELL
+inOS2=1
+endif
+endif
+else
+ifneq ($(findstring cygdrive,$(PATH)),)
+inCygWin=1
+endif
+endif
+ifdef inUnix
+SRCBATCHEXT=.sh
+else
+ifdef inOS2
+SRCBATCHEXT=.cmd
+else
+SRCBATCHEXT=.bat
+endif
+endif
+ifdef COMSPEC
+ifneq ($(findstring $(OS_SOURCE),$(OSNeedsComspecToRunBatch)),)
+ifndef RUNBATCH
+RUNBATCH=$(COMSPEC) /C
+endif
+endif
+endif
+ifdef inUnix
+PATHSEP=/
+else
+PATHSEP:=$(subst /,\,/)
+ifdef inCygWin
+PATHSEP=/
+endif
+endif
+ifdef PWD
+BASEDIR:=$(subst \,/,$(shell $(PWD)))
+ifdef inCygWin
+ifneq ($(findstring /cygdrive/,$(BASEDIR)),)
+BASENODIR:=$(patsubst /cygdrive%,%,$(BASEDIR))
+BASEDRIVE:=$(firstword $(subst /, ,$(BASENODIR)))
+BASEDIR:=$(subst /cygdrive/$(BASEDRIVE)/,$(BASEDRIVE):/,$(BASEDIR))
+endif
+endif
+else
+BASEDIR=.
+endif
+ifdef inOS2
+ifndef ECHO
+ECHO:=$(strip $(wildcard $(addsuffix /gecho$(SRCEXEEXT),$(SEARCHPATH))))
+ifeq ($(ECHO),)
+ECHO:=$(strip $(wildcard $(addsuffix /echo$(SRCEXEEXT),$(SEARCHPATH))))
+ifeq ($(ECHO),)
+ECHO=echo
+else
+ECHO:=$(firstword $(ECHO))
+endif
+else
+ECHO:=$(firstword $(ECHO))
+endif
+endif
+export ECHO
+endif
+override DEFAULT_FPCDIR=../..
+ifndef FPC
+ifdef PP
+FPC=$(PP)
+endif
+endif
+ifndef FPC
+FPCPROG:=$(strip $(wildcard $(addsuffix /fpc$(SRCEXEEXT),$(SEARCHPATH))))
+ifneq ($(FPCPROG),)
+FPCPROG:=$(firstword $(FPCPROG))
+ifneq ($(CPU_TARGET),)
+FPC:=$(shell $(FPCPROG) -P$(CPU_TARGET) -PB)
+else
+FPC:=$(shell $(FPCPROG) -PB)
+endif
+ifneq ($(findstring Error,$(FPC)),)
+override FPC=$(firstword $(strip $(wildcard $(addsuffix /ppc386$(SRCEXEEXT),$(SEARCHPATH)))))
+else
+ifeq ($(strip $(wildcard $(FPC))),)
+FPC:=$(firstword $(FPCPROG))
+endif
+endif
+else
+override FPC=$(firstword $(strip $(wildcard $(addsuffix /ppc386$(SRCEXEEXT),$(SEARCHPATH)))))
+endif
+endif
+override FPC:=$(subst $(SRCEXEEXT),,$(FPC))
+override FPC:=$(subst \,/,$(FPC))$(SRCEXEEXT)
+FOUNDFPC:=$(strip $(wildcard $(FPC)))
+ifeq ($(FOUNDFPC),)
+FOUNDFPC=$(strip $(wildcard $(addsuffix /$(FPC),$(SEARCHPATH))))
+ifeq ($(FOUNDFPC),)
+$(error Compiler $(FPC) not found)
+endif
+endif
+ifndef FPC_COMPILERINFO
+FPC_COMPILERINFO:=$(shell $(FPC) -iVSPTPSOTO)
+endif
+ifndef FPC_VERSION
+FPC_VERSION:=$(word 1,$(FPC_COMPILERINFO))
+endif
+export FPC FPC_VERSION FPC_COMPILERINFO
+unexport CHECKDEPEND ALLDEPENDENCIES
+ifndef CPU_TARGET
+ifdef CPU_TARGET_DEFAULT
+CPU_TARGET=$(CPU_TARGET_DEFAULT)
+endif
+endif
+ifndef OS_TARGET
+ifdef OS_TARGET_DEFAULT
+OS_TARGET=$(OS_TARGET_DEFAULT)
+endif
+endif
+ifneq ($(words $(FPC_COMPILERINFO)),5)
+FPC_COMPILERINFO+=$(shell $(FPC) -iSP)
+FPC_COMPILERINFO+=$(shell $(FPC) -iTP)
+FPC_COMPILERINFO+=$(shell $(FPC) -iSO)
+FPC_COMPILERINFO+=$(shell $(FPC) -iTO)
+endif
+ifndef CPU_SOURCE
+CPU_SOURCE:=$(word 2,$(FPC_COMPILERINFO))
+endif
+ifndef CPU_TARGET
+CPU_TARGET:=$(word 3,$(FPC_COMPILERINFO))
+endif
+ifndef OS_SOURCE
+OS_SOURCE:=$(word 4,$(FPC_COMPILERINFO))
+endif
+ifndef OS_TARGET
+OS_TARGET:=$(word 5,$(FPC_COMPILERINFO))
+endif
+FULL_TARGET=$(CPU_TARGET)-$(OS_TARGET)
+FULL_SOURCE=$(CPU_SOURCE)-$(OS_SOURCE)
+ifeq ($(CPU_TARGET),armeb)
+ARCH=arm
+override FPCOPT+=-Cb
+else
+ifeq ($(CPU_TARGET),armel)
+ARCH=arm
+override FPCOPT+=-CaEABI
+else
+ARCH=$(CPU_TARGET)
+endif
+endif
+ifneq ($(findstring $(OS_SOURCE),$(LIMIT83fs)),)
+TARGETSUFFIX=$(OS_TARGET)
+SOURCESUFFIX=$(OS_SOURCE)
+else
+TARGETSUFFIX=$(FULL_TARGET)
+SOURCESUFFIX=$(FULL_SOURCE)
+endif
+ifneq ($(FULL_TARGET),$(FULL_SOURCE))
+CROSSCOMPILE=1
+endif
+ifeq ($(findstring makefile,$(MAKECMDGOALS)),)
+ifeq ($(findstring $(FULL_TARGET),$(MAKEFILETARGETS)),)
+$(error The Makefile doesn't support target $(FULL_TARGET), please run fpcmake first)
+endif
+endif
+ifneq ($(findstring $(OS_TARGET),$(BSDs)),)
+BSDhier=1
+endif
+ifeq ($(OS_TARGET),linux)
+linuxHier=1
+endif
+export OS_TARGET OS_SOURCE ARCH CPU_TARGET CPU_SOURCE FULL_TARGET FULL_SOURCE TARGETSUFFIX SOURCESUFFIX CROSSCOMPILE
+ifdef FPCDIR
+override FPCDIR:=$(subst \,/,$(FPCDIR))
+ifeq ($(wildcard $(addprefix $(FPCDIR)/,rtl units)),)
+override FPCDIR=wrong
+endif
+else
+override FPCDIR=wrong
+endif
+ifdef DEFAULT_FPCDIR
+ifeq ($(FPCDIR),wrong)
+override FPCDIR:=$(subst \,/,$(DEFAULT_FPCDIR))
+ifeq ($(wildcard $(addprefix $(FPCDIR)/,rtl units)),)
+override FPCDIR=wrong
+endif
+endif
+endif
+ifeq ($(FPCDIR),wrong)
+ifdef inUnix
+override FPCDIR=/usr/local/lib/fpc/$(FPC_VERSION)
+ifeq ($(wildcard $(FPCDIR)/units),)
+override FPCDIR=/usr/lib/fpc/$(FPC_VERSION)
+endif
+else
+override FPCDIR:=$(subst /$(FPC),,$(firstword $(strip $(wildcard $(addsuffix /$(FPC),$(SEARCHPATH))))))
+override FPCDIR:=$(FPCDIR)/..
+ifeq ($(wildcard $(addprefix $(FPCDIR)/,rtl units)),)
+override FPCDIR:=$(FPCDIR)/..
+ifeq ($(wildcard $(addprefix $(FPCDIR)/,rtl units)),)
+override FPCDIR:=$(BASEDIR)
+ifeq ($(wildcard $(addprefix $(FPCDIR)/,rtl units)),)
+override FPCDIR=c:/pp
+endif
+endif
+endif
+endif
+endif
+ifndef CROSSBINDIR
+CROSSBINDIR:=$(wildcard $(FPCDIR)/bin/$(TARGETSUFFIX))
+endif
+ifeq ($(OS_TARGET),darwin)
+ifeq ($(OS_SOURCE),darwin)
+DARWIN2DARWIN=1
+endif
+endif
+ifndef BINUTILSPREFIX
+ifndef CROSSBINDIR
+ifdef CROSSCOMPILE
+ifndef DARWIN2DARWIN
+BINUTILSPREFIX=$(CPU_TARGET)-$(OS_TARGET)-
+endif
+endif
+endif
+endif
+UNITSDIR:=$(wildcard $(FPCDIR)/units/$(TARGETSUFFIX))
+ifeq ($(UNITSDIR),)
+UNITSDIR:=$(wildcard $(FPCDIR)/units/$(OS_TARGET))
+endif
+PACKAGESDIR:=$(wildcard $(FPCDIR) $(FPCDIR)/packages $(FPCDIR)/packages/base $(FPCDIR)/packages/extra)
+override PACKAGE_NAME=fcl-js
+override PACKAGE_VERSION=2.5.1
+ifeq ($(FULL_TARGET),i386-linux)
+override TARGET_UNITS+=jsbase jstree jsscanner jsparser
+endif
+ifeq ($(FULL_TARGET),i386-go32v2)
+override TARGET_UNITS+=jsbase jstree jsscanner jsparser
+endif
+ifeq ($(FULL_TARGET),i386-win32)
+override TARGET_UNITS+=jsbase jstree jsscanner jsparser
+endif
+ifeq ($(FULL_TARGET),i386-os2)
+override TARGET_UNITS+=jsbase jstree jsscanner jsparser
+endif
+ifeq ($(FULL_TARGET),i386-freebsd)
+override TARGET_UNITS+=jsbase jstree jsscanner jsparser
+endif
+ifeq ($(FULL_TARGET),i386-beos)
+override TARGET_UNITS+=jsbase jstree jsscanner jsparser
+endif
+ifeq ($(FULL_TARGET),i386-haiku)
+override TARGET_UNITS+=jsbase jstree jsscanner jsparser
+endif
+ifeq ($(FULL_TARGET),i386-netbsd)
+override TARGET_UNITS+=jsbase jstree jsscanner jsparser
+endif
+ifeq ($(FULL_TARGET),i386-solaris)
+override TARGET_UNITS+=jsbase jstree jsscanner jsparser
+endif
+ifeq ($(FULL_TARGET),i386-qnx)
+override TARGET_UNITS+=jsbase jstree jsscanner jsparser
+endif
+ifeq ($(FULL_TARGET),i386-netware)
+override TARGET_UNITS+=jsbase jstree jsscanner jsparser
+endif
+ifeq ($(FULL_TARGET),i386-openbsd)
+override TARGET_UNITS+=jsbase jstree jsscanner jsparser
+endif
+ifeq ($(FULL_TARGET),i386-wdosx)
+override TARGET_UNITS+=jsbase jstree jsscanner jsparser
+endif
+ifeq ($(FULL_TARGET),i386-darwin)
+override TARGET_UNITS+=jsbase jstree jsscanner jsparser
+endif
+ifeq ($(FULL_TARGET),i386-emx)
+override TARGET_UNITS+=jsbase jstree jsscanner jsparser
+endif
+ifeq ($(FULL_TARGET),i386-watcom)
+override TARGET_UNITS+=jsbase jstree jsscanner jsparser
+endif
+ifeq ($(FULL_TARGET),i386-netwlibc)
+override TARGET_UNITS+=jsbase jstree jsscanner jsparser
+endif
+ifeq ($(FULL_TARGET),i386-wince)
+override TARGET_UNITS+=jsbase jstree jsscanner jsparser
+endif
+ifeq ($(FULL_TARGET),i386-embedded)
+override TARGET_UNITS+=jsbase jstree jsscanner jsparser
+endif
+ifeq ($(FULL_TARGET),i386-symbian)
+override TARGET_UNITS+=jsbase jstree jsscanner jsparser
+endif
+ifeq ($(FULL_TARGET),m68k-linux)
+override TARGET_UNITS+=jsbase jstree jsscanner jsparser
+endif
+ifeq ($(FULL_TARGET),m68k-freebsd)
+override TARGET_UNITS+=jsbase jstree jsscanner jsparser
+endif
+ifeq ($(FULL_TARGET),m68k-netbsd)
+override TARGET_UNITS+=jsbase jstree jsscanner jsparser
+endif
+ifeq ($(FULL_TARGET),m68k-amiga)
+override TARGET_UNITS+=jsbase jstree jsscanner jsparser
+endif
+ifeq ($(FULL_TARGET),m68k-atari)
+override TARGET_UNITS+=jsbase jstree jsscanner jsparser
+endif
+ifeq ($(FULL_TARGET),m68k-openbsd)
+override TARGET_UNITS+=jsbase jstree jsscanner jsparser
+endif
+ifeq ($(FULL_TARGET),m68k-palmos)
+override TARGET_UNITS+=jsbase jstree jsscanner jsparser
+endif
+ifeq ($(FULL_TARGET),m68k-embedded)
+override TARGET_UNITS+=jsbase jstree jsscanner jsparser
+endif
+ifeq ($(FULL_TARGET),powerpc-linux)
+override TARGET_UNITS+=jsbase jstree jsscanner jsparser
+endif
+ifeq ($(FULL_TARGET),powerpc-netbsd)
+override TARGET_UNITS+=jsbase jstree jsscanner jsparser
+endif
+ifeq ($(FULL_TARGET),powerpc-amiga)
+override TARGET_UNITS+=jsbase jstree jsscanner jsparser
+endif
+ifeq ($(FULL_TARGET),powerpc-macos)
+override TARGET_UNITS+=jsbase jstree jsscanner jsparser
+endif
+ifeq ($(FULL_TARGET),powerpc-darwin)
+override TARGET_UNITS+=jsbase jstree jsscanner jsparser
+endif
+ifeq ($(FULL_TARGET),powerpc-morphos)
+override TARGET_UNITS+=jsbase jstree jsscanner jsparser
+endif
+ifeq ($(FULL_TARGET),powerpc-embedded)
+override TARGET_UNITS+=jsbase jstree jsscanner jsparser
+endif
+ifeq ($(FULL_TARGET),sparc-linux)
+override TARGET_UNITS+=jsbase jstree jsscanner jsparser
+endif
+ifeq ($(FULL_TARGET),sparc-netbsd)
+override TARGET_UNITS+=jsbase jstree jsscanner jsparser
+endif
+ifeq ($(FULL_TARGET),sparc-solaris)
+override TARGET_UNITS+=jsbase jstree jsscanner jsparser
+endif
+ifeq ($(FULL_TARGET),sparc-embedded)
+override TARGET_UNITS+=jsbase jstree jsscanner jsparser
+endif
+ifeq ($(FULL_TARGET),x86_64-linux)
+override TARGET_UNITS+=jsbase jstree jsscanner jsparser
+endif
+ifeq ($(FULL_TARGET),x86_64-freebsd)
+override TARGET_UNITS+=jsbase jstree jsscanner jsparser
+endif
+ifeq ($(FULL_TARGET),x86_64-darwin)
+override TARGET_UNITS+=jsbase jstree jsscanner jsparser
+endif
+ifeq ($(FULL_TARGET),x86_64-win64)
+override TARGET_UNITS+=jsbase jstree jsscanner jsparser
+endif
+ifeq ($(FULL_TARGET),x86_64-embedded)
+override TARGET_UNITS+=jsbase jstree jsscanner jsparser
+endif
+ifeq ($(FULL_TARGET),arm-linux)
+override TARGET_UNITS+=jsbase jstree jsscanner jsparser
+endif
+ifeq ($(FULL_TARGET),arm-palmos)
+override TARGET_UNITS+=jsbase jstree jsscanner jsparser
+endif
+ifeq ($(FULL_TARGET),arm-darwin)
+override TARGET_UNITS+=jsbase jstree jsscanner jsparser
+endif
+ifeq ($(FULL_TARGET),arm-wince)
+override TARGET_UNITS+=jsbase jstree jsscanner jsparser
+endif
+ifeq ($(FULL_TARGET),arm-gba)
+override TARGET_UNITS+=jsbase jstree jsscanner jsparser
+endif
+ifeq ($(FULL_TARGET),arm-nds)
+override TARGET_UNITS+=jsbase jstree jsscanner jsparser
+endif
+ifeq ($(FULL_TARGET),arm-embedded)
+override TARGET_UNITS+=jsbase jstree jsscanner jsparser
+endif
+ifeq ($(FULL_TARGET),arm-symbian)
+override TARGET_UNITS+=jsbase jstree jsscanner jsparser
+endif
+ifeq ($(FULL_TARGET),powerpc64-linux)
+override TARGET_UNITS+=jsbase jstree jsscanner jsparser
+endif
+ifeq ($(FULL_TARGET),powerpc64-darwin)
+override TARGET_UNITS+=jsbase jstree jsscanner jsparser
+endif
+ifeq ($(FULL_TARGET),powerpc64-embedded)
+override TARGET_UNITS+=jsbase jstree jsscanner jsparser
+endif
+ifeq ($(FULL_TARGET),avr-embedded)
+override TARGET_UNITS+=jsbase jstree jsscanner jsparser
+endif
+ifeq ($(FULL_TARGET),armeb-linux)
+override TARGET_UNITS+=jsbase jstree jsscanner jsparser
+endif
+ifeq ($(FULL_TARGET),armeb-embedded)
+override TARGET_UNITS+=jsbase jstree jsscanner jsparser
+endif
+override INSTALL_FPCPACKAGE=y
+ifeq ($(FULL_TARGET),i386-linux)
+override COMPILER_INCLUDEDIR+=src
+endif
+ifeq ($(FULL_TARGET),i386-go32v2)
+override COMPILER_INCLUDEDIR+=src
+endif
+ifeq ($(FULL_TARGET),i386-win32)
+override COMPILER_INCLUDEDIR+=src
+endif
+ifeq ($(FULL_TARGET),i386-os2)
+override COMPILER_INCLUDEDIR+=src
+endif
+ifeq ($(FULL_TARGET),i386-freebsd)
+override COMPILER_INCLUDEDIR+=src
+endif
+ifeq ($(FULL_TARGET),i386-beos)
+override COMPILER_INCLUDEDIR+=src
+endif
+ifeq ($(FULL_TARGET),i386-haiku)
+override COMPILER_INCLUDEDIR+=src
+endif
+ifeq ($(FULL_TARGET),i386-netbsd)
+override COMPILER_INCLUDEDIR+=src
+endif
+ifeq ($(FULL_TARGET),i386-solaris)
+override COMPILER_INCLUDEDIR+=src
+endif
+ifeq ($(FULL_TARGET),i386-qnx)
+override COMPILER_INCLUDEDIR+=src
+endif
+ifeq ($(FULL_TARGET),i386-netware)
+override COMPILER_INCLUDEDIR+=src
+endif
+ifeq ($(FULL_TARGET),i386-openbsd)
+override COMPILER_INCLUDEDIR+=src
+endif
+ifeq ($(FULL_TARGET),i386-wdosx)
+override COMPILER_INCLUDEDIR+=src
+endif
+ifeq ($(FULL_TARGET),i386-darwin)
+override COMPILER_INCLUDEDIR+=src
+endif
+ifeq ($(FULL_TARGET),i386-emx)
+override COMPILER_INCLUDEDIR+=src
+endif
+ifeq ($(FULL_TARGET),i386-watcom)
+override COMPILER_INCLUDEDIR+=src
+endif
+ifeq ($(FULL_TARGET),i386-netwlibc)
+override COMPILER_INCLUDEDIR+=src
+endif
+ifeq ($(FULL_TARGET),i386-wince)
+override COMPILER_INCLUDEDIR+=src
+endif
+ifeq ($(FULL_TARGET),i386-embedded)
+override COMPILER_INCLUDEDIR+=src
+endif
+ifeq ($(FULL_TARGET),i386-symbian)
+override COMPILER_INCLUDEDIR+=src
+endif
+ifeq ($(FULL_TARGET),m68k-linux)
+override COMPILER_INCLUDEDIR+=src
+endif
+ifeq ($(FULL_TARGET),m68k-freebsd)
+override COMPILER_INCLUDEDIR+=src
+endif
+ifeq ($(FULL_TARGET),m68k-netbsd)
+override COMPILER_INCLUDEDIR+=src
+endif
+ifeq ($(FULL_TARGET),m68k-amiga)
+override COMPILER_INCLUDEDIR+=src
+endif
+ifeq ($(FULL_TARGET),m68k-atari)
+override COMPILER_INCLUDEDIR+=src
+endif
+ifeq ($(FULL_TARGET),m68k-openbsd)
+override COMPILER_INCLUDEDIR+=src
+endif
+ifeq ($(FULL_TARGET),m68k-palmos)
+override COMPILER_INCLUDEDIR+=src
+endif
+ifeq ($(FULL_TARGET),m68k-embedded)
+override COMPILER_INCLUDEDIR+=src
+endif
+ifeq ($(FULL_TARGET),powerpc-linux)
+override COMPILER_INCLUDEDIR+=src
+endif
+ifeq ($(FULL_TARGET),powerpc-netbsd)
+override COMPILER_INCLUDEDIR+=src
+endif
+ifeq ($(FULL_TARGET),powerpc-amiga)
+override COMPILER_INCLUDEDIR+=src
+endif
+ifeq ($(FULL_TARGET),powerpc-macos)
+override COMPILER_INCLUDEDIR+=src
+endif
+ifeq ($(FULL_TARGET),powerpc-darwin)
+override COMPILER_INCLUDEDIR+=src
+endif
+ifeq ($(FULL_TARGET),powerpc-morphos)
+override COMPILER_INCLUDEDIR+=src
+endif
+ifeq ($(FULL_TARGET),powerpc-embedded)
+override COMPILER_INCLUDEDIR+=src
+endif
+ifeq ($(FULL_TARGET),sparc-linux)
+override COMPILER_INCLUDEDIR+=src
+endif
+ifeq ($(FULL_TARGET),sparc-netbsd)
+override COMPILER_INCLUDEDIR+=src
+endif
+ifeq ($(FULL_TARGET),sparc-solaris)
+override COMPILER_INCLUDEDIR+=src
+endif
+ifeq ($(FULL_TARGET),sparc-embedded)
+override COMPILER_INCLUDEDIR+=src
+endif
+ifeq ($(FULL_TARGET),x86_64-linux)
+override COMPILER_INCLUDEDIR+=src
+endif
+ifeq ($(FULL_TARGET),x86_64-freebsd)
+override COMPILER_INCLUDEDIR+=src
+endif
+ifeq ($(FULL_TARGET),x86_64-darwin)
+override COMPILER_INCLUDEDIR+=src
+endif
+ifeq ($(FULL_TARGET),x86_64-win64)
+override COMPILER_INCLUDEDIR+=src
+endif
+ifeq ($(FULL_TARGET),x86_64-embedded)
+override COMPILER_INCLUDEDIR+=src
+endif
+ifeq ($(FULL_TARGET),arm-linux)
+override COMPILER_INCLUDEDIR+=src
+endif
+ifeq ($(FULL_TARGET),arm-palmos)
+override COMPILER_INCLUDEDIR+=src
+endif
+ifeq ($(FULL_TARGET),arm-darwin)
+override COMPILER_INCLUDEDIR+=src
+endif
+ifeq ($(FULL_TARGET),arm-wince)
+override COMPILER_INCLUDEDIR+=src
+endif
+ifeq ($(FULL_TARGET),arm-gba)
+override COMPILER_INCLUDEDIR+=src
+endif
+ifeq ($(FULL_TARGET),arm-nds)
+override COMPILER_INCLUDEDIR+=src
+endif
+ifeq ($(FULL_TARGET),arm-embedded)
+override COMPILER_INCLUDEDIR+=src
+endif
+ifeq ($(FULL_TARGET),arm-symbian)
+override COMPILER_INCLUDEDIR+=src
+endif
+ifeq ($(FULL_TARGET),powerpc64-linux)
+override COMPILER_INCLUDEDIR+=src
+endif
+ifeq ($(FULL_TARGET),powerpc64-darwin)
+override COMPILER_INCLUDEDIR+=src
+endif
+ifeq ($(FULL_TARGET),powerpc64-embedded)
+override COMPILER_INCLUDEDIR+=src
+endif
+ifeq ($(FULL_TARGET),avr-embedded)
+override COMPILER_INCLUDEDIR+=src
+endif
+ifeq ($(FULL_TARGET),armeb-linux)
+override COMPILER_INCLUDEDIR+=src
+endif
+ifeq ($(FULL_TARGET),armeb-embedded)
+override COMPILER_INCLUDEDIR+=src
+endif
+ifeq ($(FULL_TARGET),i386-linux)
+override COMPILER_SOURCEDIR+=src
+endif
+ifeq ($(FULL_TARGET),i386-go32v2)
+override COMPILER_SOURCEDIR+=src
+endif
+ifeq ($(FULL_TARGET),i386-win32)
+override COMPILER_SOURCEDIR+=src
+endif
+ifeq ($(FULL_TARGET),i386-os2)
+override COMPILER_SOURCEDIR+=src
+endif
+ifeq ($(FULL_TARGET),i386-freebsd)
+override COMPILER_SOURCEDIR+=src
+endif
+ifeq ($(FULL_TARGET),i386-beos)
+override COMPILER_SOURCEDIR+=src
+endif
+ifeq ($(FULL_TARGET),i386-haiku)
+override COMPILER_SOURCEDIR+=src
+endif
+ifeq ($(FULL_TARGET),i386-netbsd)
+override COMPILER_SOURCEDIR+=src
+endif
+ifeq ($(FULL_TARGET),i386-solaris)
+override COMPILER_SOURCEDIR+=src
+endif
+ifeq ($(FULL_TARGET),i386-qnx)
+override COMPILER_SOURCEDIR+=src
+endif
+ifeq ($(FULL_TARGET),i386-netware)
+override COMPILER_SOURCEDIR+=src
+endif
+ifeq ($(FULL_TARGET),i386-openbsd)
+override COMPILER_SOURCEDIR+=src
+endif
+ifeq ($(FULL_TARGET),i386-wdosx)
+override COMPILER_SOURCEDIR+=src
+endif
+ifeq ($(FULL_TARGET),i386-darwin)
+override COMPILER_SOURCEDIR+=src
+endif
+ifeq ($(FULL_TARGET),i386-emx)
+override COMPILER_SOURCEDIR+=src
+endif
+ifeq ($(FULL_TARGET),i386-watcom)
+override COMPILER_SOURCEDIR+=src
+endif
+ifeq ($(FULL_TARGET),i386-netwlibc)
+override COMPILER_SOURCEDIR+=src
+endif
+ifeq ($(FULL_TARGET),i386-wince)
+override COMPILER_SOURCEDIR+=src
+endif
+ifeq ($(FULL_TARGET),i386-embedded)
+override COMPILER_SOURCEDIR+=src
+endif
+ifeq ($(FULL_TARGET),i386-symbian)
+override COMPILER_SOURCEDIR+=src
+endif
+ifeq ($(FULL_TARGET),m68k-linux)
+override COMPILER_SOURCEDIR+=src
+endif
+ifeq ($(FULL_TARGET),m68k-freebsd)
+override COMPILER_SOURCEDIR+=src
+endif
+ifeq ($(FULL_TARGET),m68k-netbsd)
+override COMPILER_SOURCEDIR+=src
+endif
+ifeq ($(FULL_TARGET),m68k-amiga)
+override COMPILER_SOURCEDIR+=src
+endif
+ifeq ($(FULL_TARGET),m68k-atari)
+override COMPILER_SOURCEDIR+=src
+endif
+ifeq ($(FULL_TARGET),m68k-openbsd)
+override COMPILER_SOURCEDIR+=src
+endif
+ifeq ($(FULL_TARGET),m68k-palmos)
+override COMPILER_SOURCEDIR+=src
+endif
+ifeq ($(FULL_TARGET),m68k-embedded)
+override COMPILER_SOURCEDIR+=src
+endif
+ifeq ($(FULL_TARGET),powerpc-linux)
+override COMPILER_SOURCEDIR+=src
+endif
+ifeq ($(FULL_TARGET),powerpc-netbsd)
+override COMPILER_SOURCEDIR+=src
+endif
+ifeq ($(FULL_TARGET),powerpc-amiga)
+override COMPILER_SOURCEDIR+=src
+endif
+ifeq ($(FULL_TARGET),powerpc-macos)
+override COMPILER_SOURCEDIR+=src
+endif
+ifeq ($(FULL_TARGET),powerpc-darwin)
+override COMPILER_SOURCEDIR+=src
+endif
+ifeq ($(FULL_TARGET),powerpc-morphos)
+override COMPILER_SOURCEDIR+=src
+endif
+ifeq ($(FULL_TARGET),powerpc-embedded)
+override COMPILER_SOURCEDIR+=src
+endif
+ifeq ($(FULL_TARGET),sparc-linux)
+override COMPILER_SOURCEDIR+=src
+endif
+ifeq ($(FULL_TARGET),sparc-netbsd)
+override COMPILER_SOURCEDIR+=src
+endif
+ifeq ($(FULL_TARGET),sparc-solaris)
+override COMPILER_SOURCEDIR+=src
+endif
+ifeq ($(FULL_TARGET),sparc-embedded)
+override COMPILER_SOURCEDIR+=src
+endif
+ifeq ($(FULL_TARGET),x86_64-linux)
+override COMPILER_SOURCEDIR+=src
+endif
+ifeq ($(FULL_TARGET),x86_64-freebsd)
+override COMPILER_SOURCEDIR+=src
+endif
+ifeq ($(FULL_TARGET),x86_64-darwin)
+override COMPILER_SOURCEDIR+=src
+endif
+ifeq ($(FULL_TARGET),x86_64-win64)
+override COMPILER_SOURCEDIR+=src
+endif
+ifeq ($(FULL_TARGET),x86_64-embedded)
+override COMPILER_SOURCEDIR+=src
+endif
+ifeq ($(FULL_TARGET),arm-linux)
+override COMPILER_SOURCEDIR+=src
+endif
+ifeq ($(FULL_TARGET),arm-palmos)
+override COMPILER_SOURCEDIR+=src
+endif
+ifeq ($(FULL_TARGET),arm-darwin)
+override COMPILER_SOURCEDIR+=src
+endif
+ifeq ($(FULL_TARGET),arm-wince)
+override COMPILER_SOURCEDIR+=src
+endif
+ifeq ($(FULL_TARGET),arm-gba)
+override COMPILER_SOURCEDIR+=src
+endif
+ifeq ($(FULL_TARGET),arm-nds)
+override COMPILER_SOURCEDIR+=src
+endif
+ifeq ($(FULL_TARGET),arm-embedded)
+override COMPILER_SOURCEDIR+=src
+endif
+ifeq ($(FULL_TARGET),arm-symbian)
+override COMPILER_SOURCEDIR+=src
+endif
+ifeq ($(FULL_TARGET),powerpc64-linux)
+override COMPILER_SOURCEDIR+=src
+endif
+ifeq ($(FULL_TARGET),powerpc64-darwin)
+override COMPILER_SOURCEDIR+=src
+endif
+ifeq ($(FULL_TARGET),powerpc64-embedded)
+override COMPILER_SOURCEDIR+=src
+endif
+ifeq ($(FULL_TARGET),avr-embedded)
+override COMPILER_SOURCEDIR+=src
+endif
+ifeq ($(FULL_TARGET),armeb-linux)
+override COMPILER_SOURCEDIR+=src
+endif
+ifeq ($(FULL_TARGET),armeb-embedded)
+override COMPILER_SOURCEDIR+=src
+endif
+override SHARED_BUILD=n
+override SHARED_BUILD=n
+ifdef REQUIRE_UNITSDIR
+override UNITSDIR+=$(REQUIRE_UNITSDIR)
+endif
+ifdef REQUIRE_PACKAGESDIR
+override PACKAGESDIR+=$(REQUIRE_PACKAGESDIR)
+endif
+ifdef ZIPINSTALL
+ifneq ($(findstring $(OS_TARGET),$(UNIXs)),)
+UNIXHier=1
+endif
+else
+ifneq ($(findstring $(OS_SOURCE),$(UNIXs)),)
+UNIXHier=1
+endif
+endif
+ifndef INSTALL_PREFIX
+ifdef PREFIX
+INSTALL_PREFIX=$(PREFIX)
+endif
+endif
+ifndef INSTALL_PREFIX
+ifdef UNIXHier
+INSTALL_PREFIX=/usr/local
+else
+ifdef INSTALL_FPCPACKAGE
+INSTALL_BASEDIR:=/pp
+else
+INSTALL_BASEDIR:=/$(PACKAGE_NAME)
+endif
+endif
+endif
+export INSTALL_PREFIX
+ifdef INSTALL_FPCSUBDIR
+export INSTALL_FPCSUBDIR
+endif
+ifndef DIST_DESTDIR
+DIST_DESTDIR:=$(BASEDIR)
+endif
+export DIST_DESTDIR
+ifndef COMPILER_UNITTARGETDIR
+ifdef PACKAGEDIR_MAIN
+COMPILER_UNITTARGETDIR=$(PACKAGEDIR_MAIN)/units/$(TARGETSUFFIX)
+else
+COMPILER_UNITTARGETDIR=units/$(TARGETSUFFIX)
+endif
+endif
+ifndef COMPILER_TARGETDIR
+COMPILER_TARGETDIR=.
+endif
+ifndef INSTALL_BASEDIR
+ifdef UNIXHier
+ifdef INSTALL_FPCPACKAGE
+INSTALL_BASEDIR:=$(INSTALL_PREFIX)/lib/fpc/$(FPC_VERSION)
+else
+INSTALL_BASEDIR:=$(INSTALL_PREFIX)/lib/$(PACKAGE_NAME)
+endif
+else
+INSTALL_BASEDIR:=$(INSTALL_PREFIX)
+endif
+endif
+ifndef INSTALL_BINDIR
+ifdef UNIXHier
+INSTALL_BINDIR:=$(INSTALL_PREFIX)/bin
+else
+INSTALL_BINDIR:=$(INSTALL_BASEDIR)/bin
+ifdef INSTALL_FPCPACKAGE
+ifdef CROSSCOMPILE
+ifdef CROSSINSTALL
+INSTALL_BINDIR:=$(INSTALL_BINDIR)/$(SOURCESUFFIX)
+else
+INSTALL_BINDIR:=$(INSTALL_BINDIR)/$(TARGETSUFFIX)
+endif
+else
+INSTALL_BINDIR:=$(INSTALL_BINDIR)/$(TARGETSUFFIX)
+endif
+endif
+endif
+endif
+ifndef INSTALL_UNITDIR
+INSTALL_UNITDIR:=$(INSTALL_BASEDIR)/units/$(TARGETSUFFIX)
+ifdef INSTALL_FPCPACKAGE
+ifdef PACKAGE_NAME
+INSTALL_UNITDIR:=$(INSTALL_UNITDIR)/$(PACKAGE_NAME)
+endif
+endif
+endif
+ifndef INSTALL_LIBDIR
+ifdef UNIXHier
+INSTALL_LIBDIR:=$(INSTALL_PREFIX)/lib
+else
+INSTALL_LIBDIR:=$(INSTALL_UNITDIR)
+endif
+endif
+ifndef INSTALL_SOURCEDIR
+ifdef UNIXHier
+ifdef BSDhier
+SRCPREFIXDIR=share/src
+else
+ifdef linuxHier
+SRCPREFIXDIR=share/src
+else
+SRCPREFIXDIR=src
+endif
+endif
+ifdef INSTALL_FPCPACKAGE
+ifdef INSTALL_FPCSUBDIR
+INSTALL_SOURCEDIR:=$(INSTALL_PREFIX)/$(SRCPREFIXDIR)/fpc-$(FPC_VERSION)/$(INSTALL_FPCSUBDIR)/$(PACKAGE_NAME)
+else
+INSTALL_SOURCEDIR:=$(INSTALL_PREFIX)/$(SRCPREFIXDIR)/fpc-$(FPC_VERSION)/$(PACKAGE_NAME)
+endif
+else
+INSTALL_SOURCEDIR:=$(INSTALL_PREFIX)/$(SRCPREFIXDIR)/$(PACKAGE_NAME)-$(PACKAGE_VERSION)
+endif
+else
+ifdef INSTALL_FPCPACKAGE
+ifdef INSTALL_FPCSUBDIR
+INSTALL_SOURCEDIR:=$(INSTALL_BASEDIR)/source/$(INSTALL_FPCSUBDIR)/$(PACKAGE_NAME)
+else
+INSTALL_SOURCEDIR:=$(INSTALL_BASEDIR)/source/$(PACKAGE_NAME)
+endif
+else
+INSTALL_SOURCEDIR:=$(INSTALL_BASEDIR)/source
+endif
+endif
+endif
+ifndef INSTALL_DOCDIR
+ifdef UNIXHier
+ifdef BSDhier
+DOCPREFIXDIR=share/doc
+else
+ifdef linuxHier
+DOCPREFIXDIR=share/doc
+else
+DOCPREFIXDIR=doc
+endif
+endif
+ifdef INSTALL_FPCPACKAGE
+INSTALL_DOCDIR:=$(INSTALL_PREFIX)/$(DOCPREFIXDIR)/fpc-$(FPC_VERSION)/$(PACKAGE_NAME)
+else
+INSTALL_DOCDIR:=$(INSTALL_PREFIX)/$(DOCPREFIXDIR)/$(PACKAGE_NAME)-$(PACKAGE_VERSION)
+endif
+else
+ifdef INSTALL_FPCPACKAGE
+INSTALL_DOCDIR:=$(INSTALL_BASEDIR)/doc/$(PACKAGE_NAME)
+else
+INSTALL_DOCDIR:=$(INSTALL_BASEDIR)/doc
+endif
+endif
+endif
+ifndef INSTALL_EXAMPLEDIR
+ifdef UNIXHier
+ifdef INSTALL_FPCPACKAGE
+ifdef BSDhier
+INSTALL_EXAMPLEDIR:=$(INSTALL_PREFIX)/share/examples/fpc-$(FPC_VERSION)/$(PACKAGE_NAME)
+else
+ifdef linuxHier
+INSTALL_EXAMPLEDIR:=$(INSTALL_DOCDIR)/examples
+else
+INSTALL_EXAMPLEDIR:=$(INSTALL_PREFIX)/doc/fpc-$(FPC_VERSION)/examples/$(PACKAGE_NAME)
+endif
+endif
+else
+ifdef BSDhier
+INSTALL_EXAMPLEDIR:=$(INSTALL_PREFIX)/share/examples/$(PACKAGE_NAME)-$(PACKAGE_VERSION)
+else
+ifdef linuxHier
+INSTALL_EXAMPLEDIR:=$(INSTALL_DOCDIR)/examples/$(PACKAGE_NAME)-$(PACKAGE_VERSION)
+else
+INSTALL_EXAMPLEDIR:=$(INSTALL_PREFIX)/doc/$(PACKAGE_NAME)-$(PACKAGE_VERSION)
+endif
+endif
+endif
+else
+ifdef INSTALL_FPCPACKAGE
+INSTALL_EXAMPLEDIR:=$(INSTALL_BASEDIR)/examples/$(PACKAGE_NAME)
+else
+INSTALL_EXAMPLEDIR:=$(INSTALL_BASEDIR)/examples
+endif
+endif
+endif
+ifndef INSTALL_DATADIR
+INSTALL_DATADIR=$(INSTALL_BASEDIR)
+endif
+ifndef INSTALL_SHAREDDIR
+INSTALL_SHAREDDIR=$(INSTALL_PREFIX)/lib
+endif
+ifdef CROSSCOMPILE
+ifndef CROSSBINDIR
+CROSSBINDIR:=$(wildcard $(CROSSTARGETDIR)/bin/$(SOURCESUFFIX))
+ifeq ($(CROSSBINDIR),)
+CROSSBINDIR:=$(wildcard $(INSTALL_BASEDIR)/cross/$(TARGETSUFFIX)/bin/$(FULL_SOURCE))
+endif
+endif
+else
+CROSSBINDIR=
+endif
+BATCHEXT=.bat
+LOADEREXT=.as
+EXEEXT=.exe
+PPLEXT=.ppl
+PPUEXT=.ppu
+OEXT=.o
+ASMEXT=.s
+SMARTEXT=.sl
+STATICLIBEXT=.a
+SHAREDLIBEXT=.so
+SHAREDLIBPREFIX=libfp
+STATICLIBPREFIX=libp
+IMPORTLIBPREFIX=libimp
+RSTEXT=.rst
+ifeq ($(findstring 1.0.,$(FPC_VERSION)),)
+ifeq ($(OS_TARGET),go32v1)
+STATICLIBPREFIX=
+SHORTSUFFIX=v1
+endif
+ifeq ($(OS_TARGET),go32v2)
+STATICLIBPREFIX=
+SHORTSUFFIX=dos
+IMPORTLIBPREFIX=
+endif
+ifeq ($(OS_TARGET),watcom)
+STATICLIBPREFIX=
+OEXT=.obj
+ASMEXT=.asm
+SHAREDLIBEXT=.dll
+SHORTSUFFIX=wat
+IMPORTLIBPREFIX=
+endif
+ifeq ($(OS_TARGET),linux)
+BATCHEXT=.sh
+EXEEXT=
+HASSHAREDLIB=1
+SHORTSUFFIX=lnx
+endif
+ifeq ($(OS_TARGET),freebsd)
+BATCHEXT=.sh
+EXEEXT=
+HASSHAREDLIB=1
+SHORTSUFFIX=fbs
+endif
+ifeq ($(OS_TARGET),netbsd)
+BATCHEXT=.sh
+EXEEXT=
+HASSHAREDLIB=1
+SHORTSUFFIX=nbs
+endif
+ifeq ($(OS_TARGET),openbsd)
+BATCHEXT=.sh
+EXEEXT=
+HASSHAREDLIB=1
+SHORTSUFFIX=obs
+endif
+ifeq ($(OS_TARGET),win32)
+SHAREDLIBEXT=.dll
+SHORTSUFFIX=w32
+endif
+ifeq ($(OS_TARGET),os2)
+BATCHEXT=.cmd
+AOUTEXT=.out
+STATICLIBPREFIX=
+SHAREDLIBEXT=.dll
+SHORTSUFFIX=os2
+ECHO=echo
+IMPORTLIBPREFIX=
+endif
+ifeq ($(OS_TARGET),emx)
+BATCHEXT=.cmd
+AOUTEXT=.out
+STATICLIBPREFIX=
+SHAREDLIBEXT=.dll
+SHORTSUFFIX=emx
+ECHO=echo
+IMPORTLIBPREFIX=
+endif
+ifeq ($(OS_TARGET),amiga)
+EXEEXT=
+SHAREDLIBEXT=.library
+SHORTSUFFIX=amg
+endif
+ifeq ($(OS_TARGET),morphos)
+EXEEXT=
+SHAREDLIBEXT=.library
+SHORTSUFFIX=mos
+endif
+ifeq ($(OS_TARGET),atari)
+EXEEXT=.ttp
+SHORTSUFFIX=ata
+endif
+ifeq ($(OS_TARGET),beos)
+BATCHEXT=.sh
+EXEEXT=
+SHORTSUFFIX=be
+endif
+ifeq ($(OS_TARGET),haiku)
+BATCHEXT=.sh
+EXEEXT=
+SHORTSUFFIX=hai
+endif
+ifeq ($(OS_TARGET),solaris)
+BATCHEXT=.sh
+EXEEXT=
+SHORTSUFFIX=sun
+endif
+ifeq ($(OS_TARGET),qnx)
+BATCHEXT=.sh
+EXEEXT=
+SHORTSUFFIX=qnx
+endif
+ifeq ($(OS_TARGET),netware)
+EXEEXT=.nlm
+STATICLIBPREFIX=
+SHORTSUFFIX=nw
+IMPORTLIBPREFIX=imp
+endif
+ifeq ($(OS_TARGET),netwlibc)
+EXEEXT=.nlm
+STATICLIBPREFIX=
+SHORTSUFFIX=nwl
+IMPORTLIBPREFIX=imp
+endif
+ifeq ($(OS_TARGET),macos)
+BATCHEXT=
+EXEEXT=
+DEBUGSYMEXT=.xcoff
+SHORTSUFFIX=mac
+IMPORTLIBPREFIX=imp
+endif
+ifeq ($(OS_TARGET),darwin)
+BATCHEXT=.sh
+EXEEXT=
+HASSHAREDLIB=1
+SHORTSUFFIX=dwn
+endif
+ifeq ($(OS_TARGET),gba)
+EXEEXT=.gba
+SHAREDLIBEXT=.so
+SHORTSUFFIX=gba
+endif
+ifeq ($(OS_TARGET),symbian)
+SHAREDLIBEXT=.dll
+SHORTSUFFIX=symbian
+endif
+else
+ifeq ($(OS_TARGET),go32v1)
+PPUEXT=.pp1
+OEXT=.o1
+ASMEXT=.s1
+SMARTEXT=.sl1
+STATICLIBEXT=.a1
+SHAREDLIBEXT=.so1
+STATICLIBPREFIX=
+SHORTSUFFIX=v1
+IMPORTLIBPREFIX=
+endif
+ifeq ($(OS_TARGET),go32v2)
+STATICLIBPREFIX=
+SHORTSUFFIX=dos
+IMPORTLIBPREFIX=
+endif
+ifeq ($(OS_TARGET),watcom)
+STATICLIBPREFIX=
+SHORTSUFFIX=wat
+IMPORTLIBPREFIX=
+endif
+ifeq ($(OS_TARGET),linux)
+BATCHEXT=.sh
+EXEEXT=
+HASSHAREDLIB=1
+SHORTSUFFIX=lnx
+endif
+ifeq ($(OS_TARGET),freebsd)
+BATCHEXT=.sh
+EXEEXT=
+HASSHAREDLIB=1
+SHORTSUFFIX=fbs
+endif
+ifeq ($(OS_TARGET),netbsd)
+BATCHEXT=.sh
+EXEEXT=
+HASSHAREDLIB=1
+SHORTSUFFIX=nbs
+endif
+ifeq ($(OS_TARGET),openbsd)
+BATCHEXT=.sh
+EXEEXT=
+HASSHAREDLIB=1
+SHORTSUFFIX=obs
+endif
+ifeq ($(OS_TARGET),win32)
+PPUEXT=.ppw
+OEXT=.ow
+ASMEXT=.sw
+SMARTEXT=.slw
+STATICLIBEXT=.aw
+SHAREDLIBEXT=.dll
+SHORTSUFFIX=w32
+endif
+ifeq ($(OS_TARGET),os2)
+BATCHEXT=.cmd
+PPUEXT=.ppo
+ASMEXT=.so2
+OEXT=.oo2
+AOUTEXT=.out
+SMARTEXT=.sl2
+STATICLIBPREFIX=
+STATICLIBEXT=.ao2
+SHAREDLIBEXT=.dll
+SHORTSUFFIX=os2
+ECHO=echo
+IMPORTLIBPREFIX=
+endif
+ifeq ($(OS_TARGET),amiga)
+EXEEXT=
+PPUEXT=.ppu
+ASMEXT=.s
+OEXT=.o
+SMARTEXT=.sl
+STATICLIBEXT=.a
+SHAREDLIBEXT=.library
+SHORTSUFFIX=amg
+endif
+ifeq ($(OS_TARGET),atari)
+PPUEXT=.ppu
+ASMEXT=.s
+OEXT=.o
+SMARTEXT=.sl
+STATICLIBEXT=.a
+EXEEXT=.ttp
+SHORTSUFFIX=ata
+endif
+ifeq ($(OS_TARGET),beos)
+BATCHEXT=.sh
+PPUEXT=.ppu
+ASMEXT=.s
+OEXT=.o
+SMARTEXT=.sl
+STATICLIBEXT=.a
+EXEEXT=
+SHORTSUFFIX=be
+endif
+ifeq ($(OS_TARGET),solaris)
+BATCHEXT=.sh
+PPUEXT=.ppu
+ASMEXT=.s
+OEXT=.o
+SMARTEXT=.sl
+STATICLIBEXT=.a
+EXEEXT=
+SHORTSUFFIX=sun
+endif
+ifeq ($(OS_TARGET),qnx)
+BATCHEXT=.sh
+PPUEXT=.ppu
+ASMEXT=.s
+OEXT=.o
+SMARTEXT=.sl
+STATICLIBEXT=.a
+EXEEXT=
+SHORTSUFFIX=qnx
+endif
+ifeq ($(OS_TARGET),netware)
+STATICLIBPREFIX=
+PPUEXT=.ppu
+OEXT=.o
+ASMEXT=.s
+SMARTEXT=.sl
+STATICLIBEXT=.a
+SHAREDLIBEXT=.nlm
+EXEEXT=.nlm
+SHORTSUFFIX=nw
+IMPORTLIBPREFIX=imp
+endif
+ifeq ($(OS_TARGET),netwlibc)
+STATICLIBPREFIX=
+PPUEXT=.ppu
+OEXT=.o
+ASMEXT=.s
+SMARTEXT=.sl
+STATICLIBEXT=.a
+SHAREDLIBEXT=.nlm
+EXEEXT=.nlm
+SHORTSUFFIX=nwl
+IMPORTLIBPREFIX=imp
+endif
+ifeq ($(OS_TARGET),macos)
+BATCHEXT=
+PPUEXT=.ppu
+ASMEXT=.s
+OEXT=.o
+SMARTEXT=.sl
+STATICLIBEXT=.a
+EXEEXT=
+DEBUGSYMEXT=.xcoff
+SHORTSUFFIX=mac
+IMPORTLIBPREFIX=imp
+endif
+endif
+ifneq ($(findstring $(OS_SOURCE),$(LIMIT83fs)),)
+FPCMADE=fpcmade.$(SHORTSUFFIX)
+ZIPSUFFIX=$(SHORTSUFFIX)
+ZIPCROSSPREFIX=
+ZIPSOURCESUFFIX=src
+ZIPEXAMPLESUFFIX=exm
+else
+FPCMADE=fpcmade.$(TARGETSUFFIX)
+ZIPSOURCESUFFIX=.source
+ZIPEXAMPLESUFFIX=.examples
+ifdef CROSSCOMPILE
+ZIPSUFFIX=.$(SOURCESUFFIX)
+ZIPCROSSPREFIX=$(TARGETSUFFIX)-
+else
+ZIPSUFFIX=.$(TARGETSUFFIX)
+ZIPCROSSPREFIX=
+endif
+endif
+ifndef ECHO
+ECHO:=$(strip $(wildcard $(addsuffix /gecho$(SRCEXEEXT),$(SEARCHPATH))))
+ifeq ($(ECHO),)
+ECHO:=$(strip $(wildcard $(addsuffix /echo$(SRCEXEEXT),$(SEARCHPATH))))
+ifeq ($(ECHO),)
+ECHO= __missing_command_ECHO
+else
+ECHO:=$(firstword $(ECHO))
+endif
+else
+ECHO:=$(firstword $(ECHO))
+endif
+endif
+export ECHO
+ifndef DATE
+DATE:=$(strip $(wildcard $(addsuffix /gdate$(SRCEXEEXT),$(SEARCHPATH))))
+ifeq ($(DATE),)
+DATE:=$(strip $(wildcard $(addsuffix /date$(SRCEXEEXT),$(SEARCHPATH))))
+ifeq ($(DATE),)
+DATE= __missing_command_DATE
+else
+DATE:=$(firstword $(DATE))
+endif
+else
+DATE:=$(firstword $(DATE))
+endif
+endif
+export DATE
+ifndef GINSTALL
+GINSTALL:=$(strip $(wildcard $(addsuffix /ginstall$(SRCEXEEXT),$(SEARCHPATH))))
+ifeq ($(GINSTALL),)
+GINSTALL:=$(strip $(wildcard $(addsuffix /install$(SRCEXEEXT),$(SEARCHPATH))))
+ifeq ($(GINSTALL),)
+GINSTALL= __missing_command_GINSTALL
+else
+GINSTALL:=$(firstword $(GINSTALL))
+endif
+else
+GINSTALL:=$(firstword $(GINSTALL))
+endif
+endif
+export GINSTALL
+ifndef CPPROG
+CPPROG:=$(strip $(wildcard $(addsuffix /cp$(SRCEXEEXT),$(SEARCHPATH))))
+ifeq ($(CPPROG),)
+CPPROG= __missing_command_CPPROG
+else
+CPPROG:=$(firstword $(CPPROG))
+endif
+endif
+export CPPROG
+ifndef RMPROG
+RMPROG:=$(strip $(wildcard $(addsuffix /rm$(SRCEXEEXT),$(SEARCHPATH))))
+ifeq ($(RMPROG),)
+RMPROG= __missing_command_RMPROG
+else
+RMPROG:=$(firstword $(RMPROG))
+endif
+endif
+export RMPROG
+ifndef MVPROG
+MVPROG:=$(strip $(wildcard $(addsuffix /mv$(SRCEXEEXT),$(SEARCHPATH))))
+ifeq ($(MVPROG),)
+MVPROG= __missing_command_MVPROG
+else
+MVPROG:=$(firstword $(MVPROG))
+endif
+endif
+export MVPROG
+ifndef MKDIRPROG
+MKDIRPROG:=$(strip $(wildcard $(addsuffix /gmkdir$(SRCEXEEXT),$(SEARCHPATH))))
+ifeq ($(MKDIRPROG),)
+MKDIRPROG:=$(strip $(wildcard $(addsuffix /mkdir$(SRCEXEEXT),$(SEARCHPATH))))
+ifeq ($(MKDIRPROG),)
+MKDIRPROG= __missing_command_MKDIRPROG
+else
+MKDIRPROG:=$(firstword $(MKDIRPROG))
+endif
+else
+MKDIRPROG:=$(firstword $(MKDIRPROG))
+endif
+endif
+export MKDIRPROG
+ifndef ECHOREDIR
+ifndef inUnix
+ECHOREDIR=echo
+else
+ECHOREDIR=$(ECHO)
+endif
+endif
+ifndef COPY
+COPY:=$(CPPROG) -fp
+endif
+ifndef COPYTREE
+COPYTREE:=$(CPPROG) -Rfp
+endif
+ifndef MKDIRTREE
+MKDIRTREE:=$(MKDIRPROG) -p
+endif
+ifndef MOVE
+MOVE:=$(MVPROG) -f
+endif
+ifndef DEL
+DEL:=$(RMPROG) -f
+endif
+ifndef DELTREE
+DELTREE:=$(RMPROG) -rf
+endif
+ifndef INSTALL
+ifdef inUnix
+INSTALL:=$(GINSTALL) -c -m 644
+else
+INSTALL:=$(COPY)
+endif
+endif
+ifndef INSTALLEXE
+ifdef inUnix
+INSTALLEXE:=$(GINSTALL) -c -m 755
+else
+INSTALLEXE:=$(COPY)
+endif
+endif
+ifndef MKDIR
+MKDIR:=$(GINSTALL) -m 755 -d
+endif
+export ECHOREDIR COPY COPYTREE MOVE DEL DELTREE INSTALL INSTALLEXE MKDIR
+ifndef PPUMOVE
+PPUMOVE:=$(strip $(wildcard $(addsuffix /ppumove$(SRCEXEEXT),$(SEARCHPATH))))
+ifeq ($(PPUMOVE),)
+PPUMOVE= __missing_command_PPUMOVE
+else
+PPUMOVE:=$(firstword $(PPUMOVE))
+endif
+endif
+export PPUMOVE
+ifndef FPCMAKE
+FPCMAKE:=$(strip $(wildcard $(addsuffix /fpcmake$(SRCEXEEXT),$(SEARCHPATH))))
+ifeq ($(FPCMAKE),)
+FPCMAKE= __missing_command_FPCMAKE
+else
+FPCMAKE:=$(firstword $(FPCMAKE))
+endif
+endif
+export FPCMAKE
+ifndef ZIPPROG
+ZIPPROG:=$(strip $(wildcard $(addsuffix /zip$(SRCEXEEXT),$(SEARCHPATH))))
+ifeq ($(ZIPPROG),)
+ZIPPROG= __missing_command_ZIPPROG
+else
+ZIPPROG:=$(firstword $(ZIPPROG))
+endif
+endif
+export ZIPPROG
+ifndef TARPROG
+TARPROG:=$(strip $(wildcard $(addsuffix /gtar$(SRCEXEEXT),$(SEARCHPATH))))
+ifeq ($(TARPROG),)
+TARPROG:=$(strip $(wildcard $(addsuffix /tar$(SRCEXEEXT),$(SEARCHPATH))))
+ifeq ($(TARPROG),)
+TARPROG= __missing_command_TARPROG
+else
+TARPROG:=$(firstword $(TARPROG))
+endif
+else
+TARPROG:=$(firstword $(TARPROG))
+endif
+endif
+export TARPROG
+ASNAME=$(BINUTILSPREFIX)as
+LDNAME=$(BINUTILSPREFIX)ld
+ARNAME=$(BINUTILSPREFIX)ar
+RCNAME=$(BINUTILSPREFIX)rc
+ifneq ($(findstring 1.0.,$(FPC_VERSION)),)
+ifeq ($(OS_TARGET),win32)
+ifeq ($(CROSSBINDIR),)
+ASNAME=asw
+LDNAME=ldw
+ARNAME=arw
+endif
+endif
+endif
+ifndef ASPROG
+ifdef CROSSBINDIR
+ASPROG=$(CROSSBINDIR)/$(ASNAME)$(SRCEXEEXT)
+else
+ASPROG=$(ASNAME)
+endif
+endif
+ifndef LDPROG
+ifdef CROSSBINDIR
+LDPROG=$(CROSSBINDIR)/$(LDNAME)$(SRCEXEEXT)
+else
+LDPROG=$(LDNAME)
+endif
+endif
+ifndef RCPROG
+ifdef CROSSBINDIR
+RCPROG=$(CROSSBINDIR)/$(RCNAME)$(SRCEXEEXT)
+else
+RCPROG=$(RCNAME)
+endif
+endif
+ifndef ARPROG
+ifdef CROSSBINDIR
+ARPROG=$(CROSSBINDIR)/$(ARNAME)$(SRCEXEEXT)
+else
+ARPROG=$(ARNAME)
+endif
+endif
+AS=$(ASPROG)
+LD=$(LDPROG)
+RC=$(RCPROG)
+AR=$(ARPROG)
+PPAS=ppas$(SRCBATCHEXT)
+ifdef inUnix
+LDCONFIG=ldconfig
+else
+LDCONFIG=
+endif
+ifdef DATE
+DATESTR:=$(shell $(DATE) +%Y%m%d)
+else
+DATESTR=
+endif
+ifndef UPXPROG
+ifeq ($(OS_TARGET),go32v2)
+UPXPROG:=1
+endif
+ifeq ($(OS_TARGET),win32)
+UPXPROG:=1
+endif
+ifdef UPXPROG
+UPXPROG:=$(strip $(wildcard $(addsuffix /upx$(SRCEXEEXT),$(SEARCHPATH))))
+ifeq ($(UPXPROG),)
+UPXPROG=
+else
+UPXPROG:=$(firstword $(UPXPROG))
+endif
+else
+UPXPROG=
+endif
+endif
+export UPXPROG
+ZIPOPT=-9
+ZIPEXT=.zip
+ifeq ($(USETAR),bz2)
+TAROPT=vj
+TAREXT=.tar.bz2
+else
+TAROPT=vz
+TAREXT=.tar.gz
+endif
+override REQUIRE_PACKAGES=rtl 
+ifeq ($(FULL_TARGET),i386-linux)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),i386-go32v2)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),i386-win32)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),i386-os2)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),i386-freebsd)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),i386-beos)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),i386-haiku)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),i386-netbsd)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),i386-solaris)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),i386-qnx)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),i386-netware)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),i386-openbsd)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),i386-wdosx)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),i386-darwin)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),i386-emx)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),i386-watcom)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),i386-netwlibc)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),i386-wince)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),i386-embedded)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),i386-symbian)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),m68k-linux)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),m68k-freebsd)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),m68k-netbsd)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),m68k-amiga)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),m68k-atari)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),m68k-openbsd)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),m68k-palmos)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),m68k-embedded)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),powerpc-linux)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),powerpc-netbsd)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),powerpc-amiga)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),powerpc-macos)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),powerpc-darwin)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),powerpc-morphos)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),powerpc-embedded)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),sparc-linux)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),sparc-netbsd)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),sparc-solaris)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),sparc-embedded)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),x86_64-linux)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),x86_64-freebsd)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),x86_64-darwin)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),x86_64-win64)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),x86_64-embedded)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),arm-linux)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),arm-palmos)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),arm-darwin)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),arm-wince)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),arm-gba)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),arm-nds)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),arm-embedded)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),arm-symbian)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),powerpc64-linux)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),powerpc64-darwin)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),powerpc64-embedded)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),avr-embedded)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),armeb-linux)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),armeb-embedded)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifdef REQUIRE_PACKAGES_RTL
+PACKAGEDIR_RTL:=$(firstword $(subst /Makefile.fpc,,$(strip $(wildcard $(addsuffix /rtl/Makefile.fpc,$(PACKAGESDIR))))))
+ifneq ($(PACKAGEDIR_RTL),)
+ifneq ($(wildcard $(PACKAGEDIR_RTL)/units/$(TARGETSUFFIX)),)
+UNITDIR_RTL=$(PACKAGEDIR_RTL)/units/$(TARGETSUFFIX)
+else
+UNITDIR_RTL=$(PACKAGEDIR_RTL)
+endif
+ifdef CHECKDEPEND
+$(PACKAGEDIR_RTL)/$(FPCMADE):
+	$(MAKE) -C $(PACKAGEDIR_RTL) $(FPCMADE)
+override ALLDEPENDENCIES+=$(PACKAGEDIR_RTL)/$(FPCMADE)
+endif
+else
+PACKAGEDIR_RTL=
+UNITDIR_RTL:=$(subst /Package.fpc,,$(strip $(wildcard $(addsuffix /rtl/Package.fpc,$(UNITSDIR)))))
+ifneq ($(UNITDIR_RTL),)
+UNITDIR_RTL:=$(firstword $(UNITDIR_RTL))
+else
+UNITDIR_RTL=
+endif
+endif
+ifdef UNITDIR_RTL
+override COMPILER_UNITDIR+=$(UNITDIR_RTL)
+endif
+endif
+ifndef NOCPUDEF
+override FPCOPTDEF=$(ARCH)
+endif
+ifneq ($(OS_TARGET),$(OS_SOURCE))
+override FPCOPT+=-T$(OS_TARGET)
+endif
+ifneq ($(CPU_TARGET),$(CPU_SOURCE))
+override FPCOPT+=-P$(ARCH)
+endif
+ifeq ($(OS_SOURCE),openbsd)
+override FPCOPT+=-FD$(NEW_BINUTILS_PATH)
+endif
+ifndef CROSSBOOTSTRAP
+ifneq ($(BINUTILSPREFIX),)
+override FPCOPT+=-XP$(BINUTILSPREFIX)
+endif
+ifneq ($(BINUTILSPREFIX),)
+override FPCOPT+=-Xr$(RLINKPATH)
+endif
+endif
+ifdef UNITDIR
+override FPCOPT+=$(addprefix -Fu,$(UNITDIR))
+endif
+ifdef LIBDIR
+override FPCOPT+=$(addprefix -Fl,$(LIBDIR))
+endif
+ifdef OBJDIR
+override FPCOPT+=$(addprefix -Fo,$(OBJDIR))
+endif
+ifdef INCDIR
+override FPCOPT+=$(addprefix -Fi,$(INCDIR))
+endif
+ifdef LINKSMART
+override FPCOPT+=-XX
+endif
+ifdef CREATESMART
+override FPCOPT+=-CX
+endif
+ifdef DEBUG
+override FPCOPT+=-gl
+override FPCOPTDEF+=DEBUG
+endif
+ifdef RELEASE
+ifneq ($(findstring 2.0.,$(FPC_VERSION)),)
+ifeq ($(CPU_TARGET),i386)
+FPCCPUOPT:=-OG2p3
+endif
+ifeq ($(CPU_TARGET),powerpc)
+FPCCPUOPT:=-O1r
+endif
+else
+FPCCPUOPT:=-O2
+endif
+override FPCOPT+=-Ur -Xs $(FPCCPUOPT) -n
+override FPCOPTDEF+=RELEASE
+endif
+ifdef STRIP
+override FPCOPT+=-Xs
+endif
+ifdef OPTIMIZE
+override FPCOPT+=-O2
+endif
+ifdef VERBOSE
+override FPCOPT+=-vwni
+endif
+ifdef COMPILER_OPTIONS
+override FPCOPT+=$(COMPILER_OPTIONS)
+endif
+ifdef COMPILER_UNITDIR
+override FPCOPT+=$(addprefix -Fu,$(COMPILER_UNITDIR))
+endif
+ifdef COMPILER_LIBRARYDIR
+override FPCOPT+=$(addprefix -Fl,$(COMPILER_LIBRARYDIR))
+endif
+ifdef COMPILER_OBJECTDIR
+override FPCOPT+=$(addprefix -Fo,$(COMPILER_OBJECTDIR))
+endif
+ifdef COMPILER_INCLUDEDIR
+override FPCOPT+=$(addprefix -Fi,$(COMPILER_INCLUDEDIR))
+endif
+ifdef CROSSBINDIR
+override FPCOPT+=-FD$(CROSSBINDIR)
+endif
+ifdef COMPILER_TARGETDIR
+override FPCOPT+=-FE$(COMPILER_TARGETDIR)
+ifeq ($(COMPILER_TARGETDIR),.)
+override TARGETDIRPREFIX=
+else
+override TARGETDIRPREFIX=$(COMPILER_TARGETDIR)/
+endif
+endif
+ifdef COMPILER_UNITTARGETDIR
+override FPCOPT+=-FU$(COMPILER_UNITTARGETDIR)
+ifeq ($(COMPILER_UNITTARGETDIR),.)
+override UNITTARGETDIRPREFIX=
+else
+override UNITTARGETDIRPREFIX=$(COMPILER_UNITTARGETDIR)/
+endif
+else
+ifdef COMPILER_TARGETDIR
+override COMPILER_UNITTARGETDIR=$(COMPILER_TARGETDIR)
+override UNITTARGETDIRPREFIX=$(TARGETDIRPREFIX)
+endif
+endif
+ifdef CREATESHARED
+override FPCOPT+=-Cg
+ifeq ($(CPU_TARGET),i386)
+override FPCOPT+=-Aas
+endif
+endif
+ifeq ($(findstring 2.0.,$(FPC_VERSION)),)
+ifeq ($(OS_TARGET),linux)
+ifeq ($(CPU_TARGET),x86_64)
+override FPCOPT+=-Cg
+endif
+endif
+endif
+ifdef LINKSHARED
+endif
+ifdef OPT
+override FPCOPT+=$(OPT)
+endif
+ifdef FPCOPTDEF
+override FPCOPT+=$(addprefix -d,$(FPCOPTDEF))
+endif
+ifdef CFGFILE
+override FPCOPT+=@$(CFGFILE)
+endif
+ifdef USEENV
+override FPCEXTCMD:=$(FPCOPT)
+override FPCOPT:=!FPCEXTCMD
+export FPCEXTCMD
+endif
+override AFULL_TARGET=$(CPU_TARGET)-$(OS_TARGET)
+override AFULL_SOURCE=$(CPU_SOURCE)-$(OS_SOURCE)
+ifneq ($(AFULL_TARGET),$(AFULL_SOURCE))
+override ACROSSCOMPILE=1
+endif
+ifdef ACROSSCOMPILE
+override FPCOPT+=$(CROSSOPT)
+endif
+override COMPILER:=$(FPC) $(FPCOPT)
+ifeq (,$(findstring -s ,$(COMPILER)))
+EXECPPAS=
+else
+ifeq ($(FULL_SOURCE),$(FULL_TARGET))
+ifdef RUNBATCH
+EXECPPAS:=@$(RUNBATCH) $(PPAS)
+else
+EXECPPAS:=@$(PPAS)
+endif
+endif
+endif
+.PHONY: fpc_units
+ifneq ($(TARGET_UNITS)$(TARGET_IMPLICITUNITS),)
+override ALLTARGET+=fpc_units
+override UNITPPUFILES=$(addsuffix $(PPUEXT),$(TARGET_UNITS))
+override IMPLICITUNITPPUFILES=$(addsuffix $(PPUEXT),$(TARGET_IMPLICITUNITS))
+override INSTALLPPUFILES+=$(UNITPPUFILES) $(IMPLICITUNITPPUFILES)
+override CLEANPPUFILES+=$(UNITPPUFILES) $(IMPLICITUNITPPUFILES)
+endif
+fpc_units: $(COMPILER_UNITTARGETDIR) $(UNITPPUFILES)
+ifdef TARGET_RSTS
+override RSTFILES=$(addsuffix $(RSTEXT),$(TARGET_RSTS))
+override CLEANRSTFILES+=$(RSTFILES)
+endif
+.PHONY: fpc_all fpc_smart fpc_debug fpc_release fpc_shared
+$(FPCMADE): $(ALLDEPENDENCIES) $(ALLTARGET)
+	@$(ECHOREDIR) Compiled > $(FPCMADE)
+fpc_all: $(FPCMADE)
+fpc_smart:
+	$(MAKE) all LINKSMART=1 CREATESMART=1
+fpc_debug:
+	$(MAKE) all DEBUG=1
+fpc_release:
+	$(MAKE) all RELEASE=1
+.SUFFIXES: $(EXEEXT) $(PPUEXT) $(OEXT) .pas .lpr .dpr .pp .rc .res
+$(COMPILER_UNITTARGETDIR):
+	$(MKDIRTREE) $(COMPILER_UNITTARGETDIR)
+$(COMPILER_TARGETDIR):
+	$(MKDIRTREE) $(COMPILER_TARGETDIR)
+%$(PPUEXT): %.pp
+	$(COMPILER) $<
+	$(EXECPPAS)
+%$(PPUEXT): %.pas
+	$(COMPILER) $<
+	$(EXECPPAS)
+%$(EXEEXT): %.pp
+	$(COMPILER) $<
+	$(EXECPPAS)
+%$(EXEEXT): %.pas
+	$(COMPILER) $<
+	$(EXECPPAS)
+%$(EXEEXT): %.lpr
+	$(COMPILER) $<
+	$(EXECPPAS)
+%$(EXEEXT): %.dpr
+	$(COMPILER) $<
+	$(EXECPPAS)
+%.res: %.rc
+	windres -i $< -o $@
+vpath %.pp $(COMPILER_SOURCEDIR) $(COMPILER_INCLUDEDIR)
+vpath %.pas $(COMPILER_SOURCEDIR) $(COMPILER_INCLUDEDIR)
+vpath %.lpr $(COMPILER_SOURCEDIR) $(COMPILER_INCLUDEDIR)
+vpath %.dpr $(COMPILER_SOURCEDIR) $(COMPILER_INCLUDEDIR)
+vpath %.inc $(COMPILER_INCLUDEDIR)
+vpath %$(OEXT) $(COMPILER_UNITTARGETDIR)
+vpath %$(PPUEXT) $(COMPILER_UNITTARGETDIR)
+.PHONY: fpc_shared
+override INSTALLTARGET+=fpc_shared_install
+ifndef SHARED_LIBVERSION
+SHARED_LIBVERSION=$(FPC_VERSION)
+endif
+ifndef SHARED_LIBNAME
+SHARED_LIBNAME=$(PACKAGE_NAME)
+endif
+ifndef SHARED_FULLNAME
+SHARED_FULLNAME=$(SHAREDLIBPREFIX)$(SHARED_LIBNAME)-$(SHARED_LIBVERSION)$(SHAREDLIBEXT)
+endif
+ifndef SHARED_LIBUNITS
+SHARED_LIBUNITS:=$(TARGET_UNITS) $(TARGET_IMPLICITUNITS)
+override SHARED_LIBUNITS:=$(filter-out $(INSTALL_BUILDUNIT),$(SHARED_LIBUNITS))
+endif
+fpc_shared:
+ifdef HASSHAREDLIB
+	$(MAKE) all CREATESHARED=1 LINKSHARED=1 CREATESMART=1
+ifneq ($(SHARED_BUILD),n)
+	$(PPUMOVE) -q $(SHARED_LIBUNITS) -i$(COMPILER_UNITTARGETDIR) -o$(SHARED_FULLNAME) -d$(COMPILER_UNITTARGETDIR)
+endif
+else
+	@$(ECHO) Shared Libraries not supported
+endif
+fpc_shared_install:
+ifneq ($(SHARED_BUILD),n)
+ifneq ($(SHARED_LIBUNITS),)
+ifneq ($(wildcard $(COMPILER_UNITTARGETDIR)/$(SHARED_FULLNAME)),)
+	$(INSTALL) $(COMPILER_UNITTARGETDIR)/$(SHARED_FULLNAME) $(INSTALL_SHAREDDIR)
+endif
+endif
+endif
+.PHONY: fpc_install fpc_sourceinstall fpc_exampleinstall
+ifdef INSTALL_UNITS
+override INSTALLPPUFILES+=$(addsuffix $(PPUEXT),$(INSTALL_UNITS))
+endif
+ifdef INSTALL_BUILDUNIT
+override INSTALLPPUFILES:=$(filter-out $(INSTALL_BUILDUNIT)$(PPUEXT),$(INSTALLPPUFILES))
+endif
+ifdef INSTALLPPUFILES
+override INSTALLPPULINKFILES:=$(subst $(PPUEXT),$(OEXT),$(INSTALLPPUFILES)) $(addprefix $(STATICLIBPREFIX),$(subst $(PPUEXT),$(STATICLIBEXT),$(INSTALLPPUFILES))) $(addprefix $(IMPORTLIBPREFIX),$(subst $(PPUEXT),$(STATICLIBEXT),$(INSTALLPPUFILES)))
+ifneq ($(UNITTARGETDIRPREFIX),)
+override INSTALLPPUFILES:=$(addprefix $(UNITTARGETDIRPREFIX),$(notdir $(INSTALLPPUFILES)))
+override INSTALLPPULINKFILES:=$(wildcard $(addprefix $(UNITTARGETDIRPREFIX),$(notdir $(INSTALLPPULINKFILES))))
+endif
+override INSTALL_CREATEPACKAGEFPC=1
+endif
+ifdef INSTALLEXEFILES
+ifneq ($(TARGETDIRPREFIX),)
+override INSTALLEXEFILES:=$(addprefix $(TARGETDIRPREFIX),$(notdir $(INSTALLEXEFILES)))
+endif
+endif
+fpc_install: all $(INSTALLTARGET)
+ifdef INSTALLEXEFILES
+	$(MKDIR) $(INSTALL_BINDIR)
+ifdef UPXPROG
+	-$(UPXPROG) $(INSTALLEXEFILES)
+endif
+	$(INSTALLEXE) $(INSTALLEXEFILES) $(INSTALL_BINDIR)
+endif
+ifdef INSTALL_CREATEPACKAGEFPC
+ifdef FPCMAKE
+ifdef PACKAGE_VERSION
+ifneq ($(wildcard Makefile.fpc),)
+	$(FPCMAKE) -p -T$(CPU_TARGET)-$(OS_TARGET) Makefile.fpc
+	$(MKDIR) $(INSTALL_UNITDIR)
+	$(INSTALL) Package.fpc $(INSTALL_UNITDIR)
+endif
+endif
+endif
+endif
+ifdef INSTALLPPUFILES
+	$(MKDIR) $(INSTALL_UNITDIR)
+	$(INSTALL) $(INSTALLPPUFILES) $(INSTALL_UNITDIR)
+ifneq ($(INSTALLPPULINKFILES),)
+	$(INSTALL) $(INSTALLPPULINKFILES) $(INSTALL_UNITDIR)
+endif
+ifneq ($(wildcard $(LIB_FULLNAME)),)
+	$(MKDIR) $(INSTALL_LIBDIR)
+	$(INSTALL) $(LIB_FULLNAME) $(INSTALL_LIBDIR)
+ifdef inUnix
+	ln -sf $(LIB_FULLNAME) $(INSTALL_LIBDIR)/$(LIB_NAME)
+endif
+endif
+endif
+ifdef INSTALL_FILES
+	$(MKDIR) $(INSTALL_DATADIR)
+	$(INSTALL) $(INSTALL_FILES) $(INSTALL_DATADIR)
+endif
+fpc_sourceinstall: distclean
+	$(MKDIR) $(INSTALL_SOURCEDIR)
+	$(COPYTREE) $(BASEDIR)/* $(INSTALL_SOURCEDIR)
+fpc_exampleinstall: $(addsuffix _distclean,$(TARGET_EXAMPLEDIRS))
+ifdef HASEXAMPLES
+	$(MKDIR) $(INSTALL_EXAMPLEDIR)
+endif
+ifdef EXAMPLESOURCEFILES
+	$(COPY) $(EXAMPLESOURCEFILES) $(INSTALL_EXAMPLEDIR)
+endif
+ifdef TARGET_EXAMPLEDIRS
+	$(COPYTREE) $(addsuffix /*,$(TARGET_EXAMPLEDIRS)) $(INSTALL_EXAMPLEDIR)
+endif
+.PHONY: fpc_distinstall
+fpc_distinstall: install exampleinstall
+.PHONY: fpc_zipinstall fpc_zipsourceinstall fpc_zipexampleinstall
+ifndef PACKDIR
+ifndef inUnix
+PACKDIR=$(BASEDIR)/../fpc-pack
+else
+PACKDIR=/tmp/fpc-pack
+endif
+endif
+ifndef ZIPNAME
+ifdef DIST_ZIPNAME
+ZIPNAME=$(DIST_ZIPNAME)
+else
+ZIPNAME=$(PACKAGE_NAME)
+endif
+endif
+ifndef FULLZIPNAME
+FULLZIPNAME=$(ZIPCROSSPREFIX)$(ZIPPREFIX)$(ZIPNAME)$(ZIPSUFFIX)
+endif
+ifndef ZIPTARGET
+ifdef DIST_ZIPTARGET
+ZIPTARGET=DIST_ZIPTARGET
+else
+ZIPTARGET=install
+endif
+endif
+ifndef USEZIP
+ifdef inUnix
+USETAR=1
+endif
+endif
+ifndef inUnix
+USEZIPWRAPPER=1
+endif
+ifdef USEZIPWRAPPER
+ZIPPATHSEP=$(PATHSEP)
+ZIPWRAPPER=$(subst /,$(PATHSEP),$(DIST_DESTDIR)/fpczip$(SRCBATCHEXT))
+else
+ZIPPATHSEP=/
+endif
+ZIPCMD_CDPACK:=cd $(subst /,$(ZIPPATHSEP),$(PACKDIR))
+ZIPCMD_CDBASE:=cd $(subst /,$(ZIPPATHSEP),$(BASEDIR))
+ifdef USETAR
+ZIPDESTFILE:=$(DIST_DESTDIR)/$(FULLZIPNAME)$(TAREXT)
+ZIPCMD_ZIP:=$(TARPROG) cf$(TAROPT) $(ZIPDESTFILE) *
+else
+ZIPDESTFILE:=$(DIST_DESTDIR)/$(FULLZIPNAME)$(ZIPEXT)
+ZIPCMD_ZIP:=$(subst /,$(ZIPPATHSEP),$(ZIPPROG)) -Dr $(ZIPOPT) $(ZIPDESTFILE) *
+endif
+fpc_zipinstall:
+	$(MAKE) $(ZIPTARGET) INSTALL_PREFIX=$(PACKDIR) ZIPINSTALL=1
+	$(MKDIR) $(DIST_DESTDIR)
+	$(DEL) $(ZIPDESTFILE)
+ifdef USEZIPWRAPPER
+ifneq ($(ECHOREDIR),echo)
+	$(ECHOREDIR) -e "$(subst \,\\,$(ZIPCMD_CDPACK))" > $(ZIPWRAPPER)
+	$(ECHOREDIR) -e "$(subst \,\\,$(ZIPCMD_ZIP))" >> $(ZIPWRAPPER)
+	$(ECHOREDIR) -e "$(subst \,\\,$(ZIPCMD_CDBASE))" >> $(ZIPWRAPPER)
+else
+	echo $(ZIPCMD_CDPACK) > $(ZIPWRAPPER)
+	echo $(ZIPCMD_ZIP) >> $(ZIPWRAPPER)
+	echo $(ZIPCMD_CDBASE) >> $(ZIPWRAPPER)
+endif
+ifdef inUnix
+	/bin/sh $(ZIPWRAPPER)
+else
+ifdef RUNBATCH
+	$(RUNBATCH) $(ZIPWRAPPER)
+else
+	$(ZIPWRAPPER)
+endif
+endif
+	$(DEL) $(ZIPWRAPPER)
+else
+	$(ZIPCMD_CDPACK) ; $(ZIPCMD_ZIP) ; $(ZIPCMD_CDBASE)
+endif
+	$(DELTREE) $(PACKDIR)
+fpc_zipsourceinstall:
+	$(MAKE) fpc_zipinstall ZIPTARGET=sourceinstall ZIPSUFFIX=$(ZIPSOURCESUFFIX)
+fpc_zipexampleinstall:
+ifdef HASEXAMPLES
+	$(MAKE) fpc_zipinstall ZIPTARGET=exampleinstall ZIPSUFFIX=$(ZIPEXAMPLESUFFIX)
+endif
+fpc_zipdistinstall:
+	$(MAKE) fpc_zipinstall ZIPTARGET=distinstall
+.PHONY: fpc_clean fpc_cleanall fpc_distclean
+ifdef EXEFILES
+override CLEANEXEFILES:=$(addprefix $(TARGETDIRPREFIX),$(CLEANEXEFILES))
+endif
+ifdef CLEAN_UNITS
+override CLEANPPUFILES+=$(addsuffix $(PPUEXT),$(CLEAN_UNITS))
+endif
+ifdef CLEANPPUFILES
+override CLEANPPULINKFILES:=$(subst $(PPUEXT),$(OEXT),$(CLEANPPUFILES)) $(addprefix $(STATICLIBPREFIX),$(subst $(PPUEXT),$(STATICLIBEXT),$(CLEANPPUFILES))) $(addprefix $(IMPORTLIBPREFIX),$(subst $(PPUEXT),$(STATICLIBEXT),$(CLEANPPUFILES)))
+ifdef DEBUGSYMEXT
+override CLEANPPULINKFILES+=$(subst $(PPUEXT),$(DEBUGSYMEXT),$(CLEANPPUFILES))
+endif
+override CLEANPPUFILES:=$(addprefix $(UNITTARGETDIRPREFIX),$(CLEANPPUFILES))
+override CLEANPPULINKFILES:=$(wildcard $(addprefix $(UNITTARGETDIRPREFIX),$(CLEANPPULINKFILES)))
+endif
+fpc_clean: $(CLEANTARGET)
+ifdef CLEANEXEFILES
+	-$(DEL) $(CLEANEXEFILES)
+endif
+ifdef CLEANPPUFILES
+	-$(DEL) $(CLEANPPUFILES)
+endif
+ifneq ($(CLEANPPULINKFILES),)
+	-$(DEL) $(CLEANPPULINKFILES)
+endif
+ifdef CLEANRSTFILES
+	-$(DEL) $(addprefix $(UNITTARGETDIRPREFIX),$(CLEANRSTFILES))
+endif
+ifdef CLEAN_FILES
+	-$(DEL) $(CLEAN_FILES)
+endif
+ifdef LIB_NAME
+	-$(DEL) $(LIB_NAME) $(LIB_FULLNAME)
+endif
+	-$(DEL) $(FPCMADE) Package.fpc $(PPAS) script.res link.res $(FPCEXTFILE) $(REDIRFILE)
+	-$(DEL) *$(ASMEXT) *_ppas$(BATCHEXT)
+fpc_cleanall: $(CLEANTARGET)
+ifdef CLEANEXEFILES
+	-$(DEL) $(CLEANEXEFILES)
+endif
+ifdef COMPILER_UNITTARGETDIR
+ifdef CLEANPPUFILES
+	-$(DEL) $(CLEANPPUFILES)
+endif
+ifneq ($(CLEANPPULINKFILES),)
+	-$(DEL) $(CLEANPPULINKFILES)
+endif
+ifdef CLEANRSTFILES
+	-$(DEL) $(addprefix $(UNITTARGETDIRPREFIX),$(CLEANRSTFILES))
+endif
+endif
+	-$(DELTREE) units
+	-$(DEL) *$(OEXT) *$(PPUEXT) *$(RSTEXT) *$(ASMEXT) *$(STATICLIBEXT) *$(SHAREDLIBEXT) *$(PPLEXT)
+ifneq ($(PPUEXT),.ppu)
+	-$(DEL) *.o *.ppu *.a
+endif
+	-$(DELTREE) *$(SMARTEXT)
+	-$(DEL) fpcmade.* Package.fpc $(PPAS) script.res link.res $(FPCEXTFILE) $(REDIRFILE)
+	-$(DEL) *_ppas$(BATCHEXT)
+ifdef AOUTEXT
+	-$(DEL) *$(AOUTEXT)
+endif
+ifdef DEBUGSYMEXT
+	-$(DEL) *$(DEBUGSYMEXT)
+endif
+fpc_distclean: cleanall
+.PHONY: fpc_baseinfo
+override INFORULES+=fpc_baseinfo
+fpc_baseinfo:
+	@$(ECHO)
+	@$(ECHO)  == Package info ==
+	@$(ECHO)  Package Name..... $(PACKAGE_NAME)
+	@$(ECHO)  Package Version.. $(PACKAGE_VERSION)
+	@$(ECHO)
+	@$(ECHO)  == Configuration info ==
+	@$(ECHO)
+	@$(ECHO)  FPC.......... $(FPC)
+	@$(ECHO)  FPC Version.. $(FPC_VERSION)
+	@$(ECHO)  Source CPU... $(CPU_SOURCE)
+	@$(ECHO)  Target CPU... $(CPU_TARGET)
+	@$(ECHO)  Source OS.... $(OS_SOURCE)
+	@$(ECHO)  Target OS.... $(OS_TARGET)
+	@$(ECHO)  Full Source.. $(FULL_SOURCE)
+	@$(ECHO)  Full Target.. $(FULL_TARGET)
+	@$(ECHO)  SourceSuffix. $(SOURCESUFFIX)
+	@$(ECHO)  TargetSuffix. $(TARGETSUFFIX)
+	@$(ECHO)
+	@$(ECHO)  == Directory info ==
+	@$(ECHO)
+	@$(ECHO)  Required pkgs... $(REQUIRE_PACKAGES)
+	@$(ECHO)
+	@$(ECHO)  Basedir......... $(BASEDIR)
+	@$(ECHO)  FPCDir.......... $(FPCDIR)
+	@$(ECHO)  CrossBinDir..... $(CROSSBINDIR)
+	@$(ECHO)  UnitsDir........ $(UNITSDIR)
+	@$(ECHO)  PackagesDir..... $(PACKAGESDIR)
+	@$(ECHO)
+	@$(ECHO)  GCC library..... $(GCCLIBDIR)
+	@$(ECHO)  Other library... $(OTHERLIBDIR)
+	@$(ECHO)
+	@$(ECHO)  == Tools info ==
+	@$(ECHO)
+	@$(ECHO)  As........ $(AS)
+	@$(ECHO)  Ld........ $(LD)
+	@$(ECHO)  Ar........ $(AR)
+	@$(ECHO)  Rc........ $(RC)
+	@$(ECHO)
+	@$(ECHO)  Mv........ $(MVPROG)
+	@$(ECHO)  Cp........ $(CPPROG)
+	@$(ECHO)  Rm........ $(RMPROG)
+	@$(ECHO)  GInstall.. $(GINSTALL)
+	@$(ECHO)  Echo...... $(ECHO)
+	@$(ECHO)  Shell..... $(SHELL)
+	@$(ECHO)  Date...... $(DATE)
+	@$(ECHO)  FPCMake... $(FPCMAKE)
+	@$(ECHO)  PPUMove... $(PPUMOVE)
+	@$(ECHO)  Upx....... $(UPXPROG)
+	@$(ECHO)  Zip....... $(ZIPPROG)
+	@$(ECHO)
+	@$(ECHO)  == Object info ==
+	@$(ECHO)
+	@$(ECHO)  Target Loaders........ $(TARGET_LOADERS)
+	@$(ECHO)  Target Units.......... $(TARGET_UNITS)
+	@$(ECHO)  Target Implicit Units. $(TARGET_IMPLICITUNITS)
+	@$(ECHO)  Target Programs....... $(TARGET_PROGRAMS)
+	@$(ECHO)  Target Dirs........... $(TARGET_DIRS)
+	@$(ECHO)  Target Examples....... $(TARGET_EXAMPLES)
+	@$(ECHO)  Target ExampleDirs.... $(TARGET_EXAMPLEDIRS)
+	@$(ECHO)
+	@$(ECHO)  Clean Units......... $(CLEAN_UNITS)
+	@$(ECHO)  Clean Files......... $(CLEAN_FILES)
+	@$(ECHO)
+	@$(ECHO)  Install Units....... $(INSTALL_UNITS)
+	@$(ECHO)  Install Files....... $(INSTALL_FILES)
+	@$(ECHO)
+	@$(ECHO)  == Install info ==
+	@$(ECHO)
+	@$(ECHO)  DateStr.............. $(DATESTR)
+	@$(ECHO)  ZipName.............. $(ZIPNAME)
+	@$(ECHO)  ZipPrefix............ $(ZIPPREFIX)
+	@$(ECHO)  ZipCrossPrefix....... $(ZIPCROSSPREFIX)
+	@$(ECHO)  ZipSuffix............ $(ZIPSUFFIX)
+	@$(ECHO)  FullZipName.......... $(FULLZIPNAME)
+	@$(ECHO)  Install FPC Package.. $(INSTALL_FPCPACKAGE)
+	@$(ECHO)
+	@$(ECHO)  Install base dir..... $(INSTALL_BASEDIR)
+	@$(ECHO)  Install binary dir... $(INSTALL_BINDIR)
+	@$(ECHO)  Install library dir.. $(INSTALL_LIBDIR)
+	@$(ECHO)  Install units dir.... $(INSTALL_UNITDIR)
+	@$(ECHO)  Install source dir... $(INSTALL_SOURCEDIR)
+	@$(ECHO)  Install doc dir...... $(INSTALL_DOCDIR)
+	@$(ECHO)  Install example dir.. $(INSTALL_EXAMPLEDIR)
+	@$(ECHO)  Install data dir..... $(INSTALL_DATADIR)
+	@$(ECHO)
+	@$(ECHO)  Dist destination dir. $(DIST_DESTDIR)
+	@$(ECHO)  Dist zip name........ $(DIST_ZIPNAME)
+	@$(ECHO)
+.PHONY: fpc_info
+fpc_info: $(INFORULES)
+.PHONY: fpc_makefile fpc_makefiles fpc_makefile_sub1 fpc_makefile_sub2 \
+	fpc_makefile_dirs
+fpc_makefile:
+	$(FPCMAKE) -w -T$(OS_TARGET) Makefile.fpc
+fpc_makefile_sub1:
+ifdef TARGET_DIRS
+	$(FPCMAKE) -w -T$(OS_TARGET) $(addsuffix /Makefile.fpc,$(TARGET_DIRS))
+endif
+ifdef TARGET_EXAMPLEDIRS
+	$(FPCMAKE) -w -T$(OS_TARGET) $(addsuffix /Makefile.fpc,$(TARGET_EXAMPLEDIRS))
+endif
+fpc_makefile_sub2: $(addsuffix _makefile_dirs,$(TARGET_DIRS) $(TARGET_EXAMPLEDIRS))
+fpc_makefile_dirs: fpc_makefile_sub1 fpc_makefile_sub2
+fpc_makefiles: fpc_makefile fpc_makefile_dirs
+all: fpc_all
+debug: fpc_debug
+smart: fpc_smart
+release: fpc_release
+units: fpc_units
+examples:
+shared: fpc_shared
+install: fpc_install
+sourceinstall: fpc_sourceinstall
+exampleinstall: fpc_exampleinstall
+distinstall: fpc_distinstall
+zipinstall: fpc_zipinstall
+zipsourceinstall: fpc_zipsourceinstall
+zipexampleinstall: fpc_zipexampleinstall
+zipdistinstall: fpc_zipdistinstall
+clean: fpc_clean
+distclean: fpc_distclean
+cleanall: fpc_cleanall
+info: fpc_info
+makefiles: fpc_makefiles
+.PHONY: all debug smart release units examples shared install sourceinstall exampleinstall distinstall zipinstall zipsourceinstall zipexampleinstall zipdistinstall clean distclean cleanall info makefiles
+ifneq ($(wildcard fpcmake.loc),)
+include fpcmake.loc
+endif
+.NOTPARALLEL:

+ 26 - 0
packages/fcl-js/Makefile.fpc

@@ -0,0 +1,26 @@
+#
+#   Makefile.fpc for Javascript Parser
+#
+
+[package]
+name=fcl-js
+version=2.5.1
+
+[target]
+units=jsbase jstree jsscanner jsparser
+
+[install]
+fpcpackage=y
+
+[default]
+fpcdir=../..
+
+[compiler]
+includedir=src
+sourcedir=src
+
+[shared]
+build=n
+
+[rules]
+.NOTPARALLEL:

+ 23 - 0
packages/fcl-js/README.TXT

@@ -0,0 +1,23 @@
+This is a package that contains a Javascript Scanner/parser/Syntax tree.
+
+The following units are defined:
+
+jsbase: the definition of Javascript values. Used to represent constant values.
+jstree: The Javascript syntax tree elements. Used in the parser to describe a source program
+jsscanner: the Javascript scanner. Currently not yet unicode-enabled.
+jsparser: the Javascript parser. Builds a complete javascript syntax tree.
+
+The tests directory contains a set of FPCUnit tests to test the scanner and parser.
+It needs Lazarus to run.
+
+Todo:
+- Add more tests.
+- Unicode support.
+- Runtime-engine ?
+
+The idea for the tree elements and the parser come from the Libsee library,
+written by David Leonard.
+
+Enjoy!
+
+Michael.

+ 37 - 0
packages/fcl-js/fpmake.pp

@@ -0,0 +1,37 @@
+{$ifndef ALLPACKAGES}
+{$mode objfpc}{$H+}
+program fpmake;
+
+uses fpmkunit;
+
+Var
+  P : TPackage;
+  T : TTarget;
+begin
+  With Installer do
+    begin
+{$endif ALLPACKAGES}
+
+    P:=AddPackage('fcl-js');
+{$ifdef ALLPACKAGES}
+    P.Directory:='fcl-js';
+{$endif ALLPACKAGES}
+    P.Version:='1.0';
+    P.Author := 'Michael Van Canneyt';
+    P.License := 'LGPL with FPC modification';
+    P.HomepageURL := 'www.freepascal.org';
+    P.Email := '[email protected]';
+    P.Description := 'Javascript scanner/parser/syntax tree units';
+
+    P.SourcePath.Add('src');
+    P.IncludePath.Add('src');
+
+    T:=P.Targets.AddUnit('jsbase.pp');
+    T:=P.Targets.AddUnit('jstree.pp');
+    T:=P.Targets.AddUnit('jsscanner.pp');
+    T:=P.Targets.AddUnit('jsparser.pp');
+{$ifndef ALLPACKAGES}
+    Run;
+    end;
+end.
+{$endif ALLPACKAGES}

+ 175 - 0
packages/fcl-js/src/jsbase.pp

@@ -0,0 +1,175 @@
+unit jsbase;
+
+{$mode objfpc}{$H+}
+
+interface
+
+uses
+  Classes, SysUtils;
+
+Type
+  TJSType = (jstUNDEFINED,jstNull,jstBoolean,jstNumber,jstString,jstObject,jstReference,JSTCompletion);
+
+  TJSString = WideString;
+  TJSNumber = Double;
+
+  { TJSValue }
+
+  TJSValue = Class(TObject)
+  private
+    FValueType: TJSType;
+    FValue : Record
+      Case Integer of
+      0 : (P : Pointer);
+      1 : (F : TJSNumber);
+      2 : (I : Integer);
+    end;
+    procedure ClearValue(ANewValue: TJSType);
+    function GetAsBoolean: Boolean;
+    function GetAsCompletion: TObject;
+    function GetAsNumber: TJSNumber;
+    function GetAsObject: TObject;
+    function GetAsReference: TObject;
+    function GetAsString: TJSString;
+    function GetIsNull: Boolean;
+    function GetIsUndefined: Boolean;
+    procedure SetAsBoolean(const AValue: Boolean);
+    procedure SetAsCompletion(const AValue: TObject);
+    procedure SetAsNumber(const AValue: TJSNumber);
+    procedure SetAsObject(const AValue: TObject);
+    procedure SetAsReference(const AValue: TObject);
+    procedure SetAsString(const AValue: TJSString);
+    procedure SetIsNull(const AValue: Boolean);
+    procedure SetIsUndefined(const AValue: Boolean);
+  Public
+    Destructor Destroy; override;
+    Property ValueType : TJSType Read FValueType;
+    Property IsUndefined : Boolean Read GetIsUndefined Write SetIsUndefined;
+    Property IsNull : Boolean Read GetIsNull Write SetIsNull;
+    Property AsNumber : TJSNumber Read GetAsNumber Write SetAsNumber;
+    Property AsBoolean : Boolean Read GetAsBoolean Write SetAsBoolean;
+    Property AsObject : TObject Read GetAsObject Write SetAsObject;
+    Property AsString : TJSString Read GetAsString Write SetAsString;
+    Property AsReference : TObject Read GetAsReference Write SetAsReference;
+    Property AsCompletion : TObject Read GetAsCompletion Write SetAsCompletion;
+  end;
+
+implementation
+
+{ TJSValue }
+
+
+function TJSValue.GetAsBoolean: Boolean;
+begin
+  If (ValueType=jstBoolean) then
+    Result:=(FValue.I<>0)
+  else
+    Result:=False;
+end;
+
+function TJSValue.GetAsCompletion: TObject;
+begin
+  Result:=TObject(FValue.P);
+end;
+
+function TJSValue.GetAsNumber: TJSNumber;
+begin
+  If (ValueType=jstNumber) then
+    Result:=FValue.F;
+end;
+
+function TJSValue.GetAsObject: TObject;
+begin
+  If (ValueType=jstObject) then
+    Result:=TObject(FValue.P);
+end;
+
+function TJSValue.GetAsReference: TObject;
+begin
+  If (ValueType=jstReference) then
+    Result:=TObject(FValue.P);
+end;
+
+function TJSValue.GetAsString: TJSString;
+begin
+  If (ValueType=jstString) then
+    Result:=String(FValue.P);
+end;
+
+function TJSValue.GetIsNull: Boolean;
+begin
+  Result:=(ValueType=jstNull);
+end;
+
+function TJSValue.GetIsUndefined: Boolean;
+begin
+  Result:=(fValueType=jstUndefined);
+end;
+
+procedure TJSValue.ClearValue(ANewValue : TJSType);
+
+begin
+  Case FValueType of
+    jstString : String(FValue.P):='';
+    jstNumber : FValue.F:=0;
+  else
+    FValue.I:=0;
+  end;
+  FValueType:=ANewValue;
+end;
+
+procedure TJSValue.SetAsBoolean(const AValue: Boolean);
+begin
+  ClearValue(jstBoolean);
+  FValue.I:=Ord(AValue);
+end;
+
+procedure TJSValue.SetAsCompletion(const AValue: TObject);
+begin
+  ClearValue(jstBoolean);
+  FValue.P:=AValue;
+end;
+
+procedure TJSValue.SetAsNumber(const AValue: TJSNumber);
+begin
+  ClearValue(jstNumber);
+  FValue.F:=AValue;
+end;
+
+procedure TJSValue.SetAsObject(const AValue: TObject);
+begin
+  ClearValue(jstObject);
+  FValue.P:=AVAlue;
+end;
+
+procedure TJSValue.SetAsReference(const AValue: TObject);
+begin
+  ClearValue(jstReference);
+  FValue.P:=AVAlue;
+end;
+
+procedure TJSValue.SetAsString(const AValue: TJSString);
+begin
+  ClearValue(jstString);
+  String(FValue.P):=AValue;
+end;
+
+procedure TJSValue.SetIsNull(const AValue: Boolean);
+begin
+  ClearValue(jstNull);
+end;
+
+procedure TJSValue.SetIsUndefined(const AValue: Boolean);
+begin
+  ClearValue(jstUndefined);
+end;
+
+destructor TJSValue.Destroy;
+begin
+  ClearValue(jstUndefined);
+  inherited Destroy;
+end;
+
+
+end.
+

+ 2100 - 0
packages/fcl-js/src/jsparser.pp

@@ -0,0 +1,2100 @@
+unit jsparser;
+
+{$define debugparser}
+{$mode objfpc}{$H+}
+
+interface
+
+uses
+  Classes, SysUtils, jsscanner, jstree;
+
+Const
+   SEmptyLabel = '';
+
+Type
+
+
+  { TJSLabelSet }
+
+  TJSLabelSet = Class(TObject)
+  private
+    FCOnt: Boolean;
+    FNext: TJSLabelSet;
+    FTarget: Cardinal;
+  Public
+    Property Target : Cardinal Read FTarget Write FTarget;
+    Property Next : TJSLabelSet Read FNext Write FNext; // Linked list
+    Property Continuable : Boolean Read FCOnt Write FCont;
+  end;
+
+  { TJSLabel }
+
+  TJSLabel = Class(TObject)
+  private
+    FLabelSet: TJSLabelSet;
+    FLocationLine: Integer;
+    FLocationPos: Integer;
+    FLocationSource: String;
+    FName: String;
+    FNext: TJSLabel;
+  Public
+    Property Name : String Read FName Write FName;
+    Property LabelSet : TJSLabelSet Read FLabelSet Write FLabelSet;
+    Property LocationSource : String Read FLocationSource Write FLocationSource;
+    Property LocationLine : Integer Read FLocationLine Write FLocationLine;
+    Property LocationPos : Integer Read FLocationPos Write FLocationPos;
+    Property Next : TJSLabel Read FNext Write FNext;
+  end;
+
+  { TJSParser }
+
+  TJSParser = Class(TObject)
+  Private
+    FFunctionDepth: Integer;
+    FInput : TStream;
+    FIsLHS: Boolean;
+    FNoIn: Boolean;
+    FScanner : TJSScanner;
+    FCurrent : TJSToken;
+    FCurrentString : String;
+    FNextNewLine : Boolean;
+    FNextBol : Boolean;
+    FFreeScanner : Boolean;
+    FCurrentVars : TJSElementNodes;
+    FPeekToken: TJSToken;
+    FPeekTokenString: String;
+    FLabelSets,
+    FCurrentLabelSet:TJSLabelSet;
+    FLabels : TJSLabel;
+    function EnterLabel(ALabelName: String): TJSLabel;
+    procedure Expect(aToken: TJSToken);
+    procedure Consume(aToken: TJSToken);
+    procedure FreeCurrentLabelSet;
+    procedure LeaveLabel;
+    function LookupLabel(ALabelName: String; Kind: TJSToken): TJSLabel;
+    function ParseAdditiveExpression: TJSElement;
+    function ParseArguments: TJSarguments;
+    function ParseArrayLiteral: TJSElement;
+    function ParseAssignmentExpression: TJSElement;
+    function ParseBitwiseAndExpression: TJSElement;
+    function ParseBitwiseORExpression: TJSElement;
+    function ParseBitwiseXORExpression: TJSElement;
+    function ParseBlock: TJSElement;
+    function ParseBreakStatement: TJSElement;
+    function ParseConditionalExpression: TJSElement;
+    function ParseContinueStatement: TJSElement;
+    function ParseEmptyStatement: TJSElement;
+    function ParseEqualityExpression: TJSElement;
+    function ParseExpression: TJSElement;
+    function ParseExpressionStatement: TJSElement;
+    function ParseFormalParameterList: TStrings;
+    function ParseFunctionDeclaration: TJSFunctionDeclarationStatement;
+    function ParseFunctionExpression: TJSFunctionDeclarationStatement;
+    function ParseFunctionStatement: TJSElement;
+    function ParseFunctionBody: TJSFunctionBody;
+    function ParseIdentifier: String;
+    function ParseIfStatement: TJSElement;
+    function ParseIterationStatement: TJSElement;
+    function ParseLabeledStatement: TJSElement;
+    function ParseLeftHandSideExpression: TJSElement;
+    function ParseLiteral: TJSElement;
+    function ParseLogicalAndExpression: TJSElement;
+    function ParseLogicalORExpression: TJSElement;
+    function ParseMemberExpression: TJSElement;
+    function ParseMultiplicativeExpression: TJSElement;
+    function ParseNumericLiteral: TJSElement;
+    function ParseObjectLiteral: TJSElement;
+    function ParsePostFixExpression: TJSElement;
+    function ParsePrimaryExpression: TJSElement;
+    function ParseRegularExpressionLiteral: TJSElement;
+    function ParseRelationalExpression: TJSElement;
+    function ParseReturnStatement: TJSElement;
+    function ParseShiftExpression: TJSElement;
+    function ParseStatement: TJSElement;
+    function ParseStatementList: TJSElement;
+    function ParseStringLiteral: TJSElement;
+    function ParseSwitchStatement: TJSElement;
+    function ParseThrowStatement: TJSElement;
+    function ParseTryStatement: TJSElement;
+    function ParseUnaryExpression: TJSElement;
+    function ParseVariableDeclaration: TJSElement;
+    function ParseVariableDeclarationList: TJSElement;
+    function ParseVariableStatement: TJSElement;
+    function ParseWithStatement: TJSElement;
+  Protected
+    Procedure CheckParser;
+    Function CurrentLabelSet : TJSLabelSet;
+    function CurSource: String;
+    Function CurLine : Integer;
+    Function CurPos : Integer;
+    Function CreateElement(AElementClass : TJSElementClass)  : TJSElement;
+    Procedure Error(Msg : String);
+    Procedure Error(Fmt : String; Args : Array of const);
+    // Parse functions
+    function ParseSourceElements: TJSSourceElements;
+    Property FunctionDepth : Integer Read FFunctionDepth Write FFunctionDepth;
+    Property NoIn : Boolean Read FNoIn Write FNoIn;
+    Property IsLHS : Boolean Read FIsLHS Write FIsLHS;
+  Public
+    Constructor Create(AInput: TStream);
+    Constructor Create(AScanner : TJSScanner);
+    Function Parse : TJSElement;
+    Function ParseProgram : TJSFunctionDeclarationStatement;
+    Function CurrentToken : TJSToken;
+    Function CurrentTokenString : String;
+    Function GetNextToken : TJSToken;
+    Function PeekNextToken : TJSToken;
+    Function IsEndOfLine : Boolean;
+  end;
+
+implementation
+
+uses typinfo;
+
+Resourcestring
+  SErrUnmatchedCurlyBrace    = 'Unmatched }';
+  SErrUnmatchedSquareBrace   = 'Unmatched ]';
+  SErrUnmatchedBrace         = 'Unmatched )';
+  SErrUnexpectedToken        = 'Unexpected token: ''%s''';
+  SErrTokenMismatch          = 'Unexpected token: ''%s'', expected: ''%s''';
+  SErrSemicolonOrInExpected  = 'Unexpected token: ''%s'', expected ; or ''in''';
+  SErrSemicolonExpected      = 'Unexpected token: ''%s'', expected ;';
+  SErrDuplicateLabelName     = 'Duplicate label name: ''%s''';
+  SErrLabelNotContinuable    = 'Label ''%s'' is not suitable for continue.';
+  SErrLabelNOtDefinedOrReachable = 'Label ''%s'' is not defined or not reachable.';
+  SErrContinueNotInLoop      = 'Continue statement not in loop';
+  SErrBreakNotInLoop         = 'Break statement not in loop';
+  SErrReturnNotInFunction    = 'return statement not in a function body';
+  SErrCaseEndExpected        = 'Unexpected token: Expected }, case or default clause';
+  SErrDuplicateSwitchDefault = 'Duplicate default clause for switch statement';
+  SErrNewlineAfterThrow      = 'Newline after throw not allowed';
+  SErrCatchFinallyExpected   = 'Unexpected token: Expected ''catch'' or ''finally''';
+  SErrArgumentsExpected      = 'Unexpected token: Expected '','' or '')'', got %s';
+  SErrArrayEnd               = 'Unexpected token: Expected '','' or '']'', got %s';
+  SErrObjectEnd              = 'Unexpected token: Expected '','' or ''}'', got %s';
+  SErrObjectElement          = 'Unexpected token: Expected string, identifier or number after '','' got: %s';
+  SErrLiteralExpected        = 'Unexpected token: Expected: null, true, false, number, string, or regex, got: %s';
+  SErrInvalidnumber          = 'Invalid numerical value: %s';
+  SErrInvalidRegularExpression = 'Invalid regular expression: %s';
+  SErrFunctionNotAllowedHere = 'function keyword not allowed here';
+
+{ TJSScanner }
+
+function TJSParser.CurrentToken: TJSToken;
+
+begin
+  Result:=FCurrent;
+end;
+
+function TJSParser.CurrentTokenString: String;
+begin
+  Result:=FCurrentString;
+end;
+
+function TJSParser.GetNextToken: TJSToken;
+begin
+  If (FPeekToken<>tjsunknown) then
+     begin
+     FCurrent:=FPeekToken;
+     FCurrentString:=FPeekTokenString;
+     FPeekToken:=tjsUnknown;
+     FPeekTokenString:='';
+     end
+  else
+    begin
+    FCurrent:=FScanner.FetchToken;
+    FCurrentString:=FScanner.CurTokenString;
+    end;
+  {$ifdef debugparser}Writeln('GetNextToken : ',GetEnumName(TypeInfo(TJSToken),Ord(FCurrent)), ' As string: ',FCurrentString);{$endif debugparser}
+end;
+
+function TJSParser.PeekNextToken: TJSToken;
+begin
+  If (FPeekToken=tjsUnknown) then
+    begin
+    FPeekToken:=FScanner.FetchToken;
+    FPeekTokenString:=FScanner.CurTokenString;
+    end;
+  {$ifdef debugparser}Writeln('PeekNextToken : ',GetEnumName(TypeInfo(TJSToken),Ord(FPeekToken)), ' As string: ',FPeekTokenString);{$endif debugparser}
+  Result:=FPeekToken;
+end;
+
+function TJSParser.IsEndOfLine: Boolean;
+begin
+  Result:=FScanner.IsEndOfLine;
+end;
+
+
+function TJSParser.CurPos: Integer;
+begin
+  If Assigned(FScanner) then
+    Result:=FScanner.CurColumn
+  else
+    Result:=0;
+end;
+
+function TJSParser.CurLine: Integer;
+begin
+  If Assigned(FScanner) then
+    Result:=FScanner.CurRow
+  else
+    Result:=0;
+end;
+
+function TJSParser.CurSource: String;
+begin
+  If Assigned(FScanner) then
+    Result:=FScanner.CurFileName
+  else
+    Result:='';
+end;
+
+procedure TJSParser.CheckParser;
+begin
+
+end;
+
+Procedure TJSParser.LeaveLabel;
+
+Var
+  L : TJSLabel;
+
+begin
+  L:=FLabels;
+  FLabels:=FLabels.Next;
+  L.Free; // ??
+end;
+
+function TJSParser.LookupLabel(ALabelName : String; Kind : TJSToken) :TJSLabel;
+
+Var
+  L : TJSLabel;
+
+begin
+  L:=FLabels;
+  Result:=Nil;
+  While (L<>Nil) and (Result=Nil) do
+    begin
+    If (L.Name=ALabelName) then
+      begin
+      if (kind=tjsContinue) and (Not L.LabelSet.Continuable) and (ALabelName<>SEmptyLabel) then
+        Error(SErrLabelNotContinuable,[ALabelName]);
+      Result:=L;
+      end;
+    L:=L.Next;
+    end;
+  If (Result=Nil) then
+    begin
+    If (ALabelName<>'') then
+      Error(SErrLabelNOtDefinedOrReachable,[ALabelName])
+    else if kind=tjsCOntinue then
+      Error(SErrContinueNotInLoop)
+    else
+      Error(SErrBreakNotInLoop);
+    end;
+end;
+
+function TJSParser.EnterLabel(ALabelName : String) :TJSLabel;
+
+Var
+  L : TJSLabel;
+
+begin
+  If (ALAbelName<>SEmptyLabel) then
+    begin
+    L:=FLabels;
+    While (L<>Nil) do
+      begin
+      If (L.Name=ALabelName) then
+        Error(SErrDuplicateLabelName,[ALabelName]);
+      L:=L.Next;
+      end;
+    end;
+  L:=TJSLabel.Create;
+  L.Name:=ALabelName;
+  L.LabelSet:=CurrentLabelSet;
+  L.LocationSource:=Self.CurSource;
+  L.LocationLine:=CurLine;
+  L.LocationPos:=CurPos;
+  L.Next:=FLabels;
+  FLabels:=L;
+  Result:=L;
+end;
+
+function TJSParser.CurrentLabelSet: TJSLabelSet;
+
+Var
+  LS : TJSLabelSet;
+
+begin
+  If (FCurrentLabelSet=Nil) then
+    begin
+    LS:=TJSLabelSet.Create;
+    If (FLabelSets=Nil) then
+      LS.Target:=1
+    else
+      LS.Target:=FLabelSets.Target;
+    LS.Next:=FLabelSets;
+    FLabelSets:=LS;
+    FCurrentLabelSet:=LS;
+    end;
+  Result:=FCurrentLabelSet;
+end;
+
+function TJSParser.CreateElement(AElementClass: TJSElementClass): TJSElement;
+begin
+  Result:=AElementClass.Create(CurLine,CurPos,CurSource);
+end;
+
+procedure TJSParser.Error(Msg: String);
+
+Var
+  ErrAt : String;
+
+begin
+  If Assigned(FScanner) then
+    If FScanner.CurFilename<>'' then
+      ErrAt:=Format('Error: file "%s" line %d, pos %d: ',[FScanner.CurFileName,FScanner.CurRow,FScanner.CurColumn])
+    else
+      ErrAt:=Format('Error: line %d, pos %d: ',[FScanner.Currow,FScanner.CurColumn]);
+  Raise Exception.Create(ErrAt+Msg)
+end;
+
+procedure TJSParser.Error(Fmt: String; Args: array of const);
+begin
+  Error(Format(Fmt,Args));
+end;
+
+constructor TJSParser.Create(AInput: TStream);
+begin
+  FInput:=AInput;
+  FCurrent:=TJSUnknown;
+  FScanner:=TJSScanner.Create(FInput);
+  FFreeScanner:=True;
+end;
+
+constructor TJSParser.Create(AScanner: TJSScanner);
+begin
+  FCurrent:=TJSUnknown;
+  FScanner:=AScanner;
+  FFreeScanner:=False;
+end;
+
+
+
+Procedure TJSParser.Expect(aToken : TJSToken);
+
+begin
+  {$ifdef debugparser}  Writeln('Expecting : ',GetEnumName(TypeInfo(TJSToken),Ord(AToken)), ' As string: ',TokenInfos[AToken]);{$endif debugparser}
+  If (CurrentToken<>aToken) then
+    Error(SerrTokenMismatch,[CurrenttokenString,TokenInfos[aToken]]);
+end;
+
+procedure TJSParser.Consume(aToken: TJSToken);
+begin
+  Expect(aToken);
+  GetNextToken;
+end;
+
+function TJSParser.ParseIdentifier : String;
+
+begin
+  Result:='';
+  Repeat
+    Expect(tjsIdentifier);
+    Result:=Result+CurrentTokenString;
+    GetNextToken;
+    If (CurrentToken=tjsDot) then
+      begin
+      If (Result<>'') then
+         Result:=Result+'.';
+      GetNextToken;
+      end;
+  until (CurrentToken<>tjsIdentifier);
+end;
+
+function TJSParser.ParseFormalParameterList : TStrings;
+
+begin
+  Result:=Nil;
+  While (CurrentToken=tjsIdentifier) do
+    begin
+    Expect(tjsIdentifier);
+    If (Result=Nil) then
+      Result:=TstringList.Create;
+    Result.Add(CurrentTokenString);
+    GetNextToken;
+    If (CurrentToken=tjsComma) then
+       GetNextToken;
+    end;
+end;
+
+
+function TJSParser.ParseFunctionDeclaration : TJSFunctionDeclarationStatement;
+
+Var
+  Id : String;
+  D : TJSFuncDef;
+  args : TStrings;
+  body : TJSFunctionBody;
+
+begin
+  {$ifdef debugparser}  Writeln('>>> Entering ParseFunctionDeclaration');{$endif debugparser}
+  Consume(tjsFunction);
+  ID:=ParseIdentifier;
+  Consume(tjsBraceOpen);
+  Args:=ParseFormalParameterList;
+  try
+    Consume(tjsBraceClose);
+    Consume(tjsCurlyBraceOpen);
+    Inc(FFunctionDepth);
+    try
+      Body:=ParseFunctionBody;
+      try
+        // GetNextToken; not sure
+        Consume(tjsCurlyBraceClose);
+        D:=TJSFuncDef.Create;
+        try
+          D.Name:=ID;
+          If Assigned(Args)then
+            D.Params.Assign(Args);
+          D.Body:=Body;
+          Result:=TJSFunctionDeclarationStatement(CreateElement(TJSFunctionDeclarationStatement));
+          Result.AFunction:=D;
+        except
+          FreeAndNil(D);
+          Raise;
+        end;
+      except
+        FreeAndNil(Body);
+        Raise;
+      end;
+    finally
+      Dec(FFunctionDepth);
+    end;
+  finally
+    FreeAndNil(Args);
+  end;
+  {$ifdef debugparser}  Writeln('>>> Exiting ParseFunctionDeclaration');{$endif debugparser}
+end;
+
+function TJSParser.ParseStatementList : TJSElement;
+
+Var
+  E : TJSElement;
+  SL : TJSSTatementList;
+
+begin
+  {$ifdef debugparser}  Writeln('>>> ParseStatementList');{$endif debugparser}
+  E:=ParseStatement;
+  try
+    if (CurrentToken in [tjsCurlyBraceClose,tjsEof,tjsCase,tjsDefault]) then
+      Result:=E
+    else
+      begin
+      SL:=TJSSTatementList(CreateElement(TJSStatementList));
+      try
+        SL.A:=E;
+        SL.B:=ParseStatementlist;
+        Result:=SL;
+      except
+        FreeAndNil(SL);
+        Raise;
+      end;
+      end;
+  except
+    FreeAndNil(E);
+    Raise;
+  end;
+  {$ifdef debugparser}  Writeln('<<< ParseStatementList');{$endif debugparser}
+end;
+
+function TJSParser.ParseBlock : TJSElement;
+
+begin
+  {$ifdef debugparser}  Writeln('>>> ParseBlock');{$endif debugparser}
+  Consume(tjsCurlyBraceOpen);
+  If (CurrentToken=tjsCurlyBraceClose) then
+    Result:=CreateElement(TJSEmptyBlockStatement)
+  else
+    result:=ParseStatementList;
+  Consume(tjsCurlyBraceClose);
+  {$ifdef debugparser}  Writeln('<<< ParseBlock');{$endif debugparser}
+end;
+
+Function TJSParser.ParseArrayLiteral : TJSElement;
+
+Var
+  N : TJSArrayLiteral;
+  E : TJSArrayLiteralElement;
+  I : Integer;
+
+begin
+  Consume(tjsSquaredBraceOpen);
+  N:=TJSArrayLiteral(CreateElement(TJSArrayLiteral));
+  Result:=N;
+  try
+    I:=0;
+    While (CurrentToken<>tjsSquaredBraceClose) do
+      begin
+      If (CurrentToken=tjsComma) then
+         begin
+         GetNextToken;
+         Inc(I);
+         end
+      else
+         begin
+         E:=N.Elements.AddElement;
+         E.Index:=I;
+         Inc(I);
+         E.Expr:=ParseAssignmentExpression;
+         If Not (CurrentToken in [tjsComma,tjsSquaredBraceClose]) then
+           Error(SErrArrayEnd,[CurrentTokenString])
+         end;
+      end;
+    Consume(tjsSquaredBraceClose);
+  except
+    FreeAndNil(Result);
+    Raise;
+  end;
+end;
+
+Function TJSParser.ParseObjectLiteral : TJSElement;
+
+Var
+  N : TJSObjectLiteral;
+  E : TJSObjectLiteralElement;
+  I : Integer;
+
+begin
+  Consume(tjsCurlyBraceOpen);
+  N:=TJSObjectLiteral(CreateElement(TJSObjectLiteral));
+  Result:=N;
+  try
+    While (CurrentToken<>tjsCurlyBraceClose) do
+      begin
+      If (CurrentToken in [tjsIdentifier,jsscanner.tjsString,tjsnumber]) then
+         begin
+         E:=N.Elements.AddElement;
+         E.Name:=CurrenttokenString;
+         GetNextToken;
+         end
+      else
+         Error(SErrObjectElement,[CurrentTokenString]);
+      Consume(tjsColon);
+      E.Expr:=ParseAssignmentExpression;
+      If Not (CurrentToken in [tjsComma,tjsCurlyBraceClose]) then
+        Error(SErrObjectEnd,[CurrentTokenString])
+      end;
+    Consume(tjsCurlyBraceClose);
+  except
+    FreeAndNil(Result);
+    Raise;
+  end;
+end;
+
+Function TJSParser.ParseNumericLiteral : TJSElement;
+
+Var
+  L : TJSLiteral;
+  D : Double;
+  I : Integer;
+
+begin
+  {$ifdef debugparser}  Writeln('Parsing numerical literal');{$endif debugparser}
+  Result:=Nil;
+  try
+    Val(CurrentTokenString,D,I);
+    If (I>0) then
+      Error(SErrInvalidnumber,[CurrentTokenString]);
+    L:=TJSLiteral(CreateElement(TJSLiteral));
+    GetNextToken;
+    L.Value.AsNumber:=D;
+    Result:=L;
+  except
+    FreeAndNil(Result);
+    Raise;
+  end;
+end;
+
+Function TJSParser.ParseStringLiteral : TJSElement;
+
+Var
+  L : TJSLiteral;
+  D : Double;
+  I : Integer;
+
+begin
+    {$ifdef debugparser} Writeln('Parsing string literal');{$endif debugparser}
+  Result:=Nil;
+  try
+    L:=TJSLiteral(CreateElement(TJSLiteral));
+    L.Value.AsString:=CurrentTokenString;
+    GetNextToken;
+    Result:=L;
+  except
+    FreeAndNil(Result);
+    Raise;
+  end;
+end;
+
+Function TJSParser.ParseRegularExpressionLiteral : TJSElement;
+
+Var
+  S,pa,fl : String;
+  P : integer;
+  R : TJSRegularExpressionLiteral;
+begin
+  Result:=Nil;
+  If (CurrentToken=tjsRegex) then
+    begin
+    S:=CurrentTokenString;
+    P:=Length(S);
+    While (P>=1) and (S[P]<>'/') do
+      Dec(P);
+    If (P<=1) then
+      Error(SErrInvalidRegularExpression,[CurrentTokenString]);
+    pa:=Copy(S,2,P-1);
+    fl:=Copy(S,P,Length(S)-P+1);
+    R:=TJSRegularExpressionLiteral(CreateElement(TJSRegularExpressionLiteral));
+    Result:=R;
+    R.Pattern.AsString:=Pa;
+    R.PatternFlags.AsString:=Fl;
+    R.Argv[0]:=R.Pattern;
+    R.Argv[1]:=R.PatternFlags;
+    end;
+  try
+    Consume(tjsRegEx);
+  except
+    FreeAndNil(Result);
+    Raise;
+  end;
+end;
+
+Function TJSParser.ParseLiteral : TJSElement;
+
+Var
+  L : TJSLiteral;
+
+begin
+  {$ifdef debugparser}Writeln('Parsing literal: ',GetEnumName(TypeInfo(TJSToken),Ord(CurrentToken)), ' As string: ',CurrentTokenString);{$endif debugparser}
+  Result:=Nil;
+  Case CurrentToken of
+    tjsNull : begin
+              L:=TJSLiteral(CreateElement(TJSLiteral));
+              Result:=L;
+              L.Value.IsNull:=True;
+              GetNextToken;
+              end;
+    tjsTrue,
+    tjsFalse: begin
+              L:=TJSLiteral(CreateElement(TJSLiteral));
+              Result:=L;
+              L.Value.AsBoolean:=(CurrentToken=tjsTrue);
+              GetNextToken;
+              end;
+    tjsNumber : Result:=ParseNumericLiteral;
+    jsscanner.tjsString : Result:=ParseStringLiteral;
+    tjsDiv,
+    tjsDivEq : Result:=ParseRegularExpressionLiteral
+  else
+    Error(SErrLiteralExpected,[CurrentTokenString]);
+  end;
+end;
+
+Function TJSParser.ParsePrimaryExpression : TJSElement;
+
+Var
+  R : TJSPrimaryExpressionIdent;
+
+begin
+  Result:=Nil;
+  try
+    Case CurrentToken of
+      tjsThis :
+        begin
+        Result:=TJSPrimaryExpressionThis(CreateElement(TJSPrimaryExpressionThis));
+        GetNextToken;
+        end;
+      tjsidentifier:
+        begin
+        R:=TJSPrimaryExpressionIdent(CreateElement(TJSPrimaryExpressionIdent));
+        Result:=R;
+        R.AString:=CurrentTokenString;
+        GetNextToken;
+        end;
+      tjsSquaredBraceOpen: Result:=ParseArrayLiteral;
+      tjsCurlyBraceOpen: Result:=ParseObjectLiteral;
+      tjsBraceOpen:
+        begin
+        Writeln('Found brace !!');
+        Consume(tjsBraceOpen);
+        Result:=ParseExpression;
+        Consume(tjsBraceClose);
+        end;
+    else
+      Result:=ParseLiteral;
+    end; // Case;
+  except
+    FreeAndNil(Result);
+    Raise;
+  end;
+end;
+
+
+Function TJSParser.ParseMemberExpression : TJSElement;
+
+Var
+  M  : TJSDotMemberExpression;
+  B  : TJSBracketMemberExpression;
+  C : TJSCallExpression;
+  Done : Boolean;
+
+begin
+  Case CurrentToken of
+    tjsFunction : Result:=ParseFunctionExpression;
+    tjsNew      : Result:=ParseMemberExpression;
+  else
+    Result:=ParsePrimaryExpression
+  end;
+  try
+    Done:=False;
+    Repeat
+      Case CurrentToken of
+       tjsDot :
+         begin
+         M:=TJSDotMemberExpression(CreateElement(TJSDotMemberExpression));
+         M.MExpr:=Result;
+         Result:=M;
+         GetNextToken;
+         If (CurrentToken=tjsIdentifier) then
+           M.Name:=CurrentTokenString;
+         Consume(tjsIdentifier);
+         end;
+       tjsSquaredBraceOpen:
+         begin
+         B:=TJSBracketMemberExpression(CreateElement(TJSBracketMemberExpression));
+         B.MExpr:=Result;
+         Result:=B;
+         GetNextToken;
+         B.Name:=ParseExpression;
+         Consume(tjsSquaredBraceClose);
+         end;
+      else
+        Done:=True;
+        isLHS:=True;
+      end;
+    Until Done;
+  except
+    FreeAndNil(Result);
+    Raise;
+  end;
+end;
+
+Function TJSParser.ParseArguments : TJSarguments;
+
+Var
+  E : TJSArrayLiteralElement;
+
+begin
+  Consume(tjsBraceOpen);
+  Result:=TJSArguments(CreateElement(TJSArguments));
+  try
+    While (CurrentToken<>tjsBraceClose) do
+      begin
+      E:=Result.Elements.AddElement;
+      E.Expr:=ParseAssignmentExpression;
+      If (CurrentToken<>tjsBraceClose) then
+        If CurrentToken=tjsComma then
+          GetNextToken
+        else
+          Error(SErrArgumentsExpected,[CurrentTokenString]);
+      end;
+    Consume(tjsBraceClose);
+  except
+    FreeAndNil(Result);
+    Raise;
+  end;
+end;
+
+Function TJSParser.ParseLeftHandSideExpression : TJSElement;
+
+Var
+  M  : TJSDotMemberExpression;
+  B  : TJSBracketMemberExpression;
+  C : TJSCallExpression;
+  Done : Boolean;
+
+begin
+  Case CurrentToken of
+    tjsFunction : Result:=ParseFunctionExpression;
+    tjsNew      : Result:=ParseMemberExpression;
+  else
+    Result:=ParsePrimaryExpression
+  end;
+  try
+    Done:=False;
+    Repeat
+      Case CurrentToken of
+       tjsDot :
+         begin
+         M:=TJSDotMemberExpression(CreateElement(TJSDotMemberExpression));
+         M.MExpr:=Result;
+         Result:=M;
+         GetNextToken;
+         If (CurrentToken=tjsIdentifier) then
+           M.Name:=CurrentTokenString;
+         Consume(tjsIdentifier);
+         end;
+       tjsSquaredBraceOpen:
+         begin
+         B:=TJSBracketMemberExpression(CreateElement(TJSBracketMemberExpression));
+         B.MExpr:=Result;
+         Result:=B;
+         GetNextToken;
+         B.Name:=ParseExpression;
+         Consume(tjsSquaredBraceClose);
+         end;
+       tjsBraceOpen:
+         begin
+         Writeln('Call expression !!');
+         C:=TJSCallExpression(CreateElement(TJSCallExpression));
+         C.Expr:=Result;
+         Result:=C;
+         C.Args:=ParseArguments;
+         end;
+      else
+        {$ifdef debugparser}Writeln('Leaving LHS');{$endif debugparser}
+        Done:=True;
+        isLHS:=True;
+      end;
+    Until Done;
+  except
+    FreeAndNil(Result);
+    Raise;
+  end;
+end;
+
+Function TJSParser.ParsePostFixExpression : TJSElement;
+Var
+  R : TJSUnaryExpression;
+
+begin
+  {$ifdef debugparser}  Writeln('ParsePostfixExpression');{$endif debugparser}
+  Result:=ParseLeftHandSideExpression;
+  Try
+  If (Not IsEndOfLine) and (CurrentToken in [tjsPlusPlus,tjsMinusMinus]) then
+    begin
+    If (CurrentToken=tjsPlusPLus) then
+      R:=TJSUnaryExpression(CreateElement(TJSUnaryPostPlusPlusExpression))
+    else
+      R:=TJSUnaryExpression(CreateElement(TJSUnaryPostMinusMinusExpression));
+    R.A:=Result;
+    Result:=R;
+    GetNextToken;
+    isLHS:=False;
+    end;
+  except
+    freeAndNil(Result);
+    Raise;
+  end;
+end;
+
+Function TJSParser.ParseUnaryExpression : TJSElement;
+
+Var
+  C : TJSElementClass;
+  R : TJSUnaryExpression;
+
+begin
+  {$ifdef debugparser} Writeln('ParseUnaryExpression');{$endif debugparser}
+  C:=Nil;
+  Result:=Nil;
+  try
+    Case CurrentToken of
+      tjsDelete     : C:=TJSUnaryDeleteExpression;
+      tjsVoid       : C:=TJSUnaryVoidExpression;
+      tjsTypeOf     : C:=TJSUnaryTypeOfExpression;
+      tjsPlusPlus   : C:=TJSUnaryPrePlusPlusExpression;
+      tjsMinusMinus : C:=TJSUnaryPreMinusMinusExpression;
+      tjsPlus       : C:=TJSUnaryPlusExpression;
+      tjsMinus      : C:=TJSUnaryMinusExpression;
+      tjsInv        : C:=TJSUnaryInvExpression;
+      tjsNot        : C:=TJSUnaryNotExpression;
+    else
+      Result:=ParsePostFixExpression;
+    end;
+    If (Result=Nil) then
+      begin
+      {$ifdef debugparser} Writeln('Found Unary Expression',GetEnumName(TypeInfo(TJSToken),Ord(CurrentToken)), ' As string: ',CurrentTokenString);{$endif debugparser}
+      R:=TJSUnaryExpression(CreateElement(C));
+      Result:=R;
+      GetNextToken;
+      R.A:=Self.ParseUnaryExpression;
+      isLHS:=False;
+      end;
+  except
+    FreeAndNil(Result);
+    Raise;
+  end;
+end;
+
+Function TJSParser.ParseMultiplicativeExpression : TJSElement;
+
+Var
+  C : TJSElementClass;
+  R : TJSMultiplicativeExpression;
+
+begin
+  {$ifdef debugparser}  Writeln('ParseMultiplicativeExpression');{$endif debugparser}
+  Result:=ParseUnaryExpression;
+  try
+    While (CurrentToken in [tjsMul,tjsDiv,tjsMod]) do
+      begin
+      if CurrentToken=tjsMul then
+        C:=TJSMultiplicativeExpressionMul
+      else if CurrentToken=tjsDiv then
+        C:=TJSMultiplicativeExpressionDiv
+      else
+        C:=TJSMultiplicativeExpressionMod;
+      R:=TJSMultiplicativeExpression(CreateElement(C));
+      GetNextToken;
+      R.A:=Result;
+      Result:=R;
+      R.B:=ParseUnaryExpression;
+      isLHS:=False;
+      end;
+  except
+    FreeAndNil(Result);
+    Raise;
+  end;
+end;
+
+Function TJSParser.ParseAdditiveExpression : TJSElement;
+
+Var
+  C : TJSElementClass;
+  R : TJSAdditiveExpression;
+
+begin
+  {$ifdef debugparser}  Writeln('ParseAdditiveExpression');{$endif debugparser}
+  Result:=ParseMultiplicativeExpression;
+  try
+    While (CurrentToken in [tjsPlus,tjsMinus]) do
+      begin
+      if CurrentToken=tjsPlus then
+        C:=TJSAdditiveExpressionPlus
+      else
+        C:=TJSAdditiveExpressionMinus;
+      R:=TJSAdditiveExpression(CreateElement(C));
+      GetNextToken;
+      R.A:=Result;
+      Result:=R;
+      R.B:=ParseMultiplicativeExpression;
+      isLHS:=False;
+      end;
+  except
+    FreeAndNil(Result);
+    Raise;
+  end;
+end;
+
+Function TJSParser.ParseShiftExpression : TJSElement;
+
+Var
+  C : TJSElementClass;
+  R : TJSShiftExpression;
+
+begin
+  {$ifdef debugparser}  Writeln('ParseShiftExpression');{$endif debugparser}
+  Result:=ParseAdditiveExpression;
+  try
+    While (CurrentToken in [tjsLshift,tjsRshift,tjsURShift]) do
+      begin
+      Case CurrentToken of
+        tjsLshift : C:=TJSLShiftExpression;
+        tjsRshift : C:=TJSRShiftExpression;
+        tjsURshift : C:=TJSURShiftExpression;
+      end;
+      R:=TJSShiftExpression(CreateElement(C));
+      R.A:=Result;
+      Result:=R;
+      GetNextToken;
+      R.B:=ParseAdditiveExpression;
+      IsLHS:=False;
+      end;
+  except
+    FreeAndNil(Result);
+    Raise;
+  end;
+end;
+
+Function TJSParser.ParseRelationalExpression: TJSElement;
+
+Var
+  S : Set of TJSToken;
+  C : TJSElementClass;
+  R : TJSRelationalExpression;
+
+begin
+  Result:=ParseShiftExpression;
+  try
+    S:=[tjsLT,tjsGT,tjsLE,tjsGE,tjsInstanceOf];
+    If Not Noin then
+      Include(S,tjsIn);
+    While (CurrentToken in S) do
+      begin
+      Case CurrentToken of
+        tjsLT : C:=TJSRelationalExpressionLT;
+        tjsGT : C:=TJSRelationalExpressionGT;
+        tjsLE : C:=TJSRelationalExpressionLE;
+        tjsGE : C:=TJSRelationalExpressionGE;
+        tjsInstanceOf :C:=TJSRelationalExpressionInstanceOf;
+        tjsIn : C:=TJSRelationalExpressionIn;
+      end;
+      R:=TJSRelationalExpression(CreateElement(C));
+      R.A:=Result;
+      Result:=R;
+      GetNextToken;
+      R.B:=ParseRelationalExpression;
+      IsLHS:=False;
+      end;
+  except
+    FreeAndNil(Result);
+    Raise;
+  end;
+end;
+
+Function TJSParser.ParseEqualityExpression: TJSElement;
+
+Var
+  C : TJSElementClass;
+  E : TJSEqualityExpression;
+
+begin
+  Result:=ParseRelationalExpression;
+  try
+     While (CurrentToken in [tjsEq,tjsNE,tjsSEQ,tjsSNE]) do
+       begin
+       Case CurrentToken of
+         tjsEq : C:=TJSEqualityExpressionEQ;
+         tjsNE : C:=TJSEqualityExpressionNE;
+         tjsSEQ : C:=TJSEqualityExpressionSEQ;
+         tjsSNE : C:=TJSEqualityExpressionSNE;
+       end;
+       GetNextToken;
+       E:=TJSEqualityExpression(CreateElement(C));
+       Result:=E;
+       E.A:=Result;
+       E.B:=ParseEqualityExpression;
+       E:=Nil;
+       IsLHS:=False;
+       end;
+  except
+    FreeAndNil(Result);
+    Raise;
+  end;
+end;
+
+Function TJSParser.ParseBitwiseAndExpression : TJSElement;
+
+Var
+  L : TJSBitwiseAndExpression;
+
+begin
+  Result:=ParseEqualityExpression;
+  try
+    If (CurrentToken<>tjsAnd) then
+      exit;
+    GetNextToken;
+    L:=TJSBitwiseAndExpression(CreateElement(TJSBitwiseAndExpression));
+    L.A:=Result;
+    Result:=L;
+    L.B:=ParseBitwiseAndExpression;
+    IsLHS:=False;
+  except
+    FreeAndNil(Result);
+    Raise;
+  end;
+end;
+
+Function TJSParser.ParseBitwiseXORExpression : TJSElement;
+
+Var
+  L : TJSBitwiseXOrExpression;
+
+begin
+  Result:=ParseBitwiseAndExpression;
+  try
+    If (CurrentToken<>tjsXOr) then
+      exit;
+    GetNextToken;
+    L:=TJSBitwiseXOrExpression(CreateElement(TJSBitwiseXOrExpression));
+    L.A:=Result;
+    Result:=L;
+    L.B:=ParseBitwiseXORExpression;
+    IsLHS:=False;
+  except
+    FreeAndNil(Result);
+    Raise;
+  end;
+end;
+
+Function TJSParser.ParseBitwiseORExpression : TJSElement;
+
+Var
+  L : TJSBitwiseOrExpression;
+
+begin
+  {$ifdef debugparser}  Writeln('ParseBitWiseOrExpression');{$endif debugparser}
+    Result:=ParseBitwiseXORExpression;
+    try
+      If (CurrentToken<>tjsOr) then
+        exit;
+      GetNextToken;
+      L:=TJSBitwiseOrExpression(CreateElement(TJSBitwiseOrExpression));
+      L.A:=Result;
+      Result:=L;
+      L.B:=ParseBitwiseORExpression;
+      IsLHS:=False;
+    except
+      FreeAndNil(Result);
+      Raise;
+    end;
+end;
+
+Function TJSParser.ParseLogicalAndExpression : TJSElement;
+
+Var
+  L : TJSLogicalAndExpression;
+
+begin
+  {$ifdef debugparser}  Writeln('ParseLogicalAndExpression');{$endif debugparser}
+  Result:=ParseBitwiseORExpression;
+  try
+    If (CurrentToken<>tjsAndAnd) then
+      exit;
+    GetNextToken;
+    L:=TJSLogicalAndExpression(CreateElement(TJSLogicalAndExpression));
+    L.A:=Result;
+    Result:=L;
+    L.B:=ParseLogicalAndExpression;
+    IsLHS:=False;
+  except
+    FreeAndNil(Result);
+    Raise;
+  end;
+end;
+
+Function TJSParser.ParseLogicalORExpression : TJSElement;
+
+Var
+  L : TJSLogicalOrExpression;
+
+begin
+  {$ifdef debugparser}  Writeln('ParseLogicalOrExpression');{$endif debugparser}
+  Result:=ParseLogicalAndExpression;
+  try
+    If (CurrentToken<>tjsOROR) then
+      exit;
+    GetNextToken;
+    L:=TJSLogicalOrExpression(CreateElement(TJSLogicalOrExpression));
+    L.A:=Result;
+    Result:=L;
+    L.B:=ParseLogicalOrExpression;
+    IsLHS:=False;
+  except
+    FreeAndNil(Result);
+    Raise;
+  end;
+end;
+
+Function TJSParser.ParseConditionalExpression : TJSElement;
+
+Var
+  N : TJSConditionalExpression;
+  L : TJSElement;
+begin
+  {$ifdef debugparser}  Writeln('ParseConditionalExpression');{$endif debugparser}
+  Result:=Nil;
+  Result:=ParseLogicalORExpression;
+  try
+    If (CurrentToken=tjsConditional) then
+      begin
+      GetNextToken;
+      L:=Result;
+      N:=TJSConditionalExpression(CreateElement(TJSConditionalExpression));
+      Result:=N;
+      N.A:=L;
+      L:=Nil;
+      N.B:=ParseAssignmentExpression;
+      Consume(tjsColon);
+      N.C:=ParseAssignmentExpression;
+      IsLHS:=False;
+      end;
+  except
+    FreeandNil(Result);
+  end;
+end;
+
+Function TJSParser.ParseAssignmentExpression : TJSElement;
+
+Var
+  N : TJSElement;
+  C : TJSElementClass;
+  A : TJSAssignStatement;
+
+begin
+  {$ifdef debugparser}  Writeln('ParseAssignmentExpression');{$endif debugparser}
+  Result:=Nil;
+  N:=ParseConditionalExpression;
+  If not isLHS then
+    Result:=N
+  else
+    Case CurrentToken of
+      tjsAssign    : C:=TJSSimpleAssignStatement;
+      tjsMulEq     : C:=TJSMulEqAssignStatement;
+      tjsDivEq     : C:=TJSDivEqAssignStatement;
+      tjsModEq     : C:=TJSModEqAssignStatement;
+      tjsPlusEq    : C:=TJSAddEqAssignStatement;
+      tjsMinusEq   : C:=TJSSubEqAssignStatement;
+      tjsLShiftEq  : C:=TJSLShiftEqAssignStatement;
+      tjsRShiftEq  : C:=TJSRShiftEqAssignStatement;
+      tjsURShiftEq : C:=TJSURShiftEqAssignStatement;
+      tjsANDEq     : C:=TJSANDEqAssignStatement;
+      tjsOREq      : C:=TJSOREqAssignStatement;
+      tjsXOREq     : C:=TJSXOREqAssignStatement;
+    else
+//      writeln('Strange token',GetEnumName(TypeInfo(TJSToken),Ord(CurrentToken)), ' As string: ',CurrentTokenString);
+      Result:=N
+    end;
+  If Result<>Nil then
+    Exit;
+  A:=TJSAssignStatement(CreateElement(C));
+  try
+    Result:=A;
+    A.Lhs:=N;
+    GetNextToken;
+    N:=Self.ParseAssignmentExpression;
+    A.Expr:=N;
+    IsLhs:=False;
+  except
+    FreeAndNil(Result);
+    Raise;
+  end;
+end;
+
+Function TJSParser.ParseVariableDeclaration : TJSElement;
+
+Var
+  V : TJSVarDeclaration;
+
+begin
+  V:=TJSVarDeclaration(CreateElement(TJSVarDeclaration));;
+  try
+    V.Name:=CurrenttokenString;
+    Consume(tjsIdentifier);
+    if (CurrentToken=tjsAssign) then
+      begin
+      GetNextToken;
+      V.Init:=ParseAssignmentExpression;
+      end;
+    Result:=V;
+    Writeln('Adding variable ',V.Name);
+    FCurrentVars.AddNode.Node:=Result;
+    Writeln('Current var count:  ',FCurrentVars.Count);
+  except
+    FreeAndNil(V);
+    Raise;
+  end;
+end;
+
+Function TJSParser.ParseVariableDeclarationList : TJSElement;
+
+Var
+  E,N : TJSElement;
+  L : TJSVariableDeclarationList;
+
+begin
+  Writeln('ParseVariableDeclarationList entry');
+  E:=ParseVariableDeclaration;
+  If (CurrentToken<>tjsComma) then
+    Result:=E
+  else
+    begin
+    L:=TJSVariableDeclarationList(CreateElement(TJSVariableDeclarationList));
+    Result:=L;
+    try
+      Consume(tjsComma);
+      N:=Self.ParseVariableDeclarationList;
+      L.A:=E;
+      L.B:=N;
+    except
+      FreeAndNil(Result);
+      Raise;
+    end;
+    end;
+  Writeln('ParseVariableDeclarationList exit');
+end;
+
+function TJSParser.ParseVariableStatement : TJSElement;
+
+Var
+  E : TJSElement;
+  V : TJSVariableStatement;
+
+begin
+  Writeln('ParseVariableStatement entry');
+  Result:=Nil;
+  Consume(tjsVar);
+  Result:=ParseVariableDeclarationList;
+  try
+    Consume(tjsSemicolon);
+    V:=TJSVariableStatement(CreateElement(TJSVariableStatement));
+    V.A:=Result;
+    Result:=V;
+  except
+    FreeAndNil(Result);
+    Raise;
+  end;
+  Writeln('ParseVariableStatement exit');
+end;
+
+function TJSParser.ParseEmptyStatement : TJSElement;
+
+begin
+  Consume(tjsSemiColon);
+  Result:=CreateElement(TJSEmptyStatement);
+end;
+
+function TJSParser.ParseIfStatement : TJSElement;
+
+Var
+  C,BTrue,BFalse : TJSElement;
+  I : TJSIFstatement;
+
+begin
+  C:=Nil;
+  BTrue:=Nil;
+  BFalse:=Nil;
+  try
+    Consume(tjsIF);
+    Consume(tjsBraceOpen);
+    C:=ParseExpression;
+    Consume(tjsBraceClose);
+    BTrue:=ParseStatement;
+    If (CurrentToken=tjsElse) then
+      begin
+      Consume(tjsElse);
+      BFalse:=ParseStatement;
+      end;
+    I:=TJSIfStatement(CreateElement(TJSIfStatement));
+    I.Cond:=C;
+    I.BTrue:=Btrue;
+    I.bfalse:=BFalse;
+    Result:=I;
+  except
+    FreeAndNil(C);
+    FreeAndNil(BTrue);
+    FreeAndNil(BFalse);
+    Raise;
+  end;
+end;
+
+function TJSParser.ParseIterationStatement : TJSElement;
+
+Var
+  F : TJSForStatement;
+  FI : TJSForInStatement;
+  W : TJSWhileStatement;
+  N : TJSElement;
+
+begin
+  Result:=Nil;
+  N:=Nil;
+  CurrentLabelSet.Continuable:=True;
+  EnterLabel(SEmptyLabel);
+  try
+    try
+    Case CurrentToken of
+      tjsDo :
+        begin
+        GetNextToken;
+        W:=TJSWhileStatement(CreateElement(TJSWhileStatement));
+        Result:=W;
+        W.Body:=ParseStatement;
+        Consume(tjsWhile);
+        Consume(tjsBraceOpen);
+        W.Cond:=ParseExpression;
+        Consume(tjsBraceClose);
+        Consume(tjsSemicolon);
+        end;
+      tjsWhile :
+        begin
+        GetNextToken;
+        W:=TJSWhileStatement(CreateElement(TJSWhileStatement));
+        Result:=W;
+        Consume(tjsBraceOpen);
+        W.Cond:=ParseExpression;
+        Consume(tjsBraceClose);
+        W.Body:=ParseStatement;
+        Result:=W;
+        end;
+      else
+        // For ?
+        GetNextToken;
+        Consume(tjsBraceopen);
+        If (CurrentToken=tjsVar) then
+          begin
+          GetNextToken;
+          N:=ParseVariableDeclarationList;
+          // for (var in
+          If (CurrentToken=tjsIn) and (N is tJSVarDeclaration) then
+            begin
+            Fi:=TJSForInStatement(CreateElement(TJSForInStatement));
+            Result:=Fi;
+            Fi.LHS:=N;
+            GetNextToken;
+            Fi.List:=ParseExpression;
+            Consume(tjsBraceClose);
+            Fi.Body:=ParseStatement;
+            end;
+          // for (var ;
+          If (CurrentToken<>tjsSemicolon) then
+            If (N is tJSVarDeclaration) then
+              Error(SErrSemicolonOrInExpected,[CurrentTokenString])
+            else
+              Error(SErrSemicolonExpected,[CurrentTokenString]);
+          GetNextToken;
+          F:=TJSForStatement(CreateElement(TJSForStatement));
+          Result:=F;
+          If (CurrentToken<>tjsSemicolon) then
+            F.Cond:=ParseExpression;
+          Consume(tjsSemicolon);
+          If (CurrentToken<>tjsBraceClose) then
+            F.Incr:=ParseExpression;
+          Consume(tjsBraceClose);
+          F.Body:=ParseStatement;
+          end
+        else
+          begin
+          If (CurrentToken<>tjsSemicolon) then
+            begin
+            N:=ParseExpression;
+            If (CurrentToken=tjsIn) then
+              begin
+              Fi:=TJSForInStatement(CreateElement(TJSForInStatement));
+              Result:=Fi;
+              Fi.LHS:=N;
+              N:=Nil; // prevent freeing a second time in case of an exception.
+              GetNextToken;
+              Fi.List:=ParseExpression;
+              Consume(tjsBraceClose);
+              Fi.Body:=ParseStatement;
+              Exit; // We must jump out here
+              end
+            end
+          else
+            N:=Nil;
+          // For ( Init; Cond; incr)
+          F:=TJSForStatement(CreateElement(TJSForStatement));
+          Result:=F;
+          F.Init:=N;
+          N:=Nil; // prevent freeing a second time in case of an exception.
+          Consume(tjsSemicolon);
+          if (CurrentToken<>tjsSemicolon) then
+            F.Cond:=ParseExpression;
+          Consume(tjsSemicolon);
+          If (CurrentToken<>tjsBraceClose) Then
+            F.Incr:=ParseExpression;
+          Consume(tjsBraceClose);
+          F.Body:=ParseStatement;
+          end;
+      end; // Case
+  Finally
+    LeaveLabel;
+  end;
+  except
+    FreeAndNil(N);
+    FreeAndNil(Result);
+    Raise;
+  end;
+end;
+
+function TJSParser.ParseContinueStatement : TJSElement;
+
+Var
+  L : TJSLabel;
+  C : TJSContinueStatement;
+
+begin
+  C:=TJSContinueStatement(CreateElement(TJSContinueStatement));
+  try
+    Result:=C;
+    Consume(tjsContinue);
+    If (CurrentToken=tjsSemicolon) then
+      L:=LookupLabel(SEmptyLabel,tjsContinue)
+    else
+      begin
+      if (CurrentToken=tjsIdentifier) then
+        L:=LookupLabel(CurrentTokenString,tjsContinue);
+      Consume(tjsIdentifier);
+      end;
+    Consume(tjsSemicolon);
+    C.Target:=L.Labelset.Target;
+  except
+    FreeAndNil(C);
+    Raise;
+  end;
+end;
+
+function TJSParser.ParseBreakStatement : TJSElement;
+
+Var
+  L : TJSLabel;
+  B : TJSBreakStatement;
+
+begin
+  B:=TJSBreakStatement(CreateElement(TJSBreakStatement));
+  try
+  Result:=B;
+    Consume(tjsBreak);
+    If (CurrentToken=tjsSemicolon) then
+      L:=LookupLabel(SEmptyLabel,tjsBreak)
+    else
+      begin
+      if (CurrentToken=tjsIdentifier) then
+        L:=LookupLabel(CurrentTokenString,tjsBreak);
+      Consume(tjsIdentifier);
+      end;
+    Consume(tjsSemicolon);
+    B.Target:=L.Labelset.Target;
+  except
+    FreeAndNil(B);
+    Raise;
+  end;
+end;
+
+function TJSParser.ParseReturnStatement : TJSElement;
+
+Var
+  R : TJSreturnStatement;
+
+begin
+  R:=TJSReturnStatement(CreateElement(TJSReturnStatement));
+  try
+    Result:=R;
+    Consume(tjsReturn);
+    If (FunctionDepth=0) then
+      Error(SErrReturnNotInFunction);
+    If Not (CurrentToken=tjsSemicolon) then
+      R.Expr:=ParseExpression;
+    Consume(tjsSemicolon);
+  except
+    FreeAndNil(R);
+    Raise;
+  end;
+end;
+
+function TJSParser.ParseWithStatement : TJSElement;
+
+Var
+  W : TJSWithStatement;
+  N : TJSElement;
+
+begin
+  W:=TJSWithStatement(CreateElement(TJSWithStatement));
+  try
+    Consume(tjsWith);
+    Consume(tjsBraceOpen);
+    W.A:=ParseExpression;
+    Consume(tjsBraceClose);
+    W.B:=ParseStatement;
+  except
+    FreeAndNil(W);
+    Raise;
+  end;
+end;
+
+function TJSParser.ParseSwitchStatement : TJSElement;
+
+
+Var
+  N : TJSSwitchStatement;
+  C : TJSElement;
+  Ca : TJSCaseElement;
+
+begin
+  N:=TJSSwitchStatement(CreateElement(TJSSwitchStatement));
+  try
+    N.Target:=CurrentLabelset.Target;
+    EnterLabel(SEmptyLabel);
+    try
+      Consume(tjsSwitch);
+      Consume(tjsBraceOpen);
+      N.Cond:=ParseExpression;
+      Consume(tjsBraceClose);
+      Consume(tjsCurlyBraceOpen);
+      While (CurrentToken<>tjsCurlyBraceClose) do
+        begin
+        If (CurrentToken=tjsCase) then
+          begin
+          GetNextToken;
+          Ca:=N.Cases.AddCase;
+          Ca.Expr:=ParseExpression;
+          end
+        else if (CurrentToken=tjsDefault) then
+          begin
+          If (N.TheDefault<>Nil) then
+            Error(SerrDuplicateSwitchDefault);
+          Ca:=N.Cases.AddCase;
+          N.TheDefault:=Ca;
+          GetNextToken;
+          end
+        else
+          Error(SerrCaseEndExpected);
+        Consume(tjsColon);
+        If Not (CurrentToken in [tjsCurlyBraceClose,tjsCase,tjsDefault]) then
+          Ca.Body:=ParseStatementList;
+        end;
+      Consume(tjsCurlyBraceClose);
+    finally
+      LeaveLabel;
+    end;
+  except
+    FreeAndNil(N);
+    Raise;
+  end;
+end;
+
+function TJSParser.ParseThrowStatement : TJSElement;
+
+Var
+  TS : TJSThrowStatement;
+
+begin
+  TS:=TJSThrowStatement(CreateElement(TJSThrowStatement));
+  try
+    Result:=TS;
+    Consume(tjsThrow);
+    If IsEndOfLine then
+      Error(SErrNewlineAfterThrow);
+    TS.A:=ParseExpression;
+    Consume(tjsSemicolon);
+  except
+    FreeAndNil(TS);
+    Raise;
+  end;
+end;
+
+function TJSParser.ParseTryStatement : TJSElement;
+
+Var
+  BO,BC,BF : TJSElement;
+  Id : TJSString;
+  T : TJSTryStatement;
+
+begin
+  BO:=Nil;
+  BC:=Nil;
+  BF:=Nil;
+  Result:=Nil;
+  Consume(tjsTry);
+  try
+    Bo:=ParseBlock;
+    if (CurrentToken=tjscatch) then
+      begin
+      Consume(tjsCatch);
+      Consume(tjsBraceOpen);
+      if (CurrentToken=tjsIdentifier) then
+        id:=CurrentTokenString;
+      Consume(tjsIdentifier);
+      Consume(tjsBraceClose);
+      BC:=ParseBlock;
+      end;
+    if (CurrentToken=tjsFinally) then
+      begin
+      consume(tjsFinally);
+      BF:=ParseBlock;
+      end;
+    If (BF=Nil) and (BC=Nil) then
+      Error(SErrCatchFinallyExpected);
+    If Assigned(BC) AND Assigned(BF) then
+      T:=TJSTryStatement(CreateElement(TJSTryCatchFinallyStatement))
+    else if Assigned(BC) then
+      T:=TJSTryStatement(CreateElement(TJSTryCatchStatement))
+    else
+      T:=TJSTryStatement(CreateElement(TJSTryFinallyStatement));
+    Result:=T;
+    T.Block:=Bo;
+    Bo:=Nil;
+    T.BCatch:=BC;
+    BC:=Nil;
+    T.BFinally:=BF;
+    BF:=Nil;
+    T.Ident:=ID;
+  except
+    FreeAndNil(Bo);
+    FreeAndNil(BC);
+    FreeAndNil(BF);
+    FreeAndNil(Result);
+    Raise;
+  end;
+
+end;
+
+function TJSParser.ParseFunctionExpression : TJSFunctionDeclarationStatement;
+
+Var
+  Oni,olhs: Boolean;
+  F : TJSFunctionDeclarationStatement;
+  N : String;
+  Args : TStrings;
+
+begin
+  {$ifdef debugparser} Writeln('>>> ParseFunctionExpression');{$endif}
+  oni:=NoIn;
+  olhs:=IsLHS;
+  F:=Nil;
+  Args:=Nil;
+  try
+    NoIn:=False;
+    IsLHS:=False;
+    F:=TJSFunctionDeclarationStatement(CreateElement(TJSFunctionDeclarationStatement));
+    try
+      Consume(tjsFunction);
+      if (CurrentToken=tjsIdentifier) then
+        begin
+        n:=CurrentTokenstring;
+        GetNextToken;
+        end
+      else
+        n:='';
+      Consume(tjsBraceOpen);
+      F.AFunction:= TJSFuncDef.Create;
+      Args:=ParseFormalParameterList;
+      try
+        If Assigned(Args) then
+          F.AFunction.Params.Assign(Args);
+      finally
+        FreeAndNil(Args);
+      end;
+      Consume(tjsBraceClose);
+      Consume(tjsCurlyBraceOpen);
+      Inc(FFunctionDepth);
+      try
+        F.AFunction.Body:=ParseFunctionBody;
+      Finally
+        Dec(FFunctionDepth);
+      end;
+      Consume(tjsCurlyBraceClose);
+      Result:=F;
+    except
+      FreeAndNil(F);
+      Raise;
+    end;
+  finally
+    NoIn  := oni;
+    IsLHS := olhs;
+  end;
+  {$ifdef debugparser} Writeln('<<< ParseFunctionExpression');{$endif}
+end;
+
+function TJSParser.ParseFunctionStatement : TJSElement;
+
+Var
+  F : TJSFunctionDeclarationStatement;
+  I : TJSPrimaryExpressionIdent;
+  A : TJSAssignStatement;
+  E : TJSExpressionStatement;
+
+begin
+  {$ifdef debugparser} Writeln('>>> ParseFunctionStatement');{$endif}
+  F:=Nil;
+  I:=Nil;
+  A:=Nil;
+  try
+    F:=ParseFunctionExpression;
+    I:=TJSPrimaryExpressionIdent(CreateElement(TJSPrimaryExpressionIdent));
+    I.AString:=F.AFunction.Name;
+    A:=TJSAssignStatement(CreateElement(TJSAssignStatement));
+    A.LHS:=I;
+    I:=Nil;
+    A.Expr:=F;
+    F:=Nil;
+    E:=TJSExpressionStatement(CreateElement(TJSExpressionStatement));
+    E.A:=A;
+    A:=Nil;
+    Result:=E;
+  except
+    FreeAndNil(F);
+    FreeAndNil(I);
+    FreeAndNil(A);
+    Raise;
+  end;
+  {$ifdef debugparser} Writeln('<<< ParseFunctionStatement');{$endif}
+end;
+
+function TJSParser.ParseLabeledStatement : TJSElement;
+
+Var
+  OL : TJSLabelSet;
+  LS : TJSLabeledStatement;
+  LN : String;
+
+begin
+  LS:=TJSLabeledStatement(CreateElement(TJSLabeledStatement));
+  try
+    Result:=LS;
+    OL:=FCurrentLabelSet;
+    try
+      FCurrentLabelSet:=Nil;
+      LS.target:=CurrentLabelSet.Target;
+      Repeat
+        EnterLabel(CurrentTokenString);
+        Consume(tjsIdentifier);
+        Consume(tjsColon);
+      Until (CurrentToken<>tjsIdentifier) or (PeekNextToken<>tjsColon);
+      Case CurrentToken of
+         tjsDo,tjsWhile,tjsFor : LS.A:=ParseIterationStatement;
+         tjsswitch : LS.A:=ParseSwitchStatement;
+      else
+        LS.A:=ParseStatement;
+      end;
+    finally
+      FreeCurrentLabelSet;
+      FCurrentLabelSet:=Ol;
+    end;
+  except
+    FreeAndNil(LS);
+    Raise;
+  end;
+end;
+
+procedure TJSParser.FreeCurrentLabelSet;
+
+Var
+  L : TJSLabelSet;
+
+begin
+  While Assigned(FCurrentLabelSet) do
+    begin
+    L:=FCurrentLabelset.Next;
+    FCurrentLabelSet.Free;
+    FCurrentLabelSet:=L;
+    end;
+end;
+
+function TJSParser.ParseExpressionStatement : TJSElement;
+
+Var
+  E : TJSElement;
+  R : TJSExpressionStatement;
+begin
+  E:=ParseExpression;
+  Consume(tjsSemicolon);
+  R:=TJSExpressionStatement(CreateElement(TJSExpressionStatement));
+  R.A:=E;
+  Result:=R;
+end;
+
+function TJSParser.ParseExpression : TJSElement;
+
+Var
+  C : TJSCommaExpression;
+
+begin
+  Result:=ParseAssignmentExpression;
+  try
+    If (CurrentToken=tjsComma) then
+      begin
+      C:=TJSCommaExpression(CreateElement(TJSCommaExpression));
+      C.A:=Result;
+      Result:=C;
+      GetNextToken;
+      C.B:=ParseExpression;
+      end;
+  except
+    FreeAndNil(Result);
+    Raise;
+  end;
+
+end;
+
+function TJSParser.ParseStatement : TJSElement;
+
+begin
+  {$ifdef debugparser} Writeln('>>> Parsestatement');{$endif}
+  Result:=Nil;
+  Case CurrentToken of
+    tjsCurlyBraceOpen :
+      Result:=ParseBlock;
+    tjsVar:
+      Result:=ParseVariableStatement;
+    tjsSemicolon:
+      Result:=ParseEmptyStatement;
+    tjsIf:
+      Result:=ParseIfStatement;
+    tjsDo,tjsWhile,tjsFor:
+      Result:=ParseIterationStatement;
+    tjsContinue:
+      Result:=ParseContinueStatement;
+    tjsBreak:
+      Result:=ParseBreakStatement;
+    tjsReturn:
+      Result:=ParseReturnStatement;
+    tjsWith:
+      Result:=ParseWithStatement;
+    tjsSwitch:
+      Result:=ParseSwitchStatement;
+    tjsThrow:
+      Result:=ParseThrowStatement;
+    tjsTry:
+      Result:=ParseTryStatement;
+    tjsFunction:
+      begin
+      If (PeekNextToken<>tjsBraceOpen) then
+        Result:=ParseFunctionStatement;
+      Error(SErrFunctionNotAllowedHere);
+      end;
+    tjsIdentifier:
+      If (PeekNextToken=tjsColon) then
+        Result:=ParseLabeledStatement
+      else
+        Result:=ParseExpressionStatement;
+  else
+    Result:=ParseExpressionStatement;
+  end;
+  {$ifdef debugparser} Writeln('<<< Parsestatement ',Result.ClassName);{$endif}
+end;
+
+function TJSParser.ParseSourceElements : TJSSourceElements;
+
+Const
+  StatementTokens = [tjsNULL, tjsTRUE, tjsFALSE,
+      tjsTHIS, tjsIdentifier,jsscanner.tjsSTRING,tjsNUMBER,
+      tjsBraceOpen,tjsCurlyBraceOpen,tjsSquaredBraceOpen,
+      tjsNew,tjsDelete,tjsVoid,tjsTypeOf,
+      tjsPlusPlus,tjsMinusMinus,
+      tjsPlus,tjsMinus,tjsNot,tjsNE,tjsSNE,tjsSemicolon,
+      tjsVAR,tjsIF,tjsDO,tjsWHILE,tjsFOR,jsscanner.tjsCONTINUE,jsscanner.tjsBREAK,jsscanner.tjsReturn,
+      tjsWith,jsscanner.tjsSWITCH,tjsThrow,TjsTry,tjsDIV,tjsDIVEQ];
+
+Var
+  F : TJSFunctionDeclarationStatement;
+  E : TJSElement;
+  Done : Boolean;
+  VS : TJSElementNodes;
+begin
+  {$ifdef debugparser} Writeln('>>> Entering source elements');{$endif}
+  Result:=TJSSourceElements(CreateElement(TJSSourceElements));
+  try
+    Done:=False;
+    VS:=FCurrentVars;
+    Try
+      FCurrentVars:=Result.Vars;
+      Repeat
+        {$ifdef debugparser} Writeln('Sourceelements start:',GetEnumName(TypeInfo(TJSToken),Ord(CurrentToken)), ' As string: ',CurrentTokenString);{$endif debugparser}
+        If (CurrentToken=jsscanner.tjsFunction) then
+          begin
+          If (PeekNextToken<>tjsBraceOpen) then
+            begin
+            F:=Self.ParseFunctionDeclaration;
+            Result.functions.AddNode.Node:=F;
+            end
+          else
+            begin
+            {$ifdef debugparser} Writeln('Function expression detected');{$endif}
+            E:=Self.ParseStatement;
+            Result.Statements.AddNode.Node:=E;
+            end;
+          end
+        else if CurrentToken in StatementTokens then
+          begin
+          E:=Self.ParseStatement;
+          Result.Statements.AddNode.Node:=E;
+          end
+        else
+          Done:=True;
+        {$ifdef debugparser} Writeln('Sourceelements Done : ',Done);{$endif}
+      Until Done;
+    Finally
+      FCurrentVars:=VS;
+    end;
+  except
+    FreeAndNil(Result);
+    Raise;
+  end;
+  {$ifdef debugparser}   Writeln('<<< Exiting source elements');{$endif}
+end;
+
+function TJSParser.ParseFunctionBody : TJSFunctionBody;
+
+Var
+  E : TJSElement;
+
+begin
+  {$ifdef debugparser} Writeln('>>> Entering FunctionBody');{$endif}
+  Result:=TJSFunctionBody(CreateElement(TJSFunctionBody));
+  try
+    E:=Self.ParseSourceElements;
+    Result.A:=E;
+  except
+    FreeAndNil(Result);
+    Raise;
+  end;
+  {$ifdef debugparser} Writeln('<<< Exiting FunctionBody');{$endif}
+end;
+
+function TJSParser.ParseProgram : TJSFunctionDeclarationStatement;
+
+Var
+  F : TJSFunctionDeclarationStatement;
+  FD : TJSFuncDef;
+  B : TJSElement;
+begin
+  {$ifdef debugparser} Writeln('>>> Entering FunctionDeclarationStatement');{$endif}
+  B:=Parse;
+  If Not (B is TJSFunctionBody) then
+    Error('Parse did not result in functionbody');
+  Result:=TJSFunctionDeclarationStatement(CreateElement(TJSFunctionDeclarationStatement));
+  Result.AFunction:=TJSFuncDef.Create;
+  Result.AFunction.Body:=TJSFunctionBody(B);
+  {$ifdef debugparser} Writeln('<<< Exiting FunctionDeclarationStatement');{$endif}
+end;
+
+function TJSParser.Parse: TJSElement;
+
+Var
+  Body : TJSElement;
+
+begin
+  {$ifdef debugparser} Writeln('>>> Parse');{$endif}
+  Result:=Nil;
+  CheckParser;
+  GetNextToken;
+  Body:=ParseFunctionBody;
+  Result:=Body;
+  try
+    if (CurrentToken<>tjsEOF) then
+      begin
+      if (CurrentToken=tjsCurlyBraceClose) then
+        Error(SErrUnmatchedCurlyBrace)
+      else if (CurrentToken=tjsBraceClose) then
+        Error(SerrUnmatchedBrace)
+      else if (CurrentToken=tjsSquaredBraceClose) then
+        Error(SerrUnmatchedSquareBrace);
+      Error(SErrUnexpectedToken,[CurrentTokenString]);
+      end;
+    If (Body is TJSFunctionBody) then
+      TJSFunctionBody(Body).isProgram:=True;
+  except
+    FreeAndNil(Result);
+    Raise;
+  end;
+  {$ifdef debugparser} Writeln('<<< Parse');{$endif}
+end;
+
+
+end.
+

+ 909 - 0
packages/fcl-js/src/jsscanner.pp

@@ -0,0 +1,909 @@
+{
+    This file is part of the Free Component Library
+
+    ECMAScript (JavaScript) source lexical scanner
+
+    See the file COPYING.FPC, included in this distribution,
+    for details about the copyright.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ **********************************************************************}
+
+{$mode objfpc}
+{$h+}
+
+unit JSScanner;
+
+interface
+
+uses SysUtils, Classes;
+
+resourcestring
+  SErrInvalidCharacter = 'Invalid character ''%s''';
+  SErrOpenString = 'string exceeds end of line';
+  SErrIncludeFileNotFound = 'Could not find include file ''%s''';
+  SErrIfXXXNestingLimitReached = 'Nesting of $IFxxx too deep';
+  SErrInvalidPPElse = '$ELSE without matching $IFxxx';
+  SErrInvalidPPEndif = '$ENDIF without matching $IFxxx';
+  SInvalidHexadecimalNumber = 'Invalid decimal number';
+  SErrInvalidNonEqual = 'SyntaxError: != or !== expected';
+
+type
+
+   TJSToken = (tjsUnknown,
+   // Specials
+   tjsEOF,tjsWhiteSpace,tjsChar,tjsString, tjsIdentifier,tjsNumber, tjsComment,tjsREGEX, tjsRESERVED,
+   tjsANDAND, tjsANDEQ,
+   tjsBraceOpen,tjsBraceClose,tjsSQuaredBraceOpen,tjsSQuaredBraceClose,tjsCurlyBraceOpen,tjsCurlyBraceClose,
+   tjsCOMMA,tjsCOLON,  tjsDOT,tjsSEMICOLON, tjsASSIGN,tjsGT,tjsLT, tjsConditional,
+   tjsPLUS,tjsMINUS,tjsMUL,tjsDIV,tjsAnd,tjsOR, tjsInv, tjsMod, tjsXOR, tjsNot,
+   tjsEQ,
+   tjsGE,
+   tjsLE, tjsLSHIFT, tjsLSHIFTEQ,
+   tjsMINUSEQ, tjsMINUSMINUS, tjsMODEQ,tjsDIVEQ,tjsXOREq,
+   tjsNE,
+   tjsOREQ, tjsOROR,
+   tjsPLUSEQ, tjsPLUSPLUS,
+   tjsURSHIFT, tjsURSHIFTEQ,
+   tjsRSHIFT, tjsRSHIFTEQ,
+   tjsSEQ, tjsSNE, tjsMULEQ,
+   { Reserved words start here. They must be last }
+   tjsBREAK,tjsCASE, tjsCATCH, tjsCONTINUE,
+   tjsDEFAULT, tjsDELETE, tjsDO,
+   tjsELSE,
+   tjsFalse, tjsFINALLY, tjsFOR, tjsFUNCTION,
+   tjsIF, tjsIN, tjsINSTANCEOF,
+   tjsNEW,tjsNULL,
+   tjsRETURN,
+   tjsSWITCH,
+   tjsTHIS, tjsTHROW, tjsTrue, tjsTRY, tjsTYPEOF,
+   tjsVAR, tjsVOID,
+   tjsWHILE, tjsWITH
+ );
+
+const
+  FirstKeyword = tjsBreak;
+  LastKeyWord = tJSWith;
+
+  TokenInfos: array[TJSToken] of string = ('unknown',
+     // Specials
+      'EOF','whitespace','Char','String', 'identifier','number','comment','regular expression', 'reserved word',
+      '&&','&=',
+      '(',')','[',']','{','}',
+      ',',':','.',';','=','>','<','?',
+      '+','-','*','/','&','|','~','%','^','!',
+      '==',
+      '>=',
+      '<=', '<<', '<<=',
+      '-=', '--', '%=', '/=','^=',
+      '!=',
+      '|=', '||',
+      '+=', '++',
+      '>>>', '>>>=',
+      '>>', '>>=',
+      '===', '!==', '*=',
+      // Identifiers last
+      'break','case','catch', 'continue',
+   'default','delete', 'do',
+   'else',
+   'false','finally', 'for', 'function',
+   'if', 'in', 'instanceof',
+   'new','null',
+   'return',
+   'switch',
+   'this', 'throw', 'true', 'try', 'typeof',
+   'var', 'void',
+   'while', 'with'
+  );
+
+Type
+  TLineReader = class
+  public
+    function IsEOF: Boolean; virtual; abstract;
+    function ReadLine: string; virtual; abstract;
+  end;
+
+  { TStreamLineReader }
+
+  TStreamLineReader = class(TLineReader)
+  private
+    FStream : TStream;
+    Buffer : Array[0..1024] of Byte;
+    FBufPos,
+    FBufLen : Integer;
+    procedure FillBuffer;
+  public
+    Constructor Create(AStream : TStream);
+    function IsEOF: Boolean; override;
+    function ReadLine: string; override;
+  end;
+
+  TFileLineReader = class(TLineReader)
+  private
+    FTextFile: Text;
+    FileOpened: Boolean;
+  public
+    constructor Create(const AFilename: string);
+    destructor Destroy; override;
+    function IsEOF: Boolean; override;
+    function ReadLine: string; override;
+  end;
+
+  EJSScannerError       = class(Exception);
+
+  { TJSScanner }
+
+  TJSScanner = class
+  private
+    FReturnComments: Boolean;
+    FReturnWhiteSpace: Boolean;
+    FSourceFile: TLineReader;
+    FSourceFilename: string;
+    FCurRow: Integer;
+    FCurToken: TJSToken;
+    FCurTokenString: string;
+    FCurLine: string;
+    FDefines: TStrings;
+    TokenStr: PChar;
+    FSourceStream : TStream;
+    FOwnSourceFile : Boolean;
+    function CommentDiv: TJSToken;
+    function DoIdentifier : TJSToken;
+    function DoMultiLineComment: TJSToken;
+    function DoNumericLiteral: TJSToken;
+    function DoSingleLineComment: TJSToken;
+    function DoStringLiteral: TJSToken;
+    function DoWhiteSpace: TJSToken;
+    function FetchLine: Boolean;
+    function GetCurColumn: Integer;
+    function ReadUnicodeEscape: WideChar;
+  protected
+    procedure Error(const Msg: string);overload;
+    procedure Error(const Msg: string; Args: array of Const);overload;
+  public
+    constructor Create(ALineReader: TLineReader);
+    constructor Create(AStream : TStream);
+    destructor Destroy; override;
+    procedure OpenFile(const AFilename: string);
+    Function FetchToken: TJSToken;
+    Function IsEndOfLine : Boolean;
+    Property ReturnComments : Boolean Read FReturnComments Write FReturnComments;
+    Property ReturnWhiteSpace : Boolean Read FReturnWhiteSpace Write FReturnWhiteSpace;
+    property SourceFile: TLineReader read FSourceFile;
+    property CurFilename: string read FSourceFilename;
+    property CurLine: string read FCurLine;
+    property CurRow: Integer read FCurRow;
+    property CurColumn: Integer read GetCurColumn;
+    property CurToken: TJSToken read FCurToken;
+    property CurTokenString: string read FCurTokenString;
+  end;
+
+
+implementation
+
+
+constructor TFileLineReader.Create(const AFilename: string);
+begin
+  inherited Create;
+  Assign(FTextFile, AFilename);
+  Reset(FTextFile);
+  FileOpened := true;
+end;
+
+destructor TFileLineReader.Destroy;
+begin
+  if FileOpened then
+    Close(FTextFile);
+  inherited Destroy;
+end;
+
+function TFileLineReader.IsEOF: Boolean;
+begin
+  Result := EOF(FTextFile);
+end;
+
+function TFileLineReader.ReadLine: string;
+begin
+  ReadLn(FTextFile, Result);
+end;
+
+constructor TJSScanner.Create(ALineReader: TLineReader);
+begin
+  inherited Create;
+  FSourceFile := ALineReader;
+end;
+
+constructor TJSScanner.Create(AStream: TStream);
+begin
+  FSourceStream:=ASTream;
+  FOwnSourceFile:=True;
+  Create(TStreamLineReader.Create(AStream));
+end;
+
+destructor TJSScanner.Destroy;
+begin
+  If FOwnSourceFile then
+    FSourceFile.Free;
+  inherited Destroy;
+end;
+
+procedure TJSScanner.OpenFile(const AFilename: string);
+begin
+  FSourceFile := TFileLineReader.Create(AFilename);
+  FSourceFilename := AFilename;
+end;
+
+
+procedure TJSScanner.Error(const Msg: string);
+begin
+  raise EJSScannerError.Create(Msg);
+end;
+
+procedure TJSScanner.Error(const Msg: string; Args: array of Const);
+begin
+  raise EJSScannerError.CreateFmt(Msg, Args);
+end;
+
+function TJSScanner.FetchLine: Boolean;
+begin
+  if FSourceFile.IsEOF then
+  begin
+    FCurLine := '';
+    TokenStr := nil;
+    Result := false;
+  end else
+  begin
+    FCurLine := FSourceFile.ReadLine;
+    TokenStr := PChar(CurLine);
+    Result := true;
+    Inc(FCurRow);
+  end;
+end;
+
+function TJSScanner.DoWhiteSpace : TJSToken;
+
+begin
+  Result:=tjsWhitespace;
+  repeat
+    Inc(TokenStr);
+    if TokenStr[0] = #0 then
+      if not FetchLine then
+       begin
+       FCurToken := Result;
+       exit;
+       end;
+  until not (TokenStr[0] in [#9, ' ']);
+end;
+
+function TJSScanner.DoSingleLineComment : TJSToken;
+
+Var
+  TokenStart : PChar;
+  Len : Integer;
+
+begin
+  Inc(TokenStr);
+  TokenStart := TokenStr;
+  while TokenStr[0] <> #0 do
+     Inc(TokenStr);
+  Len:=TokenStr-TokenStart;
+  SetLength(FCurTokenString, Len);
+  if (Len>0) then
+    Move(TokenStart^,FCurTokenString[1],Len);
+  Result := tjsComment;
+end;
+
+function TJSScanner.DoMultiLineComment : TJSToken;
+
+Var
+  TokenStart : PChar;
+  Len,OLen : Integer;
+  PrevToken : Char;
+
+begin
+  Inc(TokenStr);
+  TokenStart := TokenStr;
+  FCurTokenString := '';
+  OLen:= 0;
+  PrevToken:=#0;
+  while Not ((TokenStr[0]='/') and (PrevToken='*')) do
+    begin
+    if (TokenStr[0]=#0) then
+      begin
+      Len:=TokenStr-TokenStart+1;
+      SetLength(FCurTokenString,OLen+Len);
+      if Len>1 then
+        Move(TokenStart^,FCurTokenString[OLen+1],Len-1);
+      Inc(OLen,Len);
+      FCurTokenString[OLen]:=#10;
+      if not FetchLine then
+        begin
+        Result := tjsEOF;
+        FCurToken := Result;
+        exit;
+        end;
+      TokenStart := TokenStr;
+      PrevToken:=#0;
+      end
+    else
+      begin
+      PrevToken:=TokenStr[0];
+      Inc(TokenStr);
+      end;
+    end;
+  Len:=TokenStr-TokenStart-1; // -1 for *
+  SetLength(FCurTokenString, Olen+Len);
+  if (Len>0) then
+    Move(TokenStart^, FCurTokenString[Olen + 1], Len);
+  Inc(TokenStr);
+  Result := tjsComment;
+end;
+
+function TJSScanner.CommentDiv : TJSToken;
+
+begin
+  FCurTokenString := '';
+  Inc(TokenStr);
+  if (TokenStr[0] = '/') then       // Single-line comment
+    Result:=DoSingleLineComment
+  else if (TokenStr[0]='*') then
+    Result:=DoMultiLineComment
+  else if (TokenStr[0] = '=') then       // Single-line comment
+    begin
+    Result:=tjsDiveQ;
+    Inc(TokenStr)
+    end
+  else
+    Result:=tjsDiv;
+end;
+
+Function TJSScanner.ReadUnicodeEscape : WideChar;
+
+Var
+  S : String;
+  I : Integer;
+
+begin
+  S:='0000';
+  For I:=1 to 4 do
+    begin
+    Inc(TokenStr);
+    Case TokenStr[0] of
+      '0'..'9','A'..'F','a'..'f' :
+        S[i]:=Upcase(TokenStr[0]);
+    else
+      Error(SErrInvalidCharacter, [TokenStr[0]]);
+    end;
+    end;
+  // Takes care of conversion... This needs improvement !!
+  Result:=WideChar(StrToInt('$'+S));
+end;
+
+Function TJSScanner.DoStringLiteral : TJSToken;
+
+Var
+  Delim : Char;
+  TokenStart : PChar;
+  Len,OLen,I : Integer;
+  S : String;
+
+begin
+  Delim:=TokenStr[0];
+  Inc(TokenStr);
+  TokenStart := TokenStr;
+  OLen := 0;
+  FCurTokenString := '';
+  while not (TokenStr[0] in [#0,Delim]) do
+    begin
+    if (TokenStr[0]='\') then
+      begin
+      // Save length
+      Len := TokenStr - TokenStart;
+      Inc(TokenStr);
+      // Read escaped token
+      Case TokenStr[0] of
+        '"' : S:='"';
+        't' : S:=#9;
+        'b' : S:=#8;
+        'n' : S:=#10;
+        'r' : S:=#13;
+        'f' : S:=#12;
+        '\' : S:='\';
+        '/' : S:='/';
+        'u' : begin
+              S:=ReadUniCodeEscape;
+              end;
+        #0  : Error(SErrOpenString);
+      else
+        Error(SErrInvalidCharacter, [TokenStr[0]]);
+      end;
+      SetLength(FCurTokenString, OLen + Len+1+Length(S));
+      if Len > 0 then
+        Move(TokenStart^, FCurTokenString[OLen + 1], Len);
+      Move(S[1],FCurTokenString[OLen + Len+1],Length(S));
+      Inc(OLen, Len+Length(S));
+      // Next char
+      // Inc(TokenStr);
+      TokenStart := TokenStr+1;
+      end;
+    if TokenStr[0] = #0 then
+      Error(SErrOpenString);
+    Inc(TokenStr);
+    end;
+  if TokenStr[0] = #0 then
+    Error(SErrOpenString);
+  Len := TokenStr - TokenStart;
+  SetLength(FCurTokenString, OLen + Len);
+  if Len > 0 then
+    Move(TokenStart^, FCurTokenString[OLen+1], Len);
+  Inc(TokenStr);
+  Result := tjsString;
+end;
+
+function TJSScanner.DoNumericLiteral :TJSToken;
+
+Var
+  TokenStart : PChar;
+  Len : Integer;
+
+begin
+  TokenStart := TokenStr;
+  while true do
+    begin
+    Inc(TokenStr);
+    case TokenStr[0] of
+      'x':
+        If (TokenStart[0]='0') and ((TokenStr-TokenStart)=1) then
+          begin
+          Inc(TokenStr);
+          while Upcase(TokenStr[0]) in ['0'..'9','A'..'F'] do
+            Inc(TokenStr);
+          end
+        else
+          Error(SInvalidHexadecimalNumber);
+      '.':
+        begin
+          if TokenStr[1] in ['0'..'9', 'e', 'E'] then
+          begin
+            Inc(TokenStr);
+            repeat
+              Inc(TokenStr);
+            until not (TokenStr[0] in ['0'..'9', 'e', 'E','-','+']);
+          end;
+          break;
+        end;
+      '0'..'9': ;
+      'e', 'E':
+        begin
+          Inc(TokenStr);
+          if TokenStr[0] in ['-','+']  then
+            Inc(TokenStr);
+          while TokenStr[0] in ['0'..'9'] do
+            Inc(TokenStr);
+          break;
+        end;
+      else
+        break;
+    end;
+  end;
+  Len:=TokenStr-TokenStart;
+  Setlength(FCurTokenString, Len);
+  if (Len>0) then
+  Move(TokenStart^,FCurTokenString[1],Len);
+  Result := tjsNumber;
+end;
+
+function TJSScanner.DoIdentifier : TJSToken;
+
+Var
+  TokenStart:PChar;
+  Len : Integer;
+  I : TJSToken;
+
+begin
+  Result:=tjsIdentifier;
+  TokenStart := TokenStr;
+  repeat
+    Inc(TokenStr);
+    If (TokenStr[0]='\') and (TokenStr[1]='u') then
+  until not (TokenStr[0] in ['A'..'Z', 'a'..'z', '0'..'9', '_','$']);
+  Len:=(TokenStr-TokenStart);
+  SetLength(FCurTokenString,Len);
+  if Len > 0 then
+    Move(TokenStart^,FCurTokenString[1],Len);
+ // Check if this is a keyword or identifier
+ // !!!: Optimize this!
+  I:=FirstKeyword;
+  While (Result=tjsIdentifier) and (I<=Lastkeyword) do
+    begin
+    if (CurTokenString=TokenInfos[i]) then
+      begin
+      Result := i;
+      FCurToken := Result;
+      exit;
+      end;
+    I:=Succ(I);
+    end
+end;
+
+function TJSScanner.FetchToken: TJSToken;
+
+
+var
+  TokenStart, CurPos: PChar;
+  i: TJSToken;
+  OldLength, SectionLength, NestingLevel, Index: Integer;
+
+begin
+
+  Repeat
+    if TokenStr = nil then
+      if not FetchLine then
+        begin
+        Result := tjsEOF;
+        FCurToken := Result;
+        exit;
+        end;
+    CurPos:=TokenStr;
+    FCurTokenString := '';
+    case TokenStr[0] of
+      #0:         // Empty line
+        begin
+        FetchLine;
+        Result := tjsWhitespace;
+        end;
+      '/' :
+         Result:=CommentDiv;
+      #9, ' ':
+         Result := DoWhiteSpace;
+      '''','"':
+         Result:=DoStringLiteral;
+      '0'..'9':
+         Result:=DoNumericLiteral;
+     '&':
+         begin
+         Inc(TokenStr);
+         If Tokenstr[0]='&' then
+           begin
+           Inc(TokenStr);
+           Result := tjsAndAnd;
+           end
+         else If Tokenstr[0]='=' then
+           begin
+           Inc(TokenStr);
+           Result := tjsAndEQ;
+           end
+         else
+           Result := tjsAnd;
+         end;
+     '%':
+         begin
+         Inc(TokenStr);
+         If Tokenstr[0]='=' then
+           begin
+           Inc(TokenStr);
+           Result := tjsModEq;
+           end
+         else
+           Result := tjsMod;
+         end;
+     '^':
+         begin
+         Inc(TokenStr);
+         If (TokenStr[0]='=') then
+           begin
+           Result:=tjsXorEq;
+           Inc(tokenStr)
+           end
+         else
+           result:=tjsXOR;
+         end;
+     '|':
+         begin
+         Inc(TokenStr);
+         If Tokenstr[0]='|' then
+           begin
+           Inc(TokenStr);
+           Result := tjsOROR;
+           end
+         else If Tokenstr[0]='=' then
+             begin
+             Inc(TokenStr);
+             Result := tjsOREQ;
+             end
+         else
+           Result := tjsOR;
+         end;
+    '(':
+      begin
+      Inc(TokenStr);
+      Result := tjsBraceOpen;
+      end;
+    ')':
+      begin
+      Inc(TokenStr);
+      Result := tjsBraceClose;
+      end;
+    '*':
+      begin
+      Inc(TokenStr);
+      If (TokenStr[0]='=') then
+        begin
+        Inc(TokenStr);
+        Result := tjsMulEq;
+        end
+      else
+        Result := tjsMul;
+      end;
+    '+':
+      begin
+      Inc(TokenStr);
+      If (TokenStr[0]='=') then
+        begin
+        Inc(TokenStr);
+        Result := tjsPlusEq;
+        end
+      else If (TokenStr[0]='+') then
+        begin
+        Inc(TokenStr);
+        Result := tjsPlusPlus;
+        end
+      else
+        Result := tjsPlus;
+      end;
+    ',':
+      begin
+        Inc(TokenStr);
+        Result := tjsComma;
+      end;
+    '-':
+      begin
+      Inc(TokenStr);
+      If (TokenStr[0]='=') then
+        begin
+        Inc(TokenStr);
+        Result:=tjsMinusEq
+        end
+      else If (TokenStr[0]='-') then
+        begin
+        Inc(TokenStr);
+        Result:=tjsMinusMinus
+        end
+      else if (TokenStr[0] in ['0'..'9']) then
+        begin
+        Result:=DoNumericLiteral;
+        If (Result=tjsNumber) then
+          FCurTokenString:='-'+FCurTokenString;
+        end
+      else
+        Result := tjsMinus;
+      end;
+    '.':
+      begin
+      Inc(TokenStr);
+      Result := tjsDot;
+      end;
+    ':':
+      begin
+      Inc(TokenStr);
+      Result := tjsColon;
+      end;
+    ';':
+      begin
+      Inc(TokenStr);
+      Result := tjsSemicolon;
+      end;
+    '<':
+      begin
+      Inc(TokenStr);
+      if TokenStr[0] = '=' then
+        begin
+        Inc(TokenStr);
+        Result := tjsLE;
+        end
+      else if TokenStr[0] = '<' then
+        begin
+        Inc(TokenStr);
+        if (TokenStr[0] = '=') then
+          begin
+          Inc(TokenStr);
+          Result := tjsLShiftEq;
+          end
+        else
+          Result := tjsLShift;
+        end
+      else
+        Result := tjsLT;
+      end;
+    '=':
+      begin
+      Inc(TokenStr);
+      if (TokenStr[0]='=') then
+        begin
+        Inc(TokenStr);
+        If (TokenStr[0]='=') then
+          begin
+          Inc(TokenStr);
+          Result:=tjsSEQ;
+          end
+        else
+          Result:=tjsEQ;
+        end
+      else
+        Result := tjsAssign;
+      end;
+    '!':
+      begin
+      Inc(TokenStr);
+      if (TokenStr[0]='=') then
+        begin
+        Inc(TokenStr);
+        If (TokenStr[0]='=') then
+          begin
+          Inc(TokenStr);
+          Result:=tjsSNE;
+          end
+        else
+          Result:=tjsNE;
+        end
+      else
+        Result:=tjsNot;// Error(SErrInvalidNonEqual);
+      end;
+    '~':
+      begin
+      Inc(TokenStr);
+      Result:=tjsInv;
+      end;
+    '>':
+      begin
+      Inc(TokenStr);
+      if TokenStr[0] = '=' then
+	begin
+        Inc(TokenStr);
+        Result:=tjsGE;
+        end
+      else if TokenStr[0] = '>' then
+  	begin
+        Inc(TokenStr);
+        if (TokenStr[0] = '>') then
+       	  begin
+          Inc(TokenStr);
+          if (TokenStr[0] = '=') then
+            begin
+            Inc(TokenStr);
+            Result:=tjsURSHIFTEQ;
+            end
+          else
+            Result:=tjsURSHIFT;
+          end
+        else if (TokenStr[0] = '=') then
+          begin
+          Inc(TokenStr);
+          Result:=tjsRSHIFTEq;
+          end
+        else
+          Result:=tjsRSHIFT;
+        end
+      else
+        Result := tjsGT;
+      end;
+    '[':
+      begin
+      Inc(TokenStr);
+      Result := tJSSquaredBraceOpen;
+      end;
+    ']':
+      begin
+      Inc(TokenStr);
+      Result := tJSSquaredBraceClose;
+      end;
+    '{':
+      begin
+      Inc(TokenStr);
+      Result := tJSCurlyBraceOpen;
+      end;
+    '}':
+      begin
+      Inc(TokenStr);
+      Result := tJSCurlyBraceClose;
+      end;
+   else
+     Result:=DoIdentifier;
+   end; // Case
+  Until (Not (Result in [tjsComment,tjsWhitespace])) or
+        ((Result=tjsComment) and ReturnComments) or
+        ((Result=tjsWhiteSpace) and ReturnWhiteSpace);
+  FCurToken:=Result;
+
+end;
+
+function TJSScanner.IsEndOfLine: Boolean;
+begin
+  Result:=(TokenStr=Nil) or (TokenStr[0] in [#0,#10,#13]);
+end;
+
+function TJSScanner.GetCurColumn: Integer;
+begin
+  Result := TokenStr - PChar(CurLine);
+end;
+
+{ TStreamLineReader }
+
+constructor TStreamLineReader.Create(AStream: TStream);
+begin
+  FStream:=AStream;
+  FBufPos:=0;
+  FBufLen:=0;
+end;
+
+function TStreamLineReader.IsEOF: Boolean;
+begin
+  Result:=(FBufPos>=FBufLen);
+  If Result then
+    begin
+    FillBuffer;
+    Result:=(FBufLen=0);
+    end;
+end;
+
+procedure TStreamLineReader.FillBuffer;
+
+begin
+  FBufLen:=FStream.Read(Buffer,SizeOf(Buffer)-1);
+  Buffer[FBufLen]:=0;
+  FBufPos:=0;
+end;
+
+function TStreamLineReader.ReadLine: string;
+
+Var
+  FPos,OLen,Len: Integer;
+  PRun : PByte;
+
+begin
+  FPos:=FBufPos;
+  SetLength(Result,0);
+  Repeat
+    PRun:=@Buffer[FBufPos];
+    While (FBufPos<FBufLen) and Not (PRun^ in [10,13]) do
+      begin
+      Inc(PRun);
+      Inc(FBufPos);
+      end;
+    If (FBufPos=FBufLen) then
+      begin
+      Len:=FBufPos-FPos;
+      If (Len>0) then
+        begin
+        Olen:=Length(Result);
+        SetLength(Result,OLen+Len);
+        Move(Buffer[FPos],Result[OLen+1],Len)
+        end;
+      FillBuffer;
+      end;
+  until (FBufPos=FBufLen) or (PRun^ in [10,13]);
+  Len:=FBufPos-FPos;
+  If (Len>0) then
+    begin
+    Olen:=Length(Result);
+    SetLength(Result,OLen+Len);
+    Move(Buffer[FPos],Result[OLen+1],Len)
+    end;
+  If (PRun^ in [10,13]) and (FBufPos<FBufLen) then
+    begin
+    Inc(FBufPos);
+    // Check #13#10
+    If (PRun^=13) then
+      begin
+      If (FBufPos=FBufLen) then
+        FillBuffer;
+      If (FBufPos<FBufLen) and (Buffer[FBufpos]=10) then
+        Inc(FBufPos);
+      end;
+    end;
+end;
+
+end.

+ 963 - 0
packages/fcl-js/src/jstree.pp

@@ -0,0 +1,963 @@
+unit jstree;
+
+{$mode objfpc}{$H+}
+
+interface
+
+uses
+  Classes, SysUtils, jsbase;
+
+Type
+  TJSElementFlag = (elIsConst,elIsConstValid);
+  TJSElementFlags = set of TJSElementFlag;
+
+  TJSFunctionBody = Class;
+
+  { TJSElement }
+
+  TJSObject = Class(TObject);
+
+  { TJSFuncDef }
+
+  TJSFuncDef = Class(TJSObject)
+  private
+    FBody: TJSFunctionBody;
+    FCache: TJSObject;
+    FCommon: TJSObject;
+    FIsEmpty: Boolean;
+    FName: String;
+    FNext: TJSFuncDef;
+    FParams: TStrings;
+    FSec: TObject;
+    procedure SetParams(const AValue: TStrings);
+  Public
+    Constructor Create;
+    Destructor Destroy; override;
+    Property Params : TStrings Read FParams Write SetParams;
+    Property Body : TJSFunctionBody Read FBody Write FBody;
+    Property Name : String Read FName Write FName;
+    Property Common : TJSObject Read FCommon Write FCommon;
+    Property Cache : TJSObject Read FCache write FCache;
+    Property Next : TJSFuncDef Read FNext Write FNext;
+    Property IsEmpty : Boolean Read FIsEmpty Write FIsEmpty;
+    Property SecurityDomain : TObject Read FSec Write FSec;
+  end;
+
+  TJSString = WideString;
+
+  TJSElement = Class (TJSObject)
+  private
+    FFlags: TJSElementFlags;
+    FLine: Integer;
+    FRow: Integer;
+    FSource: String;
+  Public
+    Constructor Create(ALine,ARow : Integer; Const ASource : String = ''); virtual;
+    Property Source : String Read FSource Write FSource;
+    Property Row : Integer Read FRow Write FRow;
+    Property Line : Integer Read FLine Write FLine;
+    Property Flags : TJSElementFlags Read FFlags Write FFlags;
+  end;
+  TJSElementClass = Class of TJSElement;
+
+  { TJSEmptyBlockStatement }
+
+  TJSEmptyBlockStatement = Class(TJSElement);
+  TJSEmptyStatement = Class(TJSElement);
+
+  { TJSLiteral }
+
+  TJSLiteral = Class(TJSElement)
+  private
+    FValue: TJSValue;
+  Public
+    Constructor Create(ALine,ARow : Integer; Const ASource : String = ''); override;
+    Destructor Destroy; override;
+    Property Value : TJSValue Read FValue Write FValue;
+  end;
+
+  { TJSStringLiteral }
+
+  TJSStringLiteral = Class(TJSElement)
+  private
+    FValue: TJSString;
+  Public
+    Property Value : TJSString Read FValue Write FValue;
+  end;
+
+  { TJSRegularExpressionLiteral }
+
+  TJSRegularExpressionLiteral = Class(TJSElement)
+  private
+    FPattern: TJSValue;
+    FPatternFlags: TJSValue;
+    FArgv : Array[0..1] of TJSValue;
+    function GetA(AIndex : integer): TJSValue;
+    procedure SetA(AIndex : integer; const AValue: TJSValue);
+  Public
+    Constructor Create(ALine,ARow : Integer; Const ASource : String = ''); override;
+    Destructor Destroy; override;
+    Property Pattern : TJSValue Read FPattern Write FPattern;
+    Property PatternFlags : TJSValue Read FPatternFlags Write FPatternFlags;
+    Property Argv[AIndex : integer] : TJSValue Read GetA Write SetA;
+  end;
+
+  { TJSPrimaryExpressionIdent }
+
+  TJSPrimaryExpressionIdent = Class(TJSElement)
+  private
+    FString: TJSString;
+  Public
+    Property AString : TJSString Read FString Write FString;
+  end;
+  TJSPrimaryExpressionThis = Class(TJSElement);
+
+  { TJSArrayLiteralElement }
+
+  TJSArrayLiteralElement = Class(TCollectionItem)
+  private
+    FExpr: TJSelement;
+    FFindex: Integer;
+  Public
+    Destructor Destroy; override;
+    Property Expr : TJSelement Read FExpr Write FExpr;
+    Property ElementIndex : Integer Read FFindex Write FFIndex;
+  end;
+
+  { TJSArrayLiteralElements }
+
+  TJSArrayLiteralElements = Class(TCollection)
+  private
+    function GetE(AIndex : Integer): TJSArrayLiteralElement;
+    procedure SetE(AIndex : Integer; const AValue: TJSArrayLiteralElement);
+  Public
+    Function AddElement : TJSArrayLiteralElement;
+    Property Elements[AIndex : Integer] : TJSArrayLiteralElement Read GetE Write SetE; default;
+  end;
+
+  { TJSArrayLiteral }
+
+  TJSArrayLiteral = Class(TJSElement)
+  private
+    FElements: TJSArrayLiteralElements;
+  Public
+    Constructor Create(ALine,ARow : Integer; const ASource : String = ''); override;
+    Destructor Destroy; override;
+    Property Elements : TJSArrayLiteralElements Read FElements;
+  end;
+
+  { TJSObjectLiteralElement }
+
+  TJSObjectLiteralElement = Class(TCollectionItem)
+  private
+    FExpr: TJSelement;
+    FName: TJSString;
+  Public
+    Destructor Destroy; override;
+    Property Expr : TJSelement Read FExpr Write FExpr;
+    Property Name : TJSString Read FName Write FName;
+  end;
+
+  { TJSObjectLiteralElements }
+
+  TJSObjectLiteralElements = Class(TCollection)
+  private
+    function GetE(AIndex : Integer): TJSObjectLiteralElement;
+    procedure SetE(AIndex : Integer; const AValue: TJSObjectLiteralElement);
+  Public
+    Function AddElement : TJSObjectLiteralElement;
+    Property Elements[AIndex : Integer] : TJSObjectLiteralElement Read GetE Write SetE; default;
+  end;
+
+  { TJSObjectLiteral }
+
+  TJSObjectLiteral = Class(TJSElement)
+  private
+    FElements: TJSObjectLiteralElements;
+  Public
+    Constructor Create(ALine,ARow : Integer; const ASource : String = ''); override;
+    Destructor Destroy; override;
+    Property Elements : TJSObjectLiteralElements Read FElements;
+  end;
+
+  { TJSArguments }
+
+  TJSArguments = Class(TJSArrayLiteral);
+
+  { TJSMemberExpression }
+
+  TJSMemberExpression = Class(TJSElement)
+  private
+    FMexpr: TJSElement;
+  Public
+    Destructor Destroy; override;
+    Property Mexpr : TJSElement Read FMexpr Write FMexpr;
+  end;
+
+  { TJSNewMemberExpression }
+
+  TJSNewMemberExpression = Class(TJSMemberExpression)
+  private
+    FArgs: TJSArguments;
+  Public
+    Destructor Destroy; override;
+    Property Args : TJSArguments Read FArgs Write FArgs;
+  end;
+
+  { TJSDotMemberExpression }
+
+  TJSDotMemberExpression = Class(TJSMemberExpression)
+  private
+    FName: TJSString;
+  Public
+    Property Name : TJSString Read FName Write FName;
+  end;
+
+  { TJSBracketMemberExpression }
+
+  TJSBracketMemberExpression = Class(TJSMemberExpression)
+  private
+    FName: TJSElement;
+  Public
+    Destructor Destroy; override;
+    Property Name : TJSElement Read FName Write FName;
+  end;
+
+  { TJSCallExpression }
+
+  TJSCallExpression = Class(TJSElement)
+  private
+    FArgs: TJSArguments;
+    FExpr: TJSElement;
+  Public
+    Destructor Destroy; override;
+    Property Expr : TJSElement Read FExpr Write FExpr;
+    Property Args : TJSArguments Read FArgs Write FArgs;
+  end;
+
+  { TJSUnary }
+
+  TJSUnary = Class(TJSElement)
+  private
+    FA: TJSElement;
+  Public
+    Destructor Destroy; override;
+    Property A : TJSElement Read FA Write FA;
+  end;
+
+  { TJSVariableStatement }
+  TJSVariableStatement = Class(TJSUnary);
+  TJSExpressionStatement = Class(TJSUnary);
+  TJSThrowStatement = Class(TJSUnary);
+  TJSUnaryExpression = Class(TJSUnary);
+  TJSUnaryDeleteExpression = Class(TJSUnaryExpression);
+  TJSUnaryVoidExpression = Class(TJSUnaryExpression);
+  TJSUnaryTypeOfExpression = Class(TJSUnaryExpression);
+  TJSUnaryPrePlusPlusExpression = Class(TJSUnaryExpression);
+  TJSUnaryPreMinusMinusExpression = Class(TJSUnaryExpression);
+  TJSUnaryPlusExpression = Class(TJSUnaryExpression);
+  TJSUnaryMinusExpression = Class(TJSUnaryExpression);
+  TJSUnaryInvExpression = Class(TJSUnaryExpression);
+  TJSUnaryNotExpression = Class(TJSUnaryExpression);
+  TJSUnaryPostPlusPlusExpression = Class(TJSUnaryExpression);
+  TJSUnaryPostMinusMinusExpression = Class(TJSUnaryExpression);
+
+
+
+  { TJSBinary }
+
+  TJSBinary = Class(TJSElement)
+  private
+    FA: TJSElement;
+    FB: TJSElement;
+  Public
+    Destructor Destroy; override;
+    Property A : TJSElement Read FA Write FA;
+    Property B : TJSElement Read FB Write FB;
+  end;
+
+  { TJSStatementList }
+
+  TJSStatementList = Class(TJSBinary); // A->first statement, B->next in list, chained.
+  TJSVariableDeclarationList = Class(TJSBinary);
+  TJSWithStatement = Class(TJSBinary); // A-> with expression, B->statement(s)
+  TJSLogicalOrExpression = Class (TJSBinary);
+  TJSLogicalAndExpression = Class (TJSBinary);
+  TJSBitwiseAndExpression = Class (TJSBinary);
+  TJSBitwiseOrExpression = Class (TJSBinary);
+  TJSBitwiseXOrExpression = Class (TJSBinary);
+  TJSEqualityExpression = Class (TJSBinary);
+  TJSEqualityExpressionEQ = Class(TJSEqualityExpression);
+  TJSEqualityExpressionNE = Class(TJSEqualityExpression);
+  TJSEqualityExpressionSEQ = Class(TJSEqualityExpression);
+  TJSEqualityExpressionSNE = Class(TJSEqualityExpression);
+  TJSRelationalExpression = Class(TJSBinary);
+  TJSRelationalExpressionLT = Class(TJSRelationalExpression);
+  TJSRelationalExpressionGT = Class(TJSRelationalExpression);
+  TJSRelationalExpressionLE = Class(TJSRelationalExpression);
+  TJSRelationalExpressionGE = Class(TJSRelationalExpression);
+  TJSRelationalExpressionIn = Class(TJSRelationalExpression);
+  TJSRelationalExpressionInstanceOf = Class(TJSRelationalExpression);
+  TJSShiftExpression = Class(TJSBinary);
+  TJSLShiftExpression = Class(TJSShiftExpression);
+  TJSRShiftExpression = Class(TJSShiftExpression);
+  TJSURShiftExpression = Class(TJSShiftExpression);
+  TJSAdditiveExpression = Class(TJSBinary);
+  TJSAdditiveExpressionPlus = Class(TJSAdditiveExpression);
+  TJSAdditiveExpressionMinus = Class(TJSAdditiveExpression);
+  TJSMultiplicativeExpression = Class(TJSBinary);
+  TJSMultiplicativeExpressionMul = Class(TJSMultiplicativeExpression);
+  TJSMultiplicativeExpressionDiv = Class(TJSMultiplicativeExpression);
+  TJSMultiplicativeExpressionMod = Class(TJSMultiplicativeExpression);
+  TJSCommaExpression = Class(TJSBinary);
+
+  { TJSConditionalExpression }
+
+  TJSConditionalExpression = Class(TJSElement)
+  private
+    FA: TJSElement;
+    FB: TJSElement;
+    FC: TJSElement;
+  Public
+    Destructor Destroy; override;
+    Property A : TJSElement Read FA Write FA;
+    Property B : TJSElement Read FB Write FB;
+    Property C : TJSElement Read FC Write FC;
+  end;
+
+  { TJSAssignStatement }
+
+  TJSAssignStatement = Class(TJSElement)
+  private
+    FExpr: TJSElement;
+    FLHS: TJSElement;
+  Public
+    Destructor Destroy; override;
+    Property Expr : TJSElement Read FExpr Write FExpr;
+    Property LHS : TJSElement Read FLHS Write FLHS;
+  end;
+
+  TJSSimpleAssignStatement = Class(TJSAssignStatement);
+  TJSMulEqAssignStatement = Class(TJSAssignStatement);
+  TJSDivEqAssignStatement = Class(TJSAssignStatement);
+  TJSModEqAssignStatement = Class(TJSAssignStatement);
+  TJSAddEqAssignStatement = Class(TJSAssignStatement);
+  TJSSubEqAssignStatement = Class(TJSAssignStatement);
+  TJSLShiftEqAssignStatement = Class(TJSAssignStatement);
+  TJSRShiftEqAssignStatement = Class(TJSAssignStatement);
+  TJSURShiftEqAssignStatement = Class(TJSAssignStatement);
+  TJSANDEqAssignStatement = Class(TJSAssignStatement);
+  TJSOREqAssignStatement = Class(TJSAssignStatement);
+  TJSXOREqAssignStatement = Class(TJSAssignStatement);
+
+  { TJSVarDeclaration }
+
+  TJSVarDeclaration = Class(TJSElement)
+  private
+    FInit: TJSElement;
+    FName: String;
+  Public
+    Destructor Destroy; override;
+    Property Name : String Read FName Write FName;
+    Property Init : TJSElement Read FInit Write FInit;
+  end;
+
+  { TJSIfStatement }
+
+  TJSIfStatement = Class(TJSElement)
+  private
+    FBFalse: TJSElement;
+    FBTrue: TJSElement;
+    FCond: TJSElement;
+  Public
+    Destructor Destroy; override;
+    Property Cond : TJSElement Read FCond Write FCond;
+    Property btrue : TJSElement Read FBTrue Write FBTrue;
+    Property bfalse : TJSElement Read FBFalse Write FBFalse;
+  end;
+
+  { TJSWhileStatement }
+
+  { TJSTargetStatement }
+
+  TJSTargetStatement = Class(TJSElement)
+  private
+    FTarget: Cardinal;
+  Public
+    Property Target : Cardinal Read FTarget Write FTarget;
+  end;
+
+  { TJSBodyStatement }
+
+  TJSBodyStatement = Class(TJSTargetStatement)
+  private
+    FBody: TJSElement;
+  Public
+    Destructor Destroy; override;
+    Property body : TJSElement Read FBody Write FBody;
+  end;
+
+  { TJSCondLoopStatement }
+
+  TJSCondLoopStatement = Class(TJSBodyStatement)
+  private
+    FCond: TJSElement;
+  Public
+    Destructor Destroy; override;
+    Property Cond : TJSElement Read FCond Write FCond;
+  end;
+
+  TJSWhileStatement = Class(TJSCondLoopStatement)
+  end;
+
+  { TJSForStatement }
+
+  TJSForStatement = Class(TJSCondLoopStatement)
+  private
+    FIncr: TJSElement;
+    FInit: TJSElement;
+  Public
+    Destructor Destroy; override;
+    Property Incr : TJSElement Read FIncr Write FIncr;
+    Property Init : TJSElement Read FInit Write FInit;
+  end;
+
+  { TJSForInStatement }
+
+  TJSForInStatement = Class(TJSBodyStatement)
+  private
+    FLhs: TJSElement;
+    FList: TJSElement;
+  Public
+    Destructor Destroy; override;
+    Property LHS : TJSElement Read FLHS Write FLHS;
+    Property List : TJSElement Read FList Write FList;
+  end;
+
+  TJSContinueStatement = Class(TJSTargetStatement);
+
+  TJSBreakStatement = Class(TJSTargetStatement);
+
+  { TJSReturn }
+
+  TJSReturnStatement = Class(TJSElement)
+  private
+    FExpr: TJSElement;
+  Public
+    Destructor Destroy; override;
+    Property Expr : TJSElement Read FExpr Write FExpr;
+  end;
+
+  { TJSCaseElement }
+
+  TJSCaseElement = Class(TCollectionItem)
+  private
+    FBody: TJSElement;
+    FExpr: TJSelement;
+  Public
+    Destructor Destroy; override;
+    Property Expr : TJSelement Read FExpr Write FExpr;
+    Property Body : TJSElement Read FBody Write FBody;
+  end;
+
+  { TJSCaseElements }
+
+  TJSCaseElements = Class(TCollection)
+  private
+    function GetC(AIndex : Integer): TJSCaseElement;
+    procedure SetC(AIndex : Integer; const AValue: TJSCaseElement);
+  Public
+    Function AddCase : TJSCaseElement;
+    Property Cases[AIndex : Integer] : TJSCaseElement Read GetC Write SetC;
+  end;
+
+  { TJSSwitch }
+
+  TJSSwitchStatement = Class(TJSTargetStatement)
+  private
+    FCases: TJSCaseElements;
+    FCond: TJSelement;
+    FDefault: TJSCaseElement;
+  Public
+    Constructor Create(ALine,ARow : Integer; const ASource : String = ''); override;
+    Destructor Destroy; override;
+    Property Cond : TJSelement Read FCond Write FCond;
+    Property Cases : TJSCaseElements Read FCases;
+    Property TheDefault : TJSCaseelement Read FDefault Write FDefault;
+  end;
+
+  { TJSLabeledStatement }
+
+  TJSLabeledStatement = Class(TJSUnary)
+  private
+    FTarget: Integer;
+  Public
+    Property target: Integer Read FTarget Write FTarget;
+  end;
+
+  { TJSTryStatement }
+
+  TJSTryStatement = Class(TJSElement)
+  private
+    FBCatch: TJSElement;
+    FBFinally: TJSElement;
+    FBlock: TJSElement;
+    FIdent: TJSString;
+  Public
+    Destructor Destroy; override;
+    Property Block : TJSElement Read FBlock Write FBlock;
+    Property BCatch : TJSElement Read FBCatch Write FBCatch;
+    Property BFinally : TJSElement Read FBFinally Write FBFinally;
+    Property Ident : TJSString Read FIdent Write FIDent;
+  end;
+
+  TJSTryCatchFinallyStatement = Class(TJSTryStatement);
+  TJSTryCatchStatement = Class(TJSTryStatement);
+  TJSTryFinallyStatement = Class(TJSTryStatement);
+
+
+  { TJSFunction }
+
+  TJSFunctionDeclarationStatement = Class(TJSelement)
+  private
+    FFuncDef: TJSFuncDef;
+  Public
+    Destructor Destroy; override;
+    Property AFunction : TJSFuncDef Read FFuncDef Write FFuncDef;
+  end;
+
+  { TJSFunctionBody }
+
+  TJSFunctionBody = Class(TJSUnary)
+  private
+    FisProgram: Boolean;
+  Public
+    Property isProgram : Boolean Read FisProgram Write FIsProgram;
+  end;
+
+  { TJSElementNode }
+
+  TJSElementNode = Class(TCollectionItem)
+  private
+    FNode: TJSElement;
+  Public
+    Destructor Destroy; override;
+    Property Node : TJSElement Read FNode Write FNode;
+  end;
+
+  { TJSElementNodes }
+
+  TJSElementNodes = Class(TCollection)
+  private
+    function GetN(AIndex : Integer): TJSElementNode;
+    procedure SetN(AIndex : Integer; const AValue: TJSElementNode);
+  Public
+    Function AddNode : TJSElementNode;
+    Property Nodes[AIndex : Integer] : TJSElementNode Read GetN Write SetN; default;
+  end;
+
+  { TJSSourceElements }
+  TJSSourceElements = Class(TJSElement)
+  private
+    FFunctions: TJSElementNodes;
+    FStatements: TJSElementNodes;
+    FVars: TJSElementNodes;
+  Public
+    Constructor Create(ALine,ARow : Integer; const ASource : String = ''); override;
+    Destructor Destroy; override;
+    Property Statements : TJSElementNodes Read FStatements;
+    Property functions : TJSElementNodes Read FFunctions;
+    Property Vars : TJSElementNodes Read FVars;
+  end;
+
+
+implementation
+
+{ TJSElement }
+
+constructor TJSElement.Create(ALine, ARow: Integer; Const ASource: String = '');
+begin
+  FLine:=ALine;
+  FRow:=ARow;
+  FSource:=ASource;
+end;
+
+{ TJSRegularExpressionLiteral }
+
+function TJSRegularExpressionLiteral.GetA(AIndex : integer): TJSValue;
+begin
+  Result:=FArgv[AIndex];
+end;
+
+procedure TJSRegularExpressionLiteral.SetA(AIndex : integer;
+  const AValue: TJSValue);
+begin
+  FArgv[AIndex]:=Avalue;
+end;
+
+constructor TJSRegularExpressionLiteral.Create(ALine, ARow: Integer;
+  const ASource: String);
+begin
+  inherited Create(ALine, ARow, ASource);
+  FPattern:=TJSValue.Create;
+  FPatternFlags:=TJSValue.Create;
+end;
+
+destructor TJSRegularExpressionLiteral.Destroy;
+begin
+  FreeAndNil(FPattern);
+  FreeAndNil(FPatternFlags);
+  Inherited Destroy;
+end;
+
+{ TJSArrayLiteralElements }
+
+function TJSArrayLiteralElements.GetE(AIndex : Integer): TJSArrayLiteralElement;
+begin
+  Result:=TJSArrayLiteralElement(Items[AIndex]);
+end;
+
+procedure TJSArrayLiteralElements.SetE(AIndex : Integer;
+  const AValue: TJSArrayLiteralElement);
+begin
+  Items[AIndex]:=AValue;
+end;
+
+function TJSArrayLiteralElements.AddElement: TJSArrayLiteralElement;
+begin
+  Result:=TJSArrayLiteralElement(Add);
+end;
+
+{ TJSArrayLiteral }
+
+constructor TJSArrayLiteral.Create(ALine, ARow: Integer; Const ASource: String = '');
+begin
+  inherited Create(ALine, ARow, ASource);
+  FElements:=TJSArrayLiteralElements.Create(TJSArrayLiteralElement);
+end;
+
+destructor TJSArrayLiteral.Destroy;
+begin
+  FreeAndNil(FElements);
+  inherited Destroy;
+end;
+
+{ TJSObjectLiteralElements }
+
+function TJSObjectLiteralElements.GetE(AIndex : Integer
+  ): TJSObjectLiteralElement;
+begin
+  Result:=TJSObjectLiteralElement(Items[AIndex]);
+end;
+
+procedure TJSObjectLiteralElements.SetE(AIndex : Integer;
+  const AValue: TJSObjectLiteralElement);
+begin
+  Items[AIndex]:=AValue;
+end;
+
+function TJSObjectLiteralElements.AddElement: TJSObjectLiteralElement;
+begin
+  Result:=TJSObjectLiteralElement(Add);
+end;
+
+{ TJSObjectLiteral }
+
+constructor TJSObjectLiteral.Create(ALine, ARow: Integer; const ASource: String = '');
+begin
+  inherited Create(ALine, ARow, ASource);
+  FElements:=TJSObjectLiteralElements.Create(TJSObjectLiteralElement);
+end;
+
+destructor TJSObjectLiteral.Destroy;
+begin
+  FreeAndNil(FElements);
+  inherited Destroy;
+end;
+
+{ TJSObjectLiteralElement }
+
+destructor TJSObjectLiteralElement.Destroy;
+begin
+  FreeAndNil(Fexpr);
+  inherited Destroy;
+end;
+
+{ TJSArrayLiteralElement }
+
+destructor TJSArrayLiteralElement.Destroy;
+begin
+  FreeAndNil(Fexpr);
+  inherited Destroy;
+end;
+
+{ TJSNewMemberExpression }
+
+destructor TJSNewMemberExpression.Destroy;
+begin
+  FreeAndNil(FArgs);
+  inherited Destroy;
+end;
+
+{ TJSMemberExpression }
+
+destructor TJSMemberExpression.Destroy;
+begin
+  FreeAndNil(FMExpr);
+  inherited Destroy;
+end;
+
+{ TJSCallExpression }
+
+destructor TJSCallExpression.Destroy;
+begin
+  FreeAndNil(FExpr);
+  FreeAndNil(FArgs);
+  inherited Destroy;
+end;
+
+{ TJSUnary }
+
+destructor TJSUnary.Destroy;
+begin
+  FreeAndNil(FA);
+  inherited Destroy;
+end;
+
+{ TJSBinary }
+
+destructor TJSBinary.Destroy;
+begin
+  FreeAndNil(FB);
+  FreeAndNil(FA);
+  inherited Destroy;
+end;
+
+{ TJSConditionalExpression }
+
+destructor TJSConditionalExpression.Destroy;
+begin
+  FreeAndNil(FB);
+  FreeAndNil(FA);
+  FreeAndNil(FC);
+  inherited Destroy;
+end;
+
+{ TJSAssign }
+
+destructor TJSAssignStatement.Destroy;
+begin
+  FreeAndNil(FLHS);
+  FreeAndNil(FExpr);
+  inherited Destroy;
+end;
+
+{ TJSVarDeclaration }
+
+
+destructor TJSVarDeclaration.Destroy;
+begin
+  FreeAndNil(FInit);
+  inherited Destroy;
+end;
+
+{ TJSIfStatement }
+
+destructor TJSIfStatement.Destroy;
+begin
+  FreeAndNil(FCond);
+  FreeAndNil(FBTrue);
+  FreeAndNil(FBFalse);
+  inherited Destroy;
+end;
+
+{ TJSBodyStatement }
+
+destructor TJSBodyStatement.Destroy;
+begin
+  FreeAndNil(FBody);
+  inherited Destroy;
+end;
+
+{ TJSCondLoopStatement }
+
+destructor TJSCondLoopStatement.Destroy;
+begin
+  FreeAndNil(FCond);
+  inherited Destroy;
+end;
+
+{ TJSForStatement }
+
+destructor TJSForStatement.Destroy;
+begin
+  FreeAndNil(FIncr);
+  FreeAndNil(FInit);
+  inherited Destroy;
+end;
+
+{ TJSForInStatement }
+
+destructor TJSForInStatement.Destroy;
+begin
+  FreeAndNil(FList);
+  FreeAndNil(FLHS);
+  inherited Destroy;
+end;
+
+
+{ TJSReturn }
+
+destructor TJSReturnStatement.Destroy;
+begin
+  FreeAndNil(FExpr);
+  inherited Destroy;
+end;
+
+{ TJSCaseElement }
+
+destructor TJSCaseElement.Destroy;
+begin
+  FreeAndNil(FExpr);
+  FreeAndNil(FBody);
+  inherited Destroy;
+end;
+
+{ TJSSwitch }
+
+constructor TJSSwitchStatement.Create(ALine, ARow: Integer; const ASource: String);
+begin
+  inherited Create(ALine, ARow, ASource);
+  FCases:=TJSCaseElements.Create(TJSCaseElement);
+end;
+
+destructor TJSSwitchStatement.Destroy;
+begin
+  FreeAndNil(FCases);
+  FreeAndNil(FDefault);
+  FreeAndNil(FCond);
+  inherited Destroy;
+end;
+
+{ TJSCaseElements }
+
+function TJSCaseElements.GetC(AIndex : Integer): TJSCaseElement;
+begin
+  Result:=TJSCaseElement(Items[AIndex]);
+end;
+
+procedure TJSCaseElements.SetC(AIndex : Integer; const AValue: TJSCaseElement);
+begin
+  Items[AIndex]:=AValue;
+end;
+
+function TJSCaseElements.AddCase: TJSCaseElement;
+begin
+  Result:=TJSCaseElement(Add);
+end;
+
+{ TJSTryStatement }
+
+destructor TJSTryStatement.Destroy;
+begin
+  FreeAndNil(FBlock);
+  FreeAndNil(FBCatch);
+  FreeAndNil(FBFinally);
+  inherited Destroy;
+end;
+
+{ TJSSourceElements }
+
+constructor TJSSourceElements.Create(ALine, ARow: Integer; const ASource: String
+  );
+begin
+  inherited Create(ALine, ARow, ASource);
+  FStatements:=TJSElementNodes.Create(TJSElementNode);
+  FFunctions:=TJSElementNodes.Create(TJSElementNode);
+  FVars:=TJSElementNodes.Create(TJSElementNode);
+end;
+
+destructor TJSSourceElements.Destroy;
+begin
+  FreeAndNil(FStatements);
+  FreeAndNil(FFunctions);
+  FreeAndNil(FVars);
+  inherited Destroy;
+end;
+
+{ TJSElementNodes }
+
+function TJSElementNodes.GetN(AIndex : Integer): TJSElementNode;
+begin
+  Result:=TJSElementNode(Items[Aindex])
+end;
+
+procedure TJSElementNodes.SetN(AIndex : Integer; const AValue: TJSElementNode);
+begin
+  Items[AIndex]:=Avalue;
+end;
+
+function TJSElementNodes.AddNode: TJSElementNode;
+begin
+  Result:=TJSElementNode(Add);
+end;
+
+{ TJSFunction }
+
+destructor TJSFunctionDeclarationStatement.Destroy;
+begin
+  FreeAndNil(FFuncDef);
+  inherited Destroy;
+end;
+
+{ TJSElementNode }
+
+destructor TJSElementNode.Destroy;
+begin
+  //FreeAndNil(FNode);
+  inherited Destroy;
+end;
+
+{ TJSFuncDef }
+
+procedure TJSFuncDef.SetParams(const AValue: TStrings);
+begin
+  if FParams=AValue then exit;
+  FParams.Assign(AValue);
+end;
+
+constructor TJSFuncDef.Create;
+begin
+  FParams:=TStringList.Create;
+end;
+
+destructor TJSFuncDef.Destroy;
+begin
+  FreeAndNil(FParams);
+  inherited Destroy;
+end;
+
+{ TJSBracketMemberExpression }
+
+destructor TJSBracketMemberExpression.Destroy;
+begin
+  FreeAndNil(FName);
+  inherited Destroy;
+end;
+
+{ TJSLiteral }
+
+constructor TJSLiteral.Create(ALine, ARow: Integer; const ASource: String);
+begin
+  FValue:=TJSValue.Create;
+  inherited Create(ALine, ARow, ASource);
+end;
+
+destructor TJSLiteral.Destroy;
+begin
+  FreeAndNil(FValue);
+  Inherited;
+end;
+
+end.
+

+ 2311 - 0
packages/fcl-js/tests/tcparser.pp

@@ -0,0 +1,2311 @@
+unit tcparser;
+
+{$mode objfpc}{$H+}
+
+interface
+
+uses
+  Classes, SysUtils, fpcunit, testutils, testregistry, jsParser, jstree, jsbase;
+
+type
+
+  { TTestJSParser }
+
+  TTestJSParser= class(TTestCase)
+  Private
+    FSource : TStringStream;
+    FParser : TJSParser;
+    FSE : TJSSourceElements;
+    FToFree: TJSElement;
+  protected
+    procedure SetUp; override; 
+    procedure TearDown; override;
+    Procedure CreateParser(Const ASource : string);
+    Procedure CheckClass(E : TJSElement; C : TJSElementClass);
+    Procedure AssertEquals(Const AMessage : String; Expected, Actual : TJSType); overload;
+    Function  GetSourceElements : TJSSourceElements;
+    Function  GetVars : TJSElementNodes;
+    Function  GetStatements : TJSElementNodes;
+    Function  GetFunctions : TJSElementNodes;
+    Function  GetFirstStatement : TJSElement;
+    Function  GetFirstVar : TJSElement;
+    Function  GetExpressionStatement : TJSExpressionStatement;
+  published
+    procedure TestEmpty;
+    procedure TestSimple;
+    procedure TestSimpleExpressionNumericalLiteral;
+    procedure TestSimpleExpressionStringLiteral;
+    procedure TestSimpleExpressionBooleanLiteralFalse;
+    procedure TestSimpleExpressionBooleanLiteralTrue;
+    procedure TestSimpleExpressionIdentifier;
+    procedure TestSimpleExpressionNull;
+    procedure TestAssignExpressionNumerical;
+    procedure TestAssignExpressionNull;
+    procedure TestAssignExpressionString;
+    procedure TestAssignExpressionBooleanFalse;
+    procedure TestAssignExpressionBooleanTrue;
+    procedure TestAssignExpressionIdent;
+    procedure TestAssignExpressionPlus;
+    procedure TestAssignExpressionMinus;
+    procedure TestAssignExpressionDiv;
+    procedure TestAssignExpressionMul;
+    procedure TestAssignExpressionMod;
+    procedure TestAssignExpressionAnd;
+    procedure TestAssignExpressionOr;
+    procedure TestAssignExpressionXOr;
+    procedure TestAssignExpressionLShift;
+    procedure TestAssignExpressionRShift;
+    procedure TestAssignExpressionURShift;
+    procedure TestExpressionPlus;
+    procedure TestExpressionSub;
+    procedure TestExpressionMul;
+    procedure TestExpressionDiv;
+    procedure TestExpressionMod;
+    procedure TestExpressionLShift;
+    procedure TestExpressionRShift;
+    procedure TestExpressionURShift;
+    procedure TestExpressionPostPlusPlus;
+    procedure TestExpressionPostMinusMinus;
+    procedure TestExpressionPreMinusMinus;
+    procedure TestExpressionPrePlusPlus;
+    procedure TestExpressionPrecedenceMulPlus;
+    procedure TestExpressionPrecedencePlusMul;
+    procedure TestExpressionPrecedenceMulMinus;
+    procedure TestExpressionPrecedenceMinusMul;
+    procedure TestExpressionPrecedenceDivPlus;
+    procedure TestExpressionPrecedencePlusDiv;
+    procedure TestExpressionPrecedenceModPlus;
+    procedure TestExpressionPrecedencePlusMod;
+    procedure TestExpressionPrecedencePlusPostPlusPlus;
+    procedure TestExpressionPrecedencePlusPostMinusMinus;
+    procedure TestExpressionPrecedenceMulPostMinusMinus;
+    procedure TestExpressionPrecedenceMulPostPlusPlus;
+    procedure TestExpressionPrecedenceMulPreMinusMinus;
+    procedure TestExpressionPrecedenceMulPrePlusPlus;
+    procedure TestExpressionPrecedencePlusPreMinusMinus;
+    procedure TestExpressionPrecedencePlusPrePlusPlus;
+    procedure TestExpressionPrecedencePlusInv;
+    procedure TestExpressionPrecedenceMulInv;
+    procedure TestExpressionPrecedenceMulNot;
+    procedure TestExpressionPrecedencePlusNot;
+    procedure TestExpressionPrecedenceBraceMulPlus;
+    procedure TestExpressionPrecedenceBracePlusMul;
+    procedure TestExpressionFunction;
+    procedure TestFunctionCallNoArgs;
+    procedure TestFunctionCallOneArg;
+    procedure TestFunctionCallTwoArgs;
+    procedure TestArrayExpressionNumericalArgs;
+    procedure TestArrayExpressionStringArgs;
+    procedure TestArrayExpressionIdentArgs;
+    Procedure TestVarDeclarationSimple;
+    procedure TestVarDeclarationDouble;
+    procedure TestVarDeclarationSimpleInit;
+    procedure TestVarDeclarationDoubleInit;
+    procedure TestBlockEmpty;
+    procedure TestBlockEmptyStatement;
+    procedure TestBlockSimpleStatement;
+    procedure TestFunctionDeclarationEmpty;
+    procedure TestFunctionDeclarationWithArgs;
+    procedure TestFunctionDeclarationWithBody;
+    procedure TestIfSimple;
+    procedure TestIfElseSimple;
+    procedure TestIfEmptyBlock;
+    procedure TestIfEmptyBlockElse;
+    procedure TestWhileSimple;
+    procedure TestWhileBlock;
+    procedure TestDoWhileSimple;
+    procedure TestDoWhileBlock;
+    procedure TestForEmpty;
+    procedure TestForEmptyBody;
+    procedure TestForSimpleBody;
+    procedure TestTryCatch;
+    procedure TestTryCatchFinally;
+    procedure TestTryFinally;
+    procedure TestThrow;
+    procedure TestReturn;
+  end;
+
+implementation
+
+uses typinfo;
+
+procedure TTestJSParser.AssertEquals(const AMessage: String; Expected,
+  Actual: TJSType);
+
+Var
+  NE,NA : String;
+
+begin
+  NE:=GetEnumName(TypeInfo(TJSType),Ord(Expected));
+  NA:=GetEnumName(TypeInfo(TJSType),Ord(Actual));
+  AssertEquals(AMessage,NE,NA);
+end;
+
+function TTestJSParser.GetFirstStatement: TJSElement;
+
+Var
+  E : TJSElementNodes;
+  N : TJSElement;
+  X : TJSExpressionStatement;
+
+begin
+  E:=GetStatements;
+  AssertNotNull('Have statements',E);
+  AssertEquals('1 statement',1,E.Count);
+  Result:=E.Nodes[0].Node;
+  AssertNotNull('First statement assigned',Result);
+end;
+
+function TTestJSParser.GetFirstVar: TJSElement;
+Var
+  E : TJSElementNodes;
+  N : TJSElement;
+  X : TJSExpressionStatement;
+begin
+  E:=GetVars;
+  AssertNotNull('Have statements',E);
+  Writeln('Count : ',E.Count);
+  If (E.Count=0) then
+    Fail('Zero variables defined');
+  Result:=E.Nodes[0].Node;
+  AssertNotNull('First variable declaration',Result);
+end;
+
+function TTestJSParser.GetExpressionStatement: TJSExpressionStatement;
+
+Var
+  N : TJSElement;
+  X : TJSExpressionStatement;
+
+begin
+  N:=GetFirstStatement;
+  CheckClass(N,TJSExpressionStatement);
+  Result:=TJSExpressionStatement(N);
+end;
+
+
+procedure TTestJSParser.TestSimple;
+
+Var
+  E : TJSElementNodes;
+  N : TJSElement;
+  X : TJSExpressionStatement;
+
+begin
+  CreateParser('1;');
+  E:=GetStatements;
+  AssertNotNull('Have statements',E);
+  AssertEquals('1 statement',1,E.Count);
+  N:=E.Nodes[0].Node;
+  AssertNotNull('First statement assigned',N);
+  AssertNotNull('First statement assigned',N);
+  CheckClass(N,TJSExpressionStatement);
+  X:=TJSExpressionStatement(N);
+  AssertNotNull('Expression statement assigned',X.A);
+  CheckClass(X.A,TJSLiteral);
+end;
+
+procedure TTestJSParser.TestSimpleExpressionNumericalLiteral;
+Var
+  X : TJSExpressionStatement;
+
+begin
+  CreateParser('1;');
+  X:=GetExpressionStatement;
+  AssertNotNull('Expression statement assigned',X.A);
+  CheckClass(X.A,TJSLiteral);
+  AssertNotNull('Expression value assigned',TJSLiteral(X.A).Value);
+  AssertEquals('Expression value type correct', jstNumber,TJSLiteral(X.A).Value.ValueType);
+  AssertEquals('Expression value correct', 1.0,TJSLiteral(X.A).Value.AsNumber);
+end;
+
+procedure TTestJSParser.TestSimpleExpressionStringLiteral;
+
+Var
+  X : TJSExpressionStatement;
+
+begin
+  CreateParser('"string";');
+  X:=GetExpressionStatement;
+  AssertNotNull('Expression statement assigned',X.A);
+  CheckClass(X.A,TJSLiteral);
+  AssertNotNull('Expression value assigned',TJSLiteral(X.A).Value);
+  AssertEquals('Expression value type correct', jstString,TJSLiteral(X.A).Value.ValueType);
+  AssertEquals('Expression value correct', 'string',TJSLiteral(X.A).Value.AsString);
+end;
+
+procedure TTestJSParser.TestSimpleExpressionBooleanLiteralFalse;
+
+Var
+  X : TJSExpressionStatement;
+
+begin
+  CreateParser('false;');
+  X:=GetExpressionStatement;
+  AssertNotNull('Expression statement assigned',X.A);
+  CheckClass(X.A,TJSLiteral);
+  AssertNotNull('Expression value assigned',TJSLiteral(X.A).Value);
+  AssertEquals('Expression value type correct', jstBoolean,TJSLiteral(X.A).Value.ValueType);
+  AssertEquals('Expression value correct', False, TJSLiteral(X.A).Value.AsBoolean);
+end;
+
+procedure TTestJSParser.TestSimpleExpressionIdentifier;
+
+Var
+  X : TJSExpressionStatement;
+
+begin
+  CreateParser('Something;');
+  X:=GetExpressionStatement;
+  AssertNotNull('Expression statement assigned',X.A);
+  CheckClass(X.A,TJSPrimaryExpressionIdent);
+  AssertEquals('Expression value assigned','Something',TJSPrimaryExpressionIdent(X.A).AString);
+end;
+
+procedure TTestJSParser.TestSimpleExpressionNull;
+
+Var
+  X : TJSExpressionStatement;
+begin
+    CreateParser('null;');
+    X:=GetExpressionStatement;
+    AssertNotNull('Expression statement assigned',X.A);
+    CheckClass(X.A,TJSLiteral);
+    AssertNotNull('Expression value assigned',TJSLiteral(X.A).Value);
+    AssertEquals('Expression value type correct', jstNull,TJSLiteral(X.A).Value.ValueType);
+    AssertEquals('Expression value correct', True, TJSLiteral(X.A).Value.IsNull);
+end;
+
+procedure TTestJSParser.TestAssignExpressionNumerical;
+
+Var
+  X : TJSExpressionStatement;
+  SA : TJSSimpleAssignStatement;
+begin
+  CreateParser('a=1;');
+  X:=GetExpressionStatement;
+  AssertNotNull('Expression statement assigned',X.A);
+  CheckClass(X.A,TJSSimpleAssignStatement);
+  SA:=TJSSimpleAssignStatement(X.A);
+  AssertNotNull('Assignment LHS assigned',SA.LHS);
+  CheckClass(SA.LHS,TJSPrimaryExpressionIdent);
+  AssertEquals('Expression LHS name correct', 'a',TJSPrimaryExpressionIdent(SA.LHS).AString);
+  AssertNotNull('Assignment Expression assigned',SA.Expr);
+  CheckClass(SA.EXPR,TJSLiteral);
+  AssertEquals('Expression value type correct', jstNumber,TJSLiteral(SA.Expr).Value.ValueType);
+  AssertEquals('Expression value correct', 1.0, TJSLiteral(SA.Expr).Value.AsNumber);
+end;
+
+procedure TTestJSParser.TestAssignExpressionString;
+
+Var
+  X : TJSExpressionStatement;
+  SA : TJSSimpleAssignStatement;
+begin
+  CreateParser('a="string";');
+  X:=GetExpressionStatement;
+  AssertNotNull('Expression statement assigned',X.A);
+  CheckClass(X.A,TJSSimpleAssignStatement);
+  SA:=TJSSimpleAssignStatement(X.A);
+  AssertNotNull('Assignment LHS assigned',SA.LHS);
+  CheckClass(SA.LHS,TJSPrimaryExpressionIdent);
+  AssertEquals('Expression LHS name correct', 'a',TJSPrimaryExpressionIdent(SA.LHS).AString);
+  AssertNotNull('Assignment Expression assigned',SA.Expr);
+  CheckClass(SA.EXPR,TJSLiteral);
+  AssertEquals('Expression value type correct', jstString,TJSLiteral(SA.Expr).Value.ValueType);
+  AssertEquals('Expression value correct', 'string', TJSLiteral(SA.Expr).Value.AsString);
+end;
+
+procedure TTestJSParser.TestAssignExpressionBooleanFalse;
+
+Var
+  X : TJSExpressionStatement;
+  SA : TJSSimpleAssignStatement;
+begin
+  CreateParser('a=false;');
+  X:=GetExpressionStatement;
+  AssertNotNull('Expression statement assigned',X.A);
+  CheckClass(X.A,TJSSimpleAssignStatement);
+  SA:=TJSSimpleAssignStatement(X.A);
+  AssertNotNull('Assignment LHS assigned',SA.LHS);
+  CheckClass(SA.LHS,TJSPrimaryExpressionIdent);
+  AssertEquals('Expression LHS name correct', 'a',TJSPrimaryExpressionIdent(SA.LHS).AString);
+  AssertNotNull('Assignment Expression assigned',SA.Expr);
+  CheckClass(SA.EXPR,TJSLiteral);
+  AssertEquals('Expression value type correct', jstBoolean,TJSLiteral(SA.Expr).Value.ValueType);
+  AssertEquals('Expression value correct', False, TJSLiteral(SA.Expr).Value.AsBoolean);
+end;
+
+procedure TTestJSParser.TestAssignExpressionBooleanTrue;
+Var
+  X : TJSExpressionStatement;
+  SA : TJSSimpleAssignStatement;
+begin
+  CreateParser('a=true;');
+  X:=GetExpressionStatement;
+  AssertNotNull('Expression statement assigned',X.A);
+  CheckClass(X.A,TJSSimpleAssignStatement);
+  SA:=TJSSimpleAssignStatement(X.A);
+  AssertNotNull('Assignment LHS assigned',SA.LHS);
+  CheckClass(SA.LHS,TJSPrimaryExpressionIdent);
+  AssertEquals('Expression LHS name correct', 'a',TJSPrimaryExpressionIdent(SA.LHS).AString);
+  AssertNotNull('Assignment Expression assigned',SA.Expr);
+  CheckClass(SA.EXPR,TJSLiteral);
+  AssertEquals('Expression value type correct', jstBoolean,TJSLiteral(SA.Expr).Value.ValueType);
+  AssertEquals('Expression value correct', True, TJSLiteral(SA.Expr).Value.AsBoolean);
+end;
+
+procedure TTestJSParser.TestAssignExpressionNull;
+
+Var
+  X : TJSExpressionStatement;
+  SA : TJSSimpleAssignStatement;
+begin
+  CreateParser('a=null;');
+  X:=GetExpressionStatement;
+  AssertNotNull('Expression statement assigned',X.A);
+  CheckClass(X.A,TJSSimpleAssignStatement);
+  SA:=TJSSimpleAssignStatement(X.A);
+  AssertNotNull('Assignment LHS assigned',SA.LHS);
+  CheckClass(SA.LHS,TJSPrimaryExpressionIdent);
+  AssertEquals('Expression LHS name correct', 'a',TJSPrimaryExpressionIdent(SA.LHS).AString);
+  AssertNotNull('Assignment Expression assigned',SA.Expr);
+  CheckClass(SA.EXPR,TJSLiteral);
+  AssertEquals('Expression value type correct', jstNull,TJSLiteral(SA.Expr).Value.ValueType);
+  AssertEquals('Expression value correct', True, TJSLiteral(SA.Expr).Value.IsNull);
+end;
+
+procedure TTestJSParser.TestAssignExpressionIdent;
+Var
+  X : TJSExpressionStatement;
+  SA : TJSSimpleAssignStatement;
+begin
+  CreateParser('a=b;');
+  X:=GetExpressionStatement;
+  AssertNotNull('Expression statement assigned',X.A);
+  CheckClass(X.A,TJSSimpleAssignStatement);
+  SA:=TJSSimpleAssignStatement(X.A);
+  AssertNotNull('Assignment LHS assigned',SA.LHS);
+  CheckClass(SA.LHS,TJSPrimaryExpressionIdent);
+  AssertEquals('Expression LHS name correct', 'a',TJSPrimaryExpressionIdent(SA.LHS).AString);
+  AssertNotNull('Assignment Expression assigned',SA.Expr);
+  CheckClass(SA.EXPR,TJSPrimaryExpressionIdent);
+  AssertEquals('Expression value type correct', 'b',TJSPrimaryExpressionIdent(SA.Expr).AString);
+end;
+
+procedure TTestJSParser.TestAssignExpressionPlus;
+
+Var
+  X : TJSExpressionStatement;
+  SA : TJSAddEqAssignStatement;
+
+begin
+  CreateParser('a+=1;');
+  X:=GetExpressionStatement;
+  AssertNotNull('Expression statement assigned',X.A);
+  CheckClass(X.A,TJSAddEqAssignStatement);
+  SA:=TJSAddEqAssignStatement(X.A);
+  AssertNotNull('Assignment LHS assigned',SA.LHS);
+  CheckClass(SA.LHS,TJSPrimaryExpressionIdent);
+  AssertEquals('Expression LHS name correct', 'a',TJSPrimaryExpressionIdent(SA.LHS).AString);
+  AssertNotNull('Assignment Expression assigned',SA.Expr);
+  CheckClass(SA.EXPR,TJSLiteral);
+  AssertEquals('Expression value type correct', jstNumber,TJSLiteral(SA.Expr).Value.ValueType);
+  AssertEquals('Expression value correct', 1.0, TJSLiteral(SA.Expr).Value.AsNumber);
+end;
+
+procedure TTestJSParser.TestAssignExpressionMinus;
+
+Var
+  X : TJSExpressionStatement;
+  SA : TJSSubEqAssignStatement;
+
+begin
+  CreateParser('a-=1;');
+  X:=GetExpressionStatement;
+  AssertNotNull('Expression statement assigned',X.A);
+  CheckClass(X.A,TJSSubEqAssignStatement);
+  SA:=TJSSubEqAssignStatement(X.A);
+  AssertNotNull('Assignment LHS assigned',SA.LHS);
+  CheckClass(SA.LHS,TJSPrimaryExpressionIdent);
+  AssertEquals('Expression LHS name correct', 'a',TJSPrimaryExpressionIdent(SA.LHS).AString);
+  AssertNotNull('Assignment Expression assigned',SA.Expr);
+  CheckClass(SA.EXPR,TJSLiteral);
+  AssertEquals('Expression value type correct', jstNumber,TJSLiteral(SA.Expr).Value.ValueType);
+  AssertEquals('Expression value correct', 1.0, TJSLiteral(SA.Expr).Value.AsNumber);
+end;
+
+procedure TTestJSParser.TestAssignExpressionMul;
+
+Var
+  X : TJSExpressionStatement;
+  SA : TJSMulEqAssignStatement;
+
+begin
+  CreateParser('a*=1;');
+  X:=GetExpressionStatement;
+  AssertNotNull('Expression statement assigned',X.A);
+  CheckClass(X.A,TJSMulEqAssignStatement);
+  SA:=TJSMulEqAssignStatement(X.A);
+  AssertNotNull('Assignment LHS assigned',SA.LHS);
+  CheckClass(SA.LHS,TJSPrimaryExpressionIdent);
+  AssertEquals('Expression LHS name correct', 'a',TJSPrimaryExpressionIdent(SA.LHS).AString);
+  AssertNotNull('Assignment Expression assigned',SA.Expr);
+  CheckClass(SA.EXPR,TJSLiteral);
+  AssertEquals('Expression value type correct', jstNumber,TJSLiteral(SA.Expr).Value.ValueType);
+  AssertEquals('Expression value correct', 1.0, TJSLiteral(SA.Expr).Value.AsNumber);
+end;
+
+procedure TTestJSParser.TestAssignExpressionDiv;
+
+Var
+  X : TJSExpressionStatement;
+  SA : TJSDivEqAssignStatement;
+
+begin
+  CreateParser('a/=1;');
+  X:=GetExpressionStatement;
+  AssertNotNull('Expression statement assigned',X.A);
+  CheckClass(X.A,TJSDivEqAssignStatement);
+  SA:=TJSDivEqAssignStatement(X.A);
+  AssertNotNull('Assignment LHS assigned',SA.LHS);
+  CheckClass(SA.LHS,TJSPrimaryExpressionIdent);
+  AssertEquals('Expression LHS name correct', 'a',TJSPrimaryExpressionIdent(SA.LHS).AString);
+  AssertNotNull('Assignment Expression assigned',SA.Expr);
+  CheckClass(SA.EXPR,TJSLiteral);
+  AssertEquals('Expression value type correct', jstNumber,TJSLiteral(SA.Expr).Value.ValueType);
+  AssertEquals('Expression value correct', 1.0, TJSLiteral(SA.Expr).Value.AsNumber);
+end;
+
+procedure TTestJSParser.TestAssignExpressionMod;
+
+Var
+  X : TJSExpressionStatement;
+  SA : TJSModEqAssignStatement;
+
+begin
+  CreateParser('a%=1;');
+  X:=GetExpressionStatement;
+  AssertNotNull('Expression statement assigned',X.A);
+  CheckClass(X.A,TJSModEqAssignStatement);
+  SA:=TJSModEqAssignStatement(X.A);
+  AssertNotNull('Assignment LHS assigned',SA.LHS);
+  CheckClass(SA.LHS,TJSPrimaryExpressionIdent);
+  AssertEquals('Expression LHS name correct', 'a',TJSPrimaryExpressionIdent(SA.LHS).AString);
+  AssertNotNull('Assignment Expression assigned',SA.Expr);
+  CheckClass(SA.EXPR,TJSLiteral);
+  AssertEquals('Expression value type correct', jstNumber,TJSLiteral(SA.Expr).Value.ValueType);
+  AssertEquals('Expression value correct', 1.0, TJSLiteral(SA.Expr).Value.AsNumber);
+end;
+
+procedure TTestJSParser.TestAssignExpressionAnd;
+
+Var
+  X : TJSExpressionStatement;
+  SA : TJSAndEqAssignStatement;
+
+begin
+  CreateParser('a&=1;');
+  X:=GetExpressionStatement;
+  AssertNotNull('Expression statement assigned',X.A);
+  CheckClass(X.A,TJSAndEqAssignStatement);
+  SA:=TJSAndEqAssignStatement(X.A);
+  AssertNotNull('Assignment LHS assigned',SA.LHS);
+  CheckClass(SA.LHS,TJSPrimaryExpressionIdent);
+  AssertEquals('Expression LHS name correct', 'a',TJSPrimaryExpressionIdent(SA.LHS).AString);
+  AssertNotNull('Assignment Expression assigned',SA.Expr);
+  CheckClass(SA.EXPR,TJSLiteral);
+  AssertEquals('Expression value type correct', jstNumber,TJSLiteral(SA.Expr).Value.ValueType);
+  AssertEquals('Expression value correct', 1.0, TJSLiteral(SA.Expr).Value.AsNumber);
+end;
+
+procedure TTestJSParser.TestAssignExpressionOr;
+
+Var
+  X : TJSExpressionStatement;
+  SA : TJSOrEqAssignStatement;
+
+begin
+  CreateParser('a|=1;');
+  X:=GetExpressionStatement;
+  AssertNotNull('Expression statement assigned',X.A);
+  CheckClass(X.A,TJSOrEqAssignStatement);
+  SA:=TJSOrEqAssignStatement(X.A);
+  AssertNotNull('Assignment LHS assigned',SA.LHS);
+  CheckClass(SA.LHS,TJSPrimaryExpressionIdent);
+  AssertEquals('Expression LHS name correct', 'a',TJSPrimaryExpressionIdent(SA.LHS).AString);
+  AssertNotNull('Assignment Expression assigned',SA.Expr);
+  CheckClass(SA.EXPR,TJSLiteral);
+  AssertEquals('Expression value type correct', jstNumber,TJSLiteral(SA.Expr).Value.ValueType);
+  AssertEquals('Expression value correct', 1.0, TJSLiteral(SA.Expr).Value.AsNumber);
+end;
+
+procedure TTestJSParser.TestAssignExpressionXOr;
+
+Var
+  X : TJSExpressionStatement;
+  SA : TJSXOrEqAssignStatement;
+
+begin
+  CreateParser('a^=1;');
+  X:=GetExpressionStatement;
+  AssertNotNull('Expression statement assigned',X.A);
+  CheckClass(X.A,TJSXOrEqAssignStatement);
+  SA:=TJSXOrEqAssignStatement(X.A);
+  AssertNotNull('Assignment LHS assigned',SA.LHS);
+  CheckClass(SA.LHS,TJSPrimaryExpressionIdent);
+  AssertEquals('Expression LHS name correct', 'a',TJSPrimaryExpressionIdent(SA.LHS).AString);
+  AssertNotNull('Assignment Expression assigned',SA.Expr);
+  CheckClass(SA.EXPR,TJSLiteral);
+  AssertEquals('Expression value type correct', jstNumber,TJSLiteral(SA.Expr).Value.ValueType);
+  AssertEquals('Expression value correct', 1.0, TJSLiteral(SA.Expr).Value.AsNumber);
+end;
+
+procedure TTestJSParser.TestAssignExpressionLShift;
+
+Var
+  X : TJSExpressionStatement;
+  SA : TJSLShiftEqAssignStatement;
+
+begin
+  CreateParser('a<<=1;');
+  X:=GetExpressionStatement;
+  AssertNotNull('Expression statement assigned',X.A);
+  CheckClass(X.A,TJSLShiftEqAssignStatement);
+  SA:=TJSLShiftEqAssignStatement(X.A);
+  AssertNotNull('Assignment LHS assigned',SA.LHS);
+  CheckClass(SA.LHS,TJSPrimaryExpressionIdent);
+  AssertEquals('Expression LHS name correct', 'a',TJSPrimaryExpressionIdent(SA.LHS).AString);
+  AssertNotNull('Assignment Expression assigned',SA.Expr);
+  CheckClass(SA.EXPR,TJSLiteral);
+  AssertEquals('Expression value type correct', jstNumber,TJSLiteral(SA.Expr).Value.ValueType);
+  AssertEquals('Expression value correct', 1.0, TJSLiteral(SA.Expr).Value.AsNumber);
+end;
+
+procedure TTestJSParser.TestAssignExpressionRShift;
+
+Var
+  X : TJSExpressionStatement;
+  SA : TJSRShiftEqAssignStatement;
+
+begin
+  CreateParser('a>>=1;');
+  X:=GetExpressionStatement;
+  AssertNotNull('Expression statement assigned',X.A);
+  CheckClass(X.A,TJSRShiftEqAssignStatement);
+  SA:=TJSRShiftEqAssignStatement(X.A);
+  AssertNotNull('Assignment LHS assigned',SA.LHS);
+  CheckClass(SA.LHS,TJSPrimaryExpressionIdent);
+  AssertEquals('Expression LHS name correct', 'a',TJSPrimaryExpressionIdent(SA.LHS).AString);
+  AssertNotNull('Assignment Expression assigned',SA.Expr);
+  CheckClass(SA.EXPR,TJSLiteral);
+  AssertEquals('Expression value type correct', jstNumber,TJSLiteral(SA.Expr).Value.ValueType);
+  AssertEquals('Expression value correct', 1.0, TJSLiteral(SA.Expr).Value.AsNumber);
+end;
+
+procedure TTestJSParser.TestAssignExpressionURShift;
+
+Var
+  X : TJSExpressionStatement;
+  SA : TJSURShiftEqAssignStatement;
+
+begin
+  CreateParser('a>>>=1;');
+  X:=GetExpressionStatement;
+  AssertNotNull('Expression statement assigned',X.A);
+  CheckClass(X.A,TJSURShiftEqAssignStatement);
+  SA:=TJSURShiftEqAssignStatement(X.A);
+  AssertNotNull('Assignment LHS assigned',SA.LHS);
+  CheckClass(SA.LHS,TJSPrimaryExpressionIdent);
+  AssertEquals('Expression LHS name correct', 'a',TJSPrimaryExpressionIdent(SA.LHS).AString);
+  AssertNotNull('Assignment Expression assigned',SA.Expr);
+  CheckClass(SA.EXPR,TJSLiteral);
+  AssertEquals('Expression value type correct', jstNumber,TJSLiteral(SA.Expr).Value.ValueType);
+  AssertEquals('Expression value correct', 1.0, TJSLiteral(SA.Expr).Value.AsNumber);
+end;
+
+procedure TTestJSParser.TestExpressionPlus;
+
+Var
+  X : TJSExpressionStatement;
+  E : TJSAdditiveExpressionPlus;
+
+begin
+  CreateParser('1+2;');
+  X:=GetExpressionStatement;
+  AssertNotNull('Expression statement assigned',X.A);
+  CheckClass(X.A,TJSAdditiveExpressionPlus);
+  E:=TJSAdditiveExpressionPlus(X.A);
+  AssertNotNull('Expression left operand assigned',E.A);
+  AssertNotNull('Expression right operand assigned',E.B);
+  CheckClass(E.A,TJSLiteral);
+  CheckClass(E.B,TJSLiteral);
+  AssertNotNull('Expression left operand value assigned',TJSLiteral(E.A).Value);
+  AssertEquals('Expression left operand type correct', jstNumber, TJSLiteral(E.A).Value.ValueType);
+  AssertEquals('Expression left operand value correct', 1.0, TJSLiteral(E.A).Value.AsNumber);
+  AssertNotNull('Expression right operand value assigned',TJSLiteral(E.B).Value);
+  AssertEquals('Expression left operand type correct', jstNumber, TJSLiteral(E.B).Value.ValueType);
+  AssertEquals('Expression right operand value correct', 2.0,TJSLiteral(E.B).Value.AsNumber);
+end;
+
+procedure TTestJSParser.TestExpressionSub;
+Var
+  X : TJSExpressionStatement;
+  E : TJSAdditiveExpressionMinus;
+
+begin
+  CreateParser('1 - 2;');
+  X:=GetExpressionStatement;
+  AssertNotNull('Expression statement assigned',X.A);
+  CheckClass(X.A,TJSAdditiveExpressionMinus);
+  E:=TJSAdditiveExpressionMinus(X.A);
+  AssertNotNull('Expression left operand assigned',E.A);
+  AssertNotNull('Expression right operand assigned',E.B);
+  CheckClass(E.A,TJSLiteral);
+  CheckClass(E.B,TJSLiteral);
+  AssertNotNull('Expression left operand value assigned',TJSLiteral(E.A).Value);
+  AssertEquals('Expression left operand type correct', jstNumber, TJSLiteral(E.A).Value.ValueType);
+  AssertEquals('Expression left operand value correct', 1.0, TJSLiteral(E.A).Value.AsNumber);
+  AssertNotNull('Expression right operand value assigned',TJSLiteral(E.B).Value);
+  AssertEquals('Expression left operand type correct', jstNumber, TJSLiteral(E.B).Value.ValueType);
+  AssertEquals('Expression right operand value correct', 2.0,TJSLiteral(E.B).Value.AsNumber);
+end;
+
+procedure TTestJSParser.TestExpressionMul;
+
+Var
+  X : TJSExpressionStatement;
+  E : TJSMultiplicativeExpressionMul;
+
+begin
+  CreateParser('1*2;');
+  X:=GetExpressionStatement;
+  AssertNotNull('Expression statement assigned',X.A);
+  CheckClass(X.A,TJSMultiplicativeExpressionMul);
+  E:=TJSMultiplicativeExpressionMul(X.A);
+  AssertNotNull('Expression left operand assigned',E.A);
+  AssertNotNull('Expression right operand assigned',E.B);
+  CheckClass(E.A,TJSLiteral);
+  CheckClass(E.B,TJSLiteral);
+  AssertNotNull('Expression left operand value assigned',TJSLiteral(E.A).Value);
+  AssertEquals('Expression left operand type correct', jstNumber, TJSLiteral(E.A).Value.ValueType);
+  AssertEquals('Expression left operand value correct', 1.0, TJSLiteral(E.A).Value.AsNumber);
+  AssertNotNull('Expression right operand value assigned',TJSLiteral(E.B).Value);
+  AssertEquals('Expression left operand type correct', jstNumber, TJSLiteral(E.B).Value.ValueType);
+  AssertEquals('Expression right operand value correct', 2.0,TJSLiteral(E.B).Value.AsNumber);
+end;
+
+procedure TTestJSParser.TestExpressionDiv;
+Var
+  X : TJSExpressionStatement;
+  E : TJSMultiplicativeExpressionDiv;
+
+begin
+  CreateParser('1/2;');
+  X:=GetExpressionStatement;
+  AssertNotNull('Expression statement assigned',X.A);
+  CheckClass(X.A,TJSMultiplicativeExpressionDiv);
+  E:=TJSMultiplicativeExpressionDiv(X.A);
+  AssertNotNull('Expression left operand assigned',E.A);
+  AssertNotNull('Expression right operand assigned',E.B);
+  CheckClass(E.A,TJSLiteral);
+  CheckClass(E.B,TJSLiteral);
+  AssertNotNull('Expression left operand value assigned',TJSLiteral(E.A).Value);
+  AssertEquals('Expression left operand type correct', jstNumber, TJSLiteral(E.A).Value.ValueType);
+  AssertEquals('Expression left operand value correct', 1.0, TJSLiteral(E.A).Value.AsNumber);
+  AssertNotNull('Expression right operand value assigned',TJSLiteral(E.B).Value);
+  AssertEquals('Expression left operand type correct', jstNumber, TJSLiteral(E.B).Value.ValueType);
+  AssertEquals('Expression right operand value correct', 2.0,TJSLiteral(E.B).Value.AsNumber);
+end;
+
+procedure TTestJSParser.TestExpressionMod;
+Var
+  X : TJSExpressionStatement;
+  E : TJSMultiplicativeExpressionMod;
+
+begin
+  CreateParser('1%2;');
+  X:=GetExpressionStatement;
+  AssertNotNull('Expression statement assigned',X.A);
+  CheckClass(X.A,TJSMultiplicativeExpressionMod);
+  E:=TJSMultiplicativeExpressionMod(X.A);
+  AssertNotNull('Expression left operand assigned',E.A);
+  AssertNotNull('Expression right operand assigned',E.B);
+  CheckClass(E.A,TJSLiteral);
+  CheckClass(E.B,TJSLiteral);
+  AssertNotNull('Expression left operand value assigned',TJSLiteral(E.A).Value);
+  AssertEquals('Expression left operand type correct', jstNumber, TJSLiteral(E.A).Value.ValueType);
+  AssertEquals('Expression left operand value correct', 1.0, TJSLiteral(E.A).Value.AsNumber);
+  AssertNotNull('Expression right operand value assigned',TJSLiteral(E.B).Value);
+  AssertEquals('Expression left operand type correct', jstNumber, TJSLiteral(E.B).Value.ValueType);
+  AssertEquals('Expression right operand value correct', 2.0,TJSLiteral(E.B).Value.AsNumber);
+end;
+
+procedure TTestJSParser.TestExpressionLShift;
+Var
+  X : TJSExpressionStatement;
+  E : TJSLShiftExpression;
+
+begin
+  CreateParser('1 << 2;');
+  X:=GetExpressionStatement;
+  AssertNotNull('Expression statement assigned',X.A);
+  CheckClass(X.A,TJSLShiftExpression);
+  E:=TJSLShiftExpression(X.A);
+  AssertNotNull('Expression left operand assigned',E.A);
+  AssertNotNull('Expression right operand assigned',E.B);
+  CheckClass(E.A,TJSLiteral);
+  CheckClass(E.B,TJSLiteral);
+  AssertNotNull('Expression left operand value assigned',TJSLiteral(E.A).Value);
+  AssertEquals('Expression left operand type correct', jstNumber, TJSLiteral(E.A).Value.ValueType);
+  AssertEquals('Expression left operand value correct', 1.0, TJSLiteral(E.A).Value.AsNumber);
+  AssertNotNull('Expression right operand value assigned',TJSLiteral(E.B).Value);
+  AssertEquals('Expression left operand type correct', jstNumber, TJSLiteral(E.B).Value.ValueType);
+  AssertEquals('Expression right operand value correct', 2.0,TJSLiteral(E.B).Value.AsNumber);
+end;
+
+procedure TTestJSParser.TestExpressionRShift;
+Var
+  X : TJSExpressionStatement;
+  E : TJSRShiftExpression;
+
+begin
+  CreateParser('1 >> 2;');
+  X:=GetExpressionStatement;
+  AssertNotNull('Expression statement assigned',X.A);
+  CheckClass(X.A,TJSRShiftExpression);
+  E:=TJSRShiftExpression(X.A);
+  AssertNotNull('Expression left operand assigned',E.A);
+  AssertNotNull('Expression right operand assigned',E.B);
+  CheckClass(E.A,TJSLiteral);
+  CheckClass(E.B,TJSLiteral);
+  AssertNotNull('Expression left operand value assigned',TJSLiteral(E.A).Value);
+  AssertEquals('Expression left operand type correct', jstNumber, TJSLiteral(E.A).Value.ValueType);
+  AssertEquals('Expression left operand value correct', 1.0, TJSLiteral(E.A).Value.AsNumber);
+  AssertNotNull('Expression right operand value assigned',TJSLiteral(E.B).Value);
+  AssertEquals('Expression left operand type correct', jstNumber, TJSLiteral(E.B).Value.ValueType);
+  AssertEquals('Expression right operand value correct', 2.0,TJSLiteral(E.B).Value.AsNumber);
+end;
+
+procedure TTestJSParser.TestExpressionURShift;
+Var
+  X : TJSExpressionStatement;
+  E : TJSURShiftExpression;
+
+begin
+  CreateParser('1 >>> 2;');
+  X:=GetExpressionStatement;
+  AssertNotNull('Expression statement assigned',X.A);
+  CheckClass(X.A,TJSURShiftExpression);
+  E:=TJSURShiftExpression(X.A);
+  AssertNotNull('Expression left operand assigned',E.A);
+  AssertNotNull('Expression right operand assigned',E.B);
+  CheckClass(E.A,TJSLiteral);
+  CheckClass(E.B,TJSLiteral);
+  AssertNotNull('Expression left operand value assigned',TJSLiteral(E.A).Value);
+  AssertEquals('Expression left operand type correct', jstNumber, TJSLiteral(E.A).Value.ValueType);
+  AssertEquals('Expression left operand value correct', 1.0, TJSLiteral(E.A).Value.AsNumber);
+  AssertNotNull('Expression right operand value assigned',TJSLiteral(E.B).Value);
+  AssertEquals('Expression left operand type correct', jstNumber, TJSLiteral(E.B).Value.ValueType);
+  AssertEquals('Expression right operand value correct', 2.0,TJSLiteral(E.B).Value.AsNumber);
+end;
+
+procedure TTestJSParser.TestExpressionPostPlusPlus;
+Var
+  X : TJSExpressionStatement;
+  E : TJSUnaryPostPlusPlusExpression;
+
+begin
+  CreateParser('1++;');
+  X:=GetExpressionStatement;
+  AssertNotNull('Expression statement assigned',X.A);
+  CheckClass(X.A,TJSUnaryPostPlusPlusExpression);
+  E:=TJSUnaryPostPlusPlusExpression(X.A);
+  AssertNotNull('Expression left operand assigned',E.A);
+  CheckClass(E.A,TJSLiteral);
+  AssertNotNull('Expression  operand value assigned',TJSLiteral(E.A).Value);
+  AssertEquals('Expression operand type correct', jstNumber, TJSLiteral(E.A).Value.ValueType);
+  AssertEquals('Expression operand value correct', 1.0, TJSLiteral(E.A).Value.AsNumber);
+end;
+
+procedure TTestJSParser.TestExpressionPostMinusMinus;
+Var
+  X : TJSExpressionStatement;
+  E : TJSUnaryPostMinusMinusExpression;
+
+begin
+  CreateParser('1--;');
+  X:=GetExpressionStatement;
+  AssertNotNull('Expression statement assigned',X.A);
+  CheckClass(X.A,TJSUnaryPostMinusMinusExpression);
+  E:=TJSUnaryPostMinusMinusExpression(X.A);
+  AssertNotNull('Expression left operand assigned',E.A);
+  CheckClass(E.A,TJSLiteral);
+  AssertNotNull('Expression  operand value assigned',TJSLiteral(E.A).Value);
+  AssertEquals('Expression operand type correct', jstNumber, TJSLiteral(E.A).Value.ValueType);
+  AssertEquals('Expression operand value correct', 1.0, TJSLiteral(E.A).Value.AsNumber);
+end;
+
+procedure TTestJSParser.TestExpressionPrePlusPlus;
+
+Var
+  X : TJSExpressionStatement;
+  E : TJSUnaryPrePlusPlusExpression;
+
+begin
+  CreateParser('++1;');
+  X:=GetExpressionStatement;
+  AssertNotNull('Expression statement assigned',X.A);
+  CheckClass(X.A,TJSUnaryPrePlusPlusExpression);
+  E:=TJSUnaryPrePlusPlusExpression(X.A);
+  AssertNotNull('Expression left operand assigned',E.A);
+  CheckClass(E.A,TJSLiteral);
+  AssertNotNull('Expression  operand value assigned',TJSLiteral(E.A).Value);
+  AssertEquals('Expression operand type correct', jstNumber, TJSLiteral(E.A).Value.ValueType);
+  AssertEquals('Expression operand value correct', 1.0, TJSLiteral(E.A).Value.AsNumber);
+end;
+
+
+procedure TTestJSParser.TestExpressionPreMinusMinus;
+
+Var
+  X : TJSExpressionStatement;
+  E : TJSUnaryPreMinusMinusExpression;
+
+begin
+  CreateParser('--1;');
+  X:=GetExpressionStatement;
+  AssertNotNull('Expression statement assigned',X.A);
+  CheckClass(X.A,TJSUnaryPreMinusMinusExpression);
+  E:=TJSUnaryPreMinusMinusExpression(X.A);
+  AssertNotNull('Expression left operand assigned',E.A);
+  CheckClass(E.A,TJSLiteral);
+  AssertNotNull('Expression  operand value assigned',TJSLiteral(E.A).Value);
+  AssertEquals('Expression operand type correct', jstNumber, TJSLiteral(E.A).Value.ValueType);
+  AssertEquals('Expression operand value correct', 1.0, TJSLiteral(E.A).Value.AsNumber);
+end;
+
+procedure TTestJSParser.TestExpressionPrecedenceMulPlus;
+
+Var
+  X : TJSExpressionStatement;
+  E : TJSAdditiveExpressionPlus;
+  R : TJSMultiplicativeExpressionMul;
+begin
+  CreateParser('2 * 3 + 4;');
+  X:=GetExpressionStatement;
+  AssertNotNull('Expression statement assigned',X.A);
+  CheckClass(X.A,TJSAdditiveExpressionPlus);
+  E:=TJSAdditiveExpressionPlus(X.A);
+  AssertNotNull('Expression left operand assigned',E.A);
+  AssertNotNull('Expression right operand assigned',E.B);
+  CheckClass(E.A,TJSMultiplicativeExpressionMul);
+  R:=TJSMultiplicativeExpressionMul(E.A);
+  CheckClass(E.B,TJSLiteral);
+  AssertNotNull('Multiplication left operand assigned',R.A);
+  AssertNotNull('Multiplication right operand assigned',R.B);
+  CheckClass(R.A,TJSLiteral);
+  CheckClass(R.B,TJSLiteral);
+  AssertEquals('Multiplication left operand type correct', jstNumber, TJSLiteral(R.A).Value.ValueType);
+  AssertEquals('Multiplication left operand value correct', 2.0, TJSLiteral(R.A).Value.AsNumber);
+  AssertEquals('Multiplication right operand type correct', jstNumber, TJSLiteral(R.B).Value.ValueType);
+  AssertEquals('Multiplication right operand value correct', 3.0, TJSLiteral(R.B).Value.AsNumber);
+  AssertNotNull('Addition right operand value assigned',TJSLiteral(E.B).Value);
+  AssertEquals('Addition left operand type correct', jstNumber, TJSLiteral(E.B).Value.ValueType);
+  AssertEquals('Expression right operand value correct', 4.0,TJSLiteral(E.B).Value.AsNumber);
+end;
+
+procedure TTestJSParser.TestExpressionPrecedenceBraceMulPlus;
+
+Var
+  X : TJSExpressionStatement;
+  E : TJSMultiplicativeExpressionMul;
+  R : TJSAdditiveExpressionPlus;
+
+begin
+  CreateParser('2 * (3 + 4);');
+  X:=GetExpressionStatement;
+  AssertNotNull('Expression statement assigned',X.A);
+  CheckClass(X.A,TJSMultiplicativeExpressionMul);
+  E:=TJSMultiplicativeExpressionMul(X.A);
+  AssertNotNull('Expression left operand assigned',E.A);
+  AssertNotNull('Expression right operand assigned',E.B);
+  CheckClass(E.B,TJSAdditiveExpressionPlus);
+  R:=TJSAdditiveExpressionPlus(E.B);
+  CheckClass(E.A,TJSLiteral);
+  AssertNotNull('Multiplication left operand assigned',R.A);
+  AssertNotNull('Multiplication right operand assigned',R.B);
+  CheckClass(R.A,TJSLiteral);
+  CheckClass(R.B,TJSLiteral);
+  AssertEquals('Multiplication left operand type correct', jstNumber, TJSLiteral(E.A).Value.ValueType);
+  AssertEquals('Multiplication left operand value correct', 2.0, TJSLiteral(E.A).Value.AsNumber);
+  AssertEquals('Addition left operand type correct', jstNumber, TJSLiteral(R.A).Value.ValueType);
+  AssertEquals('Multiplication right operand value correct', 3.0, TJSLiteral(R.A).Value.AsNumber);
+  AssertNotNull('Addition right operand value assigned',TJSLiteral(R.B).Value);
+  AssertEquals('Addition left operand type correct', jstNumber, TJSLiteral(R.B).Value.ValueType);
+  AssertEquals('Addition right operand value correct', 4.0,TJSLiteral(R.B).Value.AsNumber);
+end;
+
+procedure TTestJSParser.TestExpressionPrecedenceBracePlusMul;
+
+Var
+  X : TJSExpressionStatement;
+  E : TJSMultiplicativeExpressionMul;
+  R : TJSAdditiveExpressionPlus;
+
+begin
+  CreateParser('(3 + 4)*2;');
+  X:=GetExpressionStatement;
+  AssertNotNull('Expression statement assigned',X.A);
+  CheckClass(X.A,TJSMultiplicativeExpressionMul);
+  E:=TJSMultiplicativeExpressionMul(X.A);
+  AssertNotNull('Expression left operand assigned',E.A);
+  AssertNotNull('Expression right operand assigned',E.B);
+  CheckClass(E.A,TJSAdditiveExpressionPlus);
+  R:=TJSAdditiveExpressionPlus(E.A);
+  CheckClass(E.B,TJSLiteral);
+  AssertNotNull('Multiplication left operand assigned',R.A);
+  AssertNotNull('Multiplication right operand assigned',R.B);
+  CheckClass(R.A,TJSLiteral);
+  CheckClass(R.B,TJSLiteral);
+  AssertEquals('Multiplication left operand type correct', jstNumber, TJSLiteral(E.B).Value.ValueType);
+  AssertEquals('Multiplication left operand value correct', 2.0, TJSLiteral(E.B).Value.AsNumber);
+  AssertEquals('Addition left operand type correct', jstNumber, TJSLiteral(R.A).Value.ValueType);
+  AssertEquals('Multiplication right operand value correct', 3.0, TJSLiteral(R.A).Value.AsNumber);
+  AssertNotNull('Addition right operand value assigned',TJSLiteral(R.B).Value);
+  AssertEquals('Addition left operand type correct', jstNumber, TJSLiteral(R.B).Value.ValueType);
+  AssertEquals('Addition right operand value correct', 4.0,TJSLiteral(R.B).Value.AsNumber);
+end;
+
+procedure TTestJSParser.TestExpressionFunction;
+Var
+  X : TJSExpressionStatement;
+  A  : TJSSimpleAssignStatement;
+begin
+  CreateParser('a = function () {};');
+  X:=GetExpressionStatement;
+  CheckClass(X.A,TJSSimpleAssignStatement);
+  A:=TJSSimpleAssignStatement(X.A);
+  AssertNotNull('Have left operand',A.LHS);
+  CheckClass(A.LHS,TJSPrimaryExpressionIdent);
+  AssertEquals('Correct name for assignment LHS ','a',TJSPrimaryExpressionIdent(A.LHS).AString);
+end;
+
+procedure TTestJSParser.TestExpressionPrecedencePlusMul;
+
+Var
+  X : TJSExpressionStatement;
+  E : TJSAdditiveExpressionPlus;
+  R : TJSMultiplicativeExpressionMul;
+begin
+  CreateParser('4 + 2 * 3;');
+  X:=GetExpressionStatement;
+  AssertNotNull('Expression statement assigned',X.A);
+  CheckClass(X.A,TJSAdditiveExpressionPlus);
+  E:=TJSAdditiveExpressionPlus(X.A);
+  AssertNotNull('Expression left operand assigned',E.A);
+  AssertNotNull('Expression right operand assigned',E.B);
+  CheckClass(E.B,TJSMultiplicativeExpressionMul);
+  R:=TJSMultiplicativeExpressionMul(E.B);
+  CheckClass(E.A,TJSLiteral);
+  AssertNotNull('Multiplication left operand assigned',R.A);
+  AssertNotNull('Multiplication right operand assigned',R.B);
+  CheckClass(R.A,TJSLiteral);
+  CheckClass(R.B,TJSLiteral);
+  AssertEquals('Multiplication left operand type correct', jstNumber, TJSLiteral(R.A).Value.ValueType);
+  AssertEquals('Multiplication left operand value correct', 2.0, TJSLiteral(R.A).Value.AsNumber);
+  AssertEquals('Multiplication right operand type correct', jstNumber, TJSLiteral(R.B).Value.ValueType);
+  AssertEquals('Multiplication right operand value correct', 3.0, TJSLiteral(R.B).Value.AsNumber);
+  AssertNotNull('Addition left operand value assigned',TJSLiteral(E.A).Value);
+  AssertEquals('Addition left operand type correct', jstNumber, TJSLiteral(E.A).Value.ValueType);
+  AssertEquals('Addition left operand value correct', 4.0,TJSLiteral(E.A).Value.AsNumber);
+end;
+
+procedure TTestJSParser.TestExpressionPrecedenceMulMinus;
+
+Var
+  X : TJSExpressionStatement;
+  E : TJSAdditiveExpressionMinus;
+  R : TJSMultiplicativeExpressionMul;
+
+begin
+  CreateParser('2 * 3 - 4;');
+  X:=GetExpressionStatement;
+  AssertNotNull('Expression statement assigned',X.A);
+  CheckClass(X.A,TJSAdditiveExpressionMinus);
+  E:=TJSAdditiveExpressionMinus(X.A);
+  AssertNotNull('Expression left operand assigned',E.A);
+  AssertNotNull('Expression right operand assigned',E.B);
+  CheckClass(E.A,TJSMultiplicativeExpressionMul);
+  R:=TJSMultiplicativeExpressionMul(E.A);
+  CheckClass(E.B,TJSLiteral);
+  AssertNotNull('Multiplication left operand assigned',R.A);
+  AssertNotNull('Multiplication right operand assigned',R.B);
+  CheckClass(R.A,TJSLiteral);
+  CheckClass(R.B,TJSLiteral);
+  AssertEquals('Multiplication left operand type correct', jstNumber, TJSLiteral(R.A).Value.ValueType);
+  AssertEquals('Multiplication left operand value correct', 2.0, TJSLiteral(R.A).Value.AsNumber);
+  AssertEquals('Multiplication right operand type correct', jstNumber, TJSLiteral(R.B).Value.ValueType);
+  AssertEquals('Multiplication right operand value correct', 3.0, TJSLiteral(R.B).Value.AsNumber);
+  AssertNotNull('subtraction right operand value assigned',TJSLiteral(E.B).Value);
+  AssertEquals('subtraction right operand type correct', jstNumber, TJSLiteral(E.B).Value.ValueType);
+  AssertEquals('subtraction right operand value correct', 4.0,TJSLiteral(E.B).Value.AsNumber);
+end;
+
+procedure TTestJSParser.TestExpressionPrecedenceMinusMul;
+
+Var
+  X : TJSExpressionStatement;
+  E : TJSAdditiveExpressionMinus;
+  R : TJSMultiplicativeExpressionMul;
+begin
+  CreateParser('4 - 2 * 3;');
+  X:=GetExpressionStatement;
+  AssertNotNull('Expression statement assigned',X.A);
+  CheckClass(X.A,TJSAdditiveExpressionMinus);
+  E:=TJSAdditiveExpressionMinus(X.A);
+  AssertNotNull('Expression left operand assigned',E.A);
+  AssertNotNull('Expression right operand assigned',E.B);
+  CheckClass(E.B,TJSMultiplicativeExpressionMul);
+  R:=TJSMultiplicativeExpressionMul(E.B);
+  CheckClass(E.A,TJSLiteral);
+  AssertNotNull('Multiplication left operand assigned',R.A);
+  AssertNotNull('Multiplication right operand assigned',R.B);
+  CheckClass(R.A,TJSLiteral);
+  CheckClass(R.B,TJSLiteral);
+  AssertEquals('Multiplication left operand type correct', jstNumber, TJSLiteral(R.A).Value.ValueType);
+  AssertEquals('Multiplication left operand value correct', 2.0, TJSLiteral(R.A).Value.AsNumber);
+  AssertEquals('Multiplication right operand type correct', jstNumber, TJSLiteral(R.B).Value.ValueType);
+  AssertEquals('Multiplication right operand value correct', 3.0, TJSLiteral(R.B).Value.AsNumber);
+  AssertNotNull('Subtraction left operand value assigned',TJSLiteral(E.A).Value);
+  AssertEquals('Subtraction left operand type correct', jstNumber, TJSLiteral(E.A).Value.ValueType);
+  AssertEquals('Subtraction left operand value correct', 4.0,TJSLiteral(E.A).Value.AsNumber);
+end;
+
+procedure TTestJSParser.TestExpressionPrecedenceDivPlus;
+
+Var
+  X : TJSExpressionStatement;
+  E : TJSAdditiveExpressionPlus;
+  R : TJSMultiplicativeExpressionDiv;
+begin
+  CreateParser('2 / 3 + 4;');
+  X:=GetExpressionStatement;
+  AssertNotNull('Expression statement assigned',X.A);
+  CheckClass(X.A,TJSAdditiveExpressionPlus);
+  E:=TJSAdditiveExpressionPlus(X.A);
+  AssertNotNull('Expression left operand assigned',E.A);
+  AssertNotNull('Expression right operand assigned',E.B);
+  CheckClass(E.A,TJSMultiplicativeExpressionDiv);
+  R:=TJSMultiplicativeExpressionDiv(E.A);
+  CheckClass(E.B,TJSLiteral);
+  AssertNotNull('Div left operand assigned',R.A);
+  AssertNotNull('Div right operand assigned',R.B);
+  CheckClass(R.A,TJSLiteral);
+  CheckClass(R.B,TJSLiteral);
+  AssertEquals('Div left operand type correct', jstNumber, TJSLiteral(R.A).Value.ValueType);
+  AssertEquals('Div left operand value correct', 2.0, TJSLiteral(R.A).Value.AsNumber);
+  AssertEquals('Div right operand type correct', jstNumber, TJSLiteral(R.B).Value.ValueType);
+  AssertEquals('Div right operand value correct', 3.0, TJSLiteral(R.B).Value.AsNumber);
+  AssertNotNull('Addition right operand value assigned',TJSLiteral(E.B).Value);
+  AssertEquals('Addition right operand type correct', jstNumber, TJSLiteral(E.B).Value.ValueType);
+  AssertEquals('Addition right operand value correct', 4.0,TJSLiteral(E.B).Value.AsNumber);
+end;
+
+procedure TTestJSParser.TestExpressionPrecedencePlusDiv;
+
+Var
+  X : TJSExpressionStatement;
+  E : TJSAdditiveExpressionPlus;
+  R : TJSMultiplicativeExpressionDiv;
+
+begin
+  CreateParser('4 + 2 / 3;');
+  X:=GetExpressionStatement;
+  AssertNotNull('Expression statement assigned',X.A);
+  CheckClass(X.A,TJSAdditiveExpressionPlus);
+  E:=TJSAdditiveExpressionPlus(X.A);
+  AssertNotNull('Expression left operand assigned',E.A);
+  AssertNotNull('Expression right operand assigned',E.B);
+  CheckClass(E.B,TJSMultiplicativeExpressionDiv);
+  R:=TJSMultiplicativeExpressionDiv(E.B);
+  CheckClass(E.A,TJSLiteral);
+  AssertNotNull('Div left operand assigned',R.A);
+  AssertNotNull('Div right operand assigned',R.B);
+  CheckClass(R.A,TJSLiteral);
+  CheckClass(R.B,TJSLiteral);
+  AssertEquals('Div left operand type correct', jstNumber, TJSLiteral(R.A).Value.ValueType);
+  AssertEquals('Div left operand value correct', 2.0, TJSLiteral(R.A).Value.AsNumber);
+  AssertEquals('Div right operand type correct', jstNumber, TJSLiteral(R.B).Value.ValueType);
+  AssertEquals('Div right operand value correct', 3.0, TJSLiteral(R.B).Value.AsNumber);
+  AssertNotNull('Addition left operand value assigned',TJSLiteral(E.A).Value);
+  AssertEquals('Addition left operand type correct', jstNumber, TJSLiteral(E.A).Value.ValueType);
+  AssertEquals('Addition left operand value correct', 4.0,TJSLiteral(E.A).Value.AsNumber);
+end;
+
+procedure TTestJSParser.TestExpressionPrecedenceModPlus;
+
+Var
+  X : TJSExpressionStatement;
+  E : TJSAdditiveExpressionPlus;
+  R : TJSMultiplicativeExpressionMod;
+begin
+  CreateParser('2 % 3 + 4;');
+  X:=GetExpressionStatement;
+  AssertNotNull('Expression statement assigned',X.A);
+  CheckClass(X.A,TJSAdditiveExpressionPlus);
+  E:=TJSAdditiveExpressionPlus(X.A);
+  AssertNotNull('Expression left operand assigned',E.A);
+  AssertNotNull('Expression right operand assigned',E.B);
+  CheckClass(E.A,TJSMultiplicativeExpressionMod);
+  R:=TJSMultiplicativeExpressionMod(E.A);
+  CheckClass(E.B,TJSLiteral);
+  AssertNotNull('mod left operand assigned',R.A);
+  AssertNotNull('mod right operand assigned',R.B);
+  CheckClass(R.A,TJSLiteral);
+  CheckClass(R.B,TJSLiteral);
+  AssertEquals('mod left operand type correct', jstNumber, TJSLiteral(R.A).Value.ValueType);
+  AssertEquals('mod left operand value correct', 2.0, TJSLiteral(R.A).Value.AsNumber);
+  AssertEquals('mod right operand type correct', jstNumber, TJSLiteral(R.B).Value.ValueType);
+  AssertEquals('mod right operand value correct', 3.0, TJSLiteral(R.B).Value.AsNumber);
+  AssertNotNull('Addition right operand value assigned',TJSLiteral(E.B).Value);
+  AssertEquals('Addition right operand type correct', jstNumber, TJSLiteral(E.B).Value.ValueType);
+  AssertEquals('Addition right operand value correct', 4.0,TJSLiteral(E.B).Value.AsNumber);
+end;
+
+procedure TTestJSParser.TestExpressionPrecedencePlusMod;
+
+Var
+  X : TJSExpressionStatement;
+  E : TJSAdditiveExpressionPlus;
+  R : TJSMultiplicativeExpressionMod;
+
+begin
+  CreateParser('4 + 2 % 3;');
+  X:=GetExpressionStatement;
+  AssertNotNull('Expression statement assigned',X.A);
+  CheckClass(X.A,TJSAdditiveExpressionPlus);
+  E:=TJSAdditiveExpressionPlus(X.A);
+  AssertNotNull('Expression left operand assigned',E.A);
+  AssertNotNull('Expression right operand assigned',E.B);
+  CheckClass(E.B,TJSMultiplicativeExpressionMod);
+  R:=TJSMultiplicativeExpressionMod(E.B);
+  CheckClass(E.A,TJSLiteral);
+  AssertNotNull('Mod left operand assigned',R.A);
+  AssertNotNull('Mod right operand assigned',R.B);
+  CheckClass(R.A,TJSLiteral);
+  CheckClass(R.B,TJSLiteral);
+  AssertEquals('Mod left operand type correct', jstNumber, TJSLiteral(R.A).Value.ValueType);
+  AssertEquals('Mod left operand value correct', 2.0, TJSLiteral(R.A).Value.AsNumber);
+  AssertEquals('Mod right operand type correct', jstNumber, TJSLiteral(R.B).Value.ValueType);
+  AssertEquals('Mod right operand value correct', 3.0, TJSLiteral(R.B).Value.AsNumber);
+  AssertNotNull('Addition right operand value assigned',TJSLiteral(E.A).Value);
+  AssertEquals('Addition left operand type correct', jstNumber, TJSLiteral(E.A).Value.ValueType);
+  AssertEquals('Addition left operand value correct', 4.0,TJSLiteral(E.A).Value.AsNumber);
+end;
+
+procedure TTestJSParser.TestExpressionPrecedencePlusPostPlusPlus;
+
+Var
+  X : TJSExpressionStatement;
+  R : TJSUnaryPostPlusPlusExpression;
+  E : TJSAdditiveExpressionPlus;
+
+begin
+  CreateParser('4 + 2++;');
+  X:=GetExpressionStatement;
+  AssertNotNull('Expression statement assigned',X.A);
+  CheckClass(X.A,TJSAdditiveExpressionPlus);
+  E:=TJSAdditiveExpressionPlus(X.A);
+  AssertNotNull('Expression left operand assigned',E.A);
+  AssertNotNull('Expression right operand assigned',E.B);
+  CheckClass(E.B,TJSUnaryPostPlusPlusExpression);
+  R:=TJSUnaryPostPlusPlusExpression(E.B);
+  CheckClass(E.A,TJSLiteral);
+  AssertNotNull('++ operand assigned',R.A);
+  CheckClass(R.A,TJSLiteral);
+  AssertEquals('++ operand type correct', jstNumber, TJSLiteral(R.A).Value.ValueType);
+  AssertEquals('++ operand value correct', 2.0, TJSLiteral(R.A).Value.AsNumber);
+  AssertNotNull('Addition left operand value assigned',TJSLiteral(E.A).Value);
+  AssertEquals('Addition left operand type correct', jstNumber, TJSLiteral(E.A).Value.ValueType);
+  AssertEquals('Addition left operand value correct', 4.0,TJSLiteral(E.A).Value.AsNumber);
+end;
+
+procedure TTestJSParser.TestExpressionPrecedencePlusPostMinusMinus;
+Var
+  X : TJSExpressionStatement;
+  R : TJSUnaryPostMinusMinusExpression;
+  E : TJSAdditiveExpressionPlus;
+
+begin
+  CreateParser('4 + 2--;');
+  X:=GetExpressionStatement;
+  AssertNotNull('Expression statement assigned',X.A);
+  CheckClass(X.A,TJSAdditiveExpressionPlus);
+  E:=TJSAdditiveExpressionPlus(X.A);
+  AssertNotNull('Expression left operand assigned',E.A);
+  AssertNotNull('Expression right operand assigned',E.B);
+  CheckClass(E.B,TJSUnaryPostMinusMinusExpression);
+  R:=TJSUnaryPostMinusMinusExpression(E.B);
+  CheckClass(E.A,TJSLiteral);
+  AssertNotNull('-- operand assigned',R.A);
+  CheckClass(R.A,TJSLiteral);
+  AssertEquals('-- operand type correct', jstNumber, TJSLiteral(R.A).Value.ValueType);
+  AssertEquals('-- operand value correct', 2.0, TJSLiteral(R.A).Value.AsNumber);
+  AssertNotNull('Addition left operand value assigned',TJSLiteral(E.A).Value);
+  AssertEquals('Addition left operand type correct', jstNumber, TJSLiteral(E.A).Value.ValueType);
+  AssertEquals('Addition left operand value correct', 4.0,TJSLiteral(E.A).Value.AsNumber);
+end;
+
+procedure TTestJSParser.TestExpressionPrecedenceMulPostPlusPlus;
+
+Var
+  X : TJSExpressionStatement;
+  R : TJSUnaryPostPlusPlusExpression;
+  E : TJSMultiplicativeExpressionMul;
+
+begin
+  CreateParser('4 * 2++;');
+  X:=GetExpressionStatement;
+  AssertNotNull('Expression statement assigned',X.A);
+  CheckClass(X.A,TJSMultiplicativeExpressionMul);
+  E:=TJSMultiplicativeExpressionMul(X.A);
+  AssertNotNull('Expression left operand assigned',E.A);
+  AssertNotNull('Expression right operand assigned',E.B);
+  CheckClass(E.B,TJSUnaryPostPlusPlusExpression);
+  R:=TJSUnaryPostPlusPlusExpression(E.B);
+  CheckClass(E.A,TJSLiteral);
+  AssertNotNull('++operand assigned',R.A);
+  CheckClass(R.A,TJSLiteral);
+  AssertEquals('++ operand type correct', jstNumber, TJSLiteral(R.A).Value.ValueType);
+  AssertEquals('++ operand value correct', 2.0, TJSLiteral(R.A).Value.AsNumber);
+  AssertNotNull('Multiplication left operand value assigned',TJSLiteral(E.A).Value);
+  AssertEquals('Multiplication left operand type correct', jstNumber, TJSLiteral(E.A).Value.ValueType);
+  AssertEquals('Multiplication left operand value correct', 4.0,TJSLiteral(E.A).Value.AsNumber);
+end;
+
+procedure TTestJSParser.TestExpressionPrecedenceMulPostMinusMinus;
+Var
+  X : TJSExpressionStatement;
+  R : TJSUnaryPostMinusMinusExpression;
+  E : TJSMultiplicativeExpressionMul;
+
+begin
+  CreateParser('4 * 2--;');
+  X:=GetExpressionStatement;
+  AssertNotNull('Expression statement assigned',X.A);
+  CheckClass(X.A,TJSMultiplicativeExpressionMul);
+  E:=TJSMultiplicativeExpressionMul(X.A);
+  AssertNotNull('Expression left operand assigned',E.A);
+  AssertNotNull('Expression right operand assigned',E.B);
+  CheckClass(E.B,TJSUnaryPostMinusMinusExpression);
+  R:=TJSUnaryPostMinusMinusExpression(E.B);
+  CheckClass(E.A,TJSLiteral);
+  AssertNotNull('-- operand assigned',R.A);
+  CheckClass(R.A,TJSLiteral);
+  AssertEquals('-- operand type correct', jstNumber, TJSLiteral(R.A).Value.ValueType);
+  AssertEquals('-- operand value correct', 2.0, TJSLiteral(R.A).Value.AsNumber);
+  AssertNotNull('Multiplication left operand value assigned',TJSLiteral(E.A).Value);
+  AssertEquals('Multiplication left operand type correct', jstNumber, TJSLiteral(E.A).Value.ValueType);
+  AssertEquals('Multiplication left operand value correct', 4.0,TJSLiteral(E.A).Value.AsNumber);
+end;
+
+procedure TTestJSParser.TestExpressionPrecedencePlusPrePlusPlus;
+
+Var
+  X : TJSExpressionStatement;
+  R : TJSUnaryPrePlusPlusExpression;
+  E : TJSAdditiveExpressionPlus;
+
+begin
+  CreateParser('4 + ++2;');
+  X:=GetExpressionStatement;
+  AssertNotNull('Expression statement assigned',X.A);
+  CheckClass(X.A,TJSAdditiveExpressionPlus);
+  E:=TJSAdditiveExpressionPlus(X.A);
+  AssertNotNull('Expression left operand assigned',E.A);
+  AssertNotNull('Expression right operand assigned',E.B);
+  CheckClass(E.B,TJSUnaryPrePlusPlusExpression);
+  R:=TJSUnaryPrePlusPlusExpression(E.B);
+  CheckClass(E.A,TJSLiteral);
+  AssertNotNull('Multiplication left operand assigned',R.A);
+  CheckClass(R.A,TJSLiteral);
+  AssertEquals('++ operand type correct', jstNumber, TJSLiteral(R.A).Value.ValueType);
+  AssertEquals('++ operand value correct', 2.0, TJSLiteral(R.A).Value.AsNumber);
+  AssertNotNull('Addition left operand value assigned',TJSLiteral(E.A).Value);
+  AssertEquals('Addition left operand type correct', jstNumber, TJSLiteral(E.A).Value.ValueType);
+  AssertEquals('Addition left operand value correct', 4.0,TJSLiteral(E.A).Value.AsNumber);
+end;
+
+procedure TTestJSParser.TestExpressionPrecedencePlusInv;
+
+Var
+  X : TJSExpressionStatement;
+  R : TJSUnaryInvExpression;
+  E : TJSAdditiveExpressionPlus;
+
+begin
+    CreateParser('4 + ~2;');
+    X:=GetExpressionStatement;
+    AssertNotNull('Expression statement assigned',X.A);
+    CheckClass(X.A,TJSAdditiveExpressionPlus);
+    E:=TJSAdditiveExpressionPlus(X.A);
+    AssertNotNull('Expression left operand assigned',E.A);
+    AssertNotNull('Expression right operand assigned',E.B);
+    CheckClass(E.B,TJSUnaryInvExpression);
+    R:=TJSUnaryInvExpression(E.B);
+    CheckClass(E.A,TJSLiteral);
+    AssertNotNull('Multiplication left operand assigned',R.A);
+    CheckClass(R.A,TJSLiteral);
+    AssertEquals('inv operand type correct', jstNumber, TJSLiteral(R.A).Value.ValueType);
+    AssertEquals('inv operand value correct', 2.0, TJSLiteral(R.A).Value.AsNumber);
+    AssertNotNull('Addition left operand value assigned',TJSLiteral(E.A).Value);
+    AssertEquals('Addition left operand type correct', jstNumber, TJSLiteral(E.A).Value.ValueType);
+    AssertEquals('Addition left operand value correct', 4.0,TJSLiteral(E.A).Value.AsNumber);
+end;
+
+procedure TTestJSParser.TestExpressionPrecedenceMulInv;
+
+Var
+  X : TJSExpressionStatement;
+  R : TJSUnaryInvExpression;
+  E : TJSMultiplicativeExpressionMul;
+
+begin
+  CreateParser('4 * ~2;');
+  X:=GetExpressionStatement;
+  AssertNotNull('Expression statement assigned',X.A);
+  CheckClass(X.A,TJSMultiplicativeExpressionMul);
+  E:=TJSMultiplicativeExpressionMul(X.A);
+  AssertNotNull('Expression left operand assigned',E.A);
+  AssertNotNull('Expression right operand assigned',E.B);
+  CheckClass(E.B,TJSUnaryInvExpression);
+  R:=TJSUnaryInvExpression(E.B);
+  CheckClass(E.A,TJSLiteral);
+  AssertNotNull('Multiplication left operand assigned',R.A);
+  CheckClass(R.A,TJSLiteral);
+  AssertEquals('Inv operand type correct', jstNumber, TJSLiteral(R.A).Value.ValueType);
+  AssertEquals('Inv operand value correct', 2.0, TJSLiteral(R.A).Value.AsNumber);
+  AssertNotNull('Multiplication left operand value assigned',TJSLiteral(E.A).Value);
+  AssertEquals('Multiplication left operand type correct', jstNumber, TJSLiteral(E.A).Value.ValueType);
+  AssertEquals('Multiplication left operand value correct', 4.0,TJSLiteral(E.A).Value.AsNumber);
+end;
+
+procedure TTestJSParser.TestExpressionPrecedencePlusNot;
+
+Var
+  X : TJSExpressionStatement;
+  R : TJSUnaryNotExpression;
+  E : TJSAdditiveExpressionPlus;
+
+begin
+    CreateParser('4 + !2;');
+    X:=GetExpressionStatement;
+    AssertNotNull('Expression statement assigned',X.A);
+    CheckClass(X.A,TJSAdditiveExpressionPlus);
+    E:=TJSAdditiveExpressionPlus(X.A);
+    AssertNotNull('Expression left operand assigned',E.A);
+    AssertNotNull('Expression right operand assigned',E.B);
+    CheckClass(E.B,TJSUnaryNotExpression);
+    R:=TJSUnaryNotExpression(E.B);
+    CheckClass(E.A,TJSLiteral);
+    AssertNotNull('Multiplication left operand assigned',R.A);
+    CheckClass(R.A,TJSLiteral);
+    AssertEquals('Not operand type correct', jstNumber, TJSLiteral(R.A).Value.ValueType);
+    AssertEquals('Not operand value correct', 2.0, TJSLiteral(R.A).Value.AsNumber);
+    AssertNotNull('Addition left operand value assigned',TJSLiteral(E.A).Value);
+    AssertEquals('Addition left operand type correct', jstNumber, TJSLiteral(E.A).Value.ValueType);
+    AssertEquals('Addition left operand value correct', 4.0,TJSLiteral(E.A).Value.AsNumber);
+end;
+
+procedure TTestJSParser.TestFunctionCallNoArgs;
+
+Var
+  X : TJSExpressionStatement;
+  C : TJSCallExpression;
+
+begin
+  CreateParser('abc();');
+  X:=GetExpressionStatement;
+  CheckClass(X.A,TJSCallExpression);
+  C:=TJSCallExpression(X.A);
+  AssertEquals('No arguments',0,C.Args.Elements.Count);
+  AssertNotNull('Call function expression',C.Expr);
+  CheckClass(C.Expr,TJSPrimaryExpressionIdent);
+  AssertEquals('Function name correct','abc',TJSPrimaryExpressionIdent(C.Expr).AString);
+end;
+
+procedure TTestJSParser.TestFunctionCallOneArg;
+
+Var
+  X : TJSExpressionStatement;
+  C : TJSCallExpression;
+  E : TJSelement;
+
+begin
+  CreateParser('abc(d);');
+  X:=GetExpressionStatement;
+  CheckClass(X.A,TJSCallExpression);
+  C:=TJSCallExpression(X.A);
+  AssertNotNull('Call function expression',C.Expr);
+  CheckClass(C.Expr,TJSPrimaryExpressionIdent);
+  AssertEquals('Function name correct','abc',TJSPrimaryExpressionIdent(C.Expr).AString);
+  AssertEquals('1 argument',1,C.Args.Elements.Count);
+  E:=C.Args.Elements[0].Expr;
+  AssertNotNull('First argument expression',E);
+  CheckClass(E,TJSPrimaryExpressionIdent);
+  AssertEquals('First argument name correct','d',TJSPrimaryExpressionIdent(E).AString);
+end;
+
+procedure TTestJSParser.TestFunctionCallTwoArgs;
+
+Var
+  X : TJSExpressionStatement;
+  C : TJSCallExpression;
+  E : TJSelement;
+
+begin
+  CreateParser('abc(d,e);');
+  X:=GetExpressionStatement;
+  CheckClass(X.A,TJSCallExpression);
+  C:=TJSCallExpression(X.A);
+  AssertNotNull('Call function expression',C.Expr);
+  CheckClass(C.Expr,TJSPrimaryExpressionIdent);
+  AssertEquals('Function name correct','abc',TJSPrimaryExpressionIdent(C.Expr).AString);
+  AssertEquals('2 arguments',2,C.Args.Elements.Count);
+  E:=C.Args.Elements[0].Expr;
+  AssertNotNull('First argument expression',E);
+  CheckClass(E,TJSPrimaryExpressionIdent);
+  AssertEquals('First argument name correct','d',TJSPrimaryExpressionIdent(E).AString);
+  E:=C.Args.Elements[1].Expr;
+  AssertNotNull('Second argument expression',E);
+  CheckClass(E,TJSPrimaryExpressionIdent);
+  AssertEquals('Second argument name correct','e',TJSPrimaryExpressionIdent(E).AString);
+end;
+
+procedure TTestJSParser.TestArrayExpressionNumericalArgs;
+Var
+  X : TJSExpressionStatement;
+  B : TJSBracketMemberExpression;
+
+begin
+  CreateParser('A[1];');
+  X:=GetExpressionStatement;
+  CheckClass(X.A,TJSBracketMemberExpression);
+  B:=TJSBracketMemberExpression(X.A);
+  CheckClass(B.Name,TJSLiteral);
+  AssertEquals('Member name operand type correct', jstNumber, TJSLiteral(B.Name).Value.ValueType);
+  AssertEquals('Member name operand value correct', 1.0, TJSLiteral(B.Name).Value.AsNumber);
+  CheckClass(B.Mexpr,TJSPrimaryExpressionIdent);
+  AssertEquals('Array name correct','A',TJSPrimaryExpressionIdent(B.Mexpr).AString);
+end;
+
+procedure TTestJSParser.TestArrayExpressionStringArgs;
+Var
+  X : TJSExpressionStatement;
+  B : TJSBracketMemberExpression;
+
+begin
+  CreateParser('A["propname"];');
+  X:=GetExpressionStatement;
+  CheckClass(X.A,TJSBracketMemberExpression);
+  B:=TJSBracketMemberExpression(X.A);
+  CheckClass(B.Name,TJSLiteral);
+  AssertEquals('Member name operand type correct', jstString, TJSLiteral(B.Name).Value.ValueType);
+  AssertEquals('Member name operand value correct', 'propname', TJSLiteral(B.Name).Value.AsString);
+  CheckClass(B.Mexpr,TJSPrimaryExpressionIdent);
+  AssertEquals('Array name correct','A',TJSPrimaryExpressionIdent(B.Mexpr).AString);
+end;
+
+procedure TTestJSParser.TestArrayExpressionIdentArgs;
+
+Var
+  X : TJSExpressionStatement;
+  B : TJSBracketMemberExpression;
+
+begin
+  CreateParser('A[B];');
+  X:=GetExpressionStatement;
+  CheckClass(X.A,TJSBracketMemberExpression);
+  B:=TJSBracketMemberExpression(X.A);
+  CheckClass(B.Name,TJSPrimaryExpressionIdent);
+  AssertEquals('Member name identifier correct', 'B', TJSPrimaryExpressionIdent(B.Name).AString);
+  CheckClass(B.Mexpr,TJSPrimaryExpressionIdent);
+  AssertEquals('Array name correct','A',TJSPrimaryExpressionIdent(B.Mexpr).AString);
+end;
+
+procedure TTestJSParser.TestVarDeclarationSimple;
+
+Var
+  X : TJSELement;
+  V : TJSVarDeclaration;
+begin
+  CreateParser('var a;');
+  X:=GetFirstVar;
+  CheckClass(X,TJSVarDeclaration);
+  V:=TJSVarDeclaration(X);
+//  AssertNotNull('Variable statement assigned',(X));
+  AssertEquals('variable name correct registered', 'a', V.Name);
+  AssertNull('No initialization expression', V.Init);
+end;
+
+procedure TTestJSParser.TestVarDeclarationDouble;
+
+Var
+  X : TJSELement;
+  V : TJSVarDeclaration;
+
+begin
+  CreateParser('var a, b ;');
+  AssertEquals('2 variables declared',2,GetVars.Count);
+  X:=GetFirstVar;
+  CheckClass(X,TJSVarDeclaration);
+  V:=TJSVarDeclaration(X);
+//  AssertNotNull('Variable statement assigned',(X));
+  AssertEquals('variable name correct registered', 'a', V.name);
+  X:=GetVars.Nodes[1].Node;
+  CheckClass(X,TJSVarDeclaration);
+  V:=TJSVarDeclaration(X);
+  AssertEquals('variable name correct registered', 'b', V.Name);
+  AssertNull('No initialization expression', V.Init);
+end;
+
+procedure TTestJSParser.TestVarDeclarationSimpleInit;
+
+Var
+  X : TJSELement;
+  V : TJSVarDeclaration;
+begin
+  CreateParser('var a = b;');
+  X:=GetFirstVar;
+  CheckClass(X,TJSVarDeclaration);
+  V:=TJSVarDeclaration(X);
+//  AssertNotNull('Variable statement assigned',(X));
+  AssertEquals('variable name correct registered', 'a', V.Name);
+  AssertNotNull('Initialization expression present', V.Init);
+  CheckClass(V.Init,TJSPrimaryExpressionIdent);
+  AssertEquals('Member name identifier correct', 'b', TJSPrimaryExpressionIdent(V.init).AString);
+end;
+
+procedure TTestJSParser.TestVarDeclarationDoubleInit;
+
+Var
+  X : TJSELement;
+  V : TJSVarDeclaration;
+begin
+  CreateParser('var a, c = b;');
+  AssertEquals('2 variables declared',2,GetVars.Count);
+  X:=GetFirstVar;
+  CheckClass(X,TJSVarDeclaration);
+  V:=TJSVarDeclaration(X);
+//  AssertNotNull('Variable statement assigned',(X));
+  AssertEquals('variable name correct registered', 'a', V.Name);
+  AssertNull('No initialization expression', V.Init);
+  X:=GetVars.Nodes[1].Node;
+  CheckClass(X,TJSVarDeclaration);
+  V:=TJSVarDeclaration(X);
+  AssertEquals('variable name correct registered', 'c', V.Name);
+  AssertNotNull('No initialization expression', V.Init);
+  CheckClass(V.Init,TJSPrimaryExpressionIdent);
+  AssertEquals('Member name identifier correct', 'b', TJSPrimaryExpressionIdent(V.init).AString);
+end;
+
+procedure TTestJSParser.TestBlockEmpty;
+
+Var
+  E : TJSSourceElements;
+  X : TJSElement;
+
+begin
+  CreateParser('{}');
+  E:=GetSourceElements;
+  AssertEquals('1 statement in block',1,E.Statements.Count);
+  X:=E.Statements.Nodes[0].Node;
+  CheckClass(X,TJSEmptyBlockStatement);
+end;
+
+procedure TTestJSParser.TestBlockEmptyStatement;
+
+Var
+  E : TJSSourceElements;
+  X : TJSElement;
+
+begin
+  CreateParser('{;}');
+  E:=GetSourceElements;
+  AssertEquals('1 statement in block',1,E.Statements.Count);
+  X:=E.Statements.Nodes[0].Node;
+  CheckClass(X,TJSEmptyStatement);
+end;
+
+procedure TTestJSParser.TestBlockSimpleStatement;
+
+Var
+  E : TJSSourceElements;
+  X : TJSElement;
+
+begin
+  CreateParser('{a;}');
+  E:=GetSourceElements;
+  AssertEquals('1 statement in block',1,E.Statements.Count);
+  X:=E.Statements.Nodes[0].Node;
+  CheckClass(X,TJSExpressionStatement);
+  CheckNotNull(TJSExpressionStatement(X).A);
+  CheckClass(TJSExpressionStatement(X).A,TJSPrimaryExpressionIdent);
+  AssertEquals('a',TJSPrimaryExpressionIdent(TJSExpressionStatement(X).A).AString)
+end;
+
+procedure TTestJSParser.TestFunctionDeclarationEmpty;
+
+Var
+  E : TJSSourceElements;
+  N : TJSElement;
+  FD : TJSFunctionDeclarationStatement;
+
+begin
+  CreateParser('function a () {}');
+  E:=GetSourceElements;
+  AssertEquals('1 function defined',1,E.functions.Count);
+  N:=E.Functions.Nodes[0].Node;
+  AssertNotNull('Function element defined ',N);
+  CheckClass(N,TJSFunctionDeclarationStatement);
+  FD:=TJSFunctionDeclarationStatement(N);
+  AssertNotNull('Function definition assigned',FD.AFunction);
+  AssertEquals('Function name OK','a',FD.AFunction.Name);
+  AssertNotNull('Function body assigned', FD.AFunction.Body);
+  AssertEquals('No parameters',0,FD.AFunction.Params.Count);
+  N:=FD.AFunction.Body;
+  CheckClass(N,TJSFunctionBody);
+  AssertNotNull('Function body has element',TJSFunctionBody(N).A);
+  CheckClass(TJSFunctionBody(N).A,  TJSSourceElements);
+  E:=TJSSourceElements(TJSFunctionBody(N).A);
+  AssertEquals('0 statement in functionbody elements',0,E.Statements.Count);
+//  TJSEmptyBlockStatement
+end;
+
+procedure TTestJSParser.TestFunctionDeclarationWithArgs;
+
+Var
+  E : TJSSourceElements;
+  N : TJSElement;
+  FD : TJSFunctionDeclarationStatement;
+
+begin
+  CreateParser('function a (b,c) {}');
+  E:=GetSourceElements;
+  AssertEquals('1 function defined',1,E.functions.Count);
+  N:=E.Functions.Nodes[0].Node;
+  AssertNotNull('Function element defined ',N);
+  CheckClass(N,TJSFunctionDeclarationStatement);
+  FD:=TJSFunctionDeclarationStatement(N);
+  AssertNotNull('Function definition assigned',FD.AFunction);
+  AssertEquals('Function name OK','a',FD.AFunction.Name);
+  AssertNotNull('Function body assigned', FD.AFunction.Body);
+  AssertEquals('2 parameters',2,FD.AFunction.Params.Count);
+  AssertEquals('1st parameter','b',FD.AFunction.Params[0]);
+  AssertEquals('2nd parameter','c',FD.AFunction.Params[1]);
+  N:=FD.AFunction.Body;
+  CheckClass(N,TJSFunctionBody);
+  AssertNotNull('Function body has element',TJSFunctionBody(N).A);
+  CheckClass(TJSFunctionBody(N).A,  TJSSourceElements);
+  E:=TJSSourceElements(TJSFunctionBody(N).A);
+  AssertEquals('0 statement in functionbody elements',0,E.Statements.Count);
+//  TJSEmptyBlockStatement
+end;
+
+procedure TTestJSParser.TestFunctionDeclarationWithBody;
+
+Var
+  E : TJSSourceElements;
+  N : TJSElement;
+  FD : TJSFunctionDeclarationStatement;
+
+begin
+  CreateParser('function a () { b; }');
+  E:=GetSourceElements;
+  AssertEquals('1 function defined',1,E.functions.Count);
+  N:=E.Functions.Nodes[0].Node;
+  AssertNotNull('Function element defined ',N);
+  CheckClass(N,TJSFunctionDeclarationStatement);
+  FD:=TJSFunctionDeclarationStatement(N);
+  AssertNotNull('Function definition assigned',FD.AFunction);
+  AssertEquals('Function name OK','a',FD.AFunction.Name);
+  AssertNotNull('Function body assigned', FD.AFunction.Body);
+  AssertEquals('2 parameters',0,FD.AFunction.Params.Count);
+  N:=FD.AFunction.Body;
+  CheckClass(N,TJSFunctionBody);
+  AssertNotNull('Function body has element',TJSFunctionBody(N).A);
+  CheckClass(TJSFunctionBody(N).A,  TJSSourceElements);
+  E:=TJSSourceElements(TJSFunctionBody(N).A);
+  AssertEquals('1 statement in functionbody elements',1,E.Statements.Count);
+  N:=E.Statements.Nodes[0].Node;
+  CheckClass(N,TJSExpressionStatement);
+  CheckNotNull(TJSExpressionStatement(N).A);
+  CheckClass(TJSExpressionStatement(N).A,TJSPrimaryExpressionIdent);
+  AssertEquals('b',TJSPrimaryExpressionIdent(TJSExpressionStatement(N).A).AString);
+//  TJSEmptyBlockStatement
+end;
+
+procedure TTestJSParser.TestIfSimple;
+
+Var
+  E : TJSElement;
+  I : TJSIfStatement;
+
+begin
+  CreateParser('if (a) b;');
+  E:=GetFirstStatement;
+  CheckClass(E,TJSIfStatement);
+  I:=TJSIfStatement(E);
+  AssertNotNull('Statement condition assigned',I.Cond);
+  CheckClass(I.Cond,TJSPrimaryExpressionIdent);
+  AssertEquals('a',TJSPrimaryExpressionIdent(I.Cond).AString);
+  AssertNull('Statement false branch assigned',I.BFalse);
+  AssertNotNull('Statement true branch assigned',I.Btrue);
+  CheckClass(I.Btrue,TJSExpressionStatement);
+  AssertNotNull('Expression statement expression',TJSExpressionStatement(I.BTrue).A);
+  CheckClass(TJSExpressionStatement(I.BTrue).A,TJSPrimaryExpressionIdent);
+  AssertEquals('b',TJSPrimaryExpressionIdent(TJSExpressionStatement(I.Btrue).A).AString);
+end;
+
+procedure TTestJSParser.TestIfEmptyBlock;
+
+Var
+  E : TJSElement;
+  I : TJSIfStatement;
+
+begin
+  CreateParser('if (a) {}');
+  E:=GetFirstStatement;
+  CheckClass(E,TJSIfStatement);
+  I:=TJSIfStatement(E);
+  AssertNotNull('Statement condition assigned',I.Cond);
+  CheckClass(I.Cond,TJSPrimaryExpressionIdent);
+  AssertEquals('a',TJSPrimaryExpressionIdent(I.Cond).AString);
+  AssertNull('Statement false branch assigned',I.BFalse);
+  AssertNotNull('Statement true branch assigned',I.Btrue);
+  CheckClass(I.Btrue,TJSEmptyBlockStatement);
+end;
+
+procedure TTestJSParser.TestIfEmptyBlockElse;
+
+Var
+  E : TJSElement;
+  I : TJSIfStatement;
+
+begin
+  CreateParser('if (a) {} else b;');
+  E:=GetFirstStatement;
+  CheckClass(E,TJSIfStatement);
+  I:=TJSIfStatement(E);
+  AssertNotNull('Statement condition assigned',I.Cond);
+  CheckClass(I.Cond,TJSPrimaryExpressionIdent);
+  AssertEquals('a',TJSPrimaryExpressionIdent(I.Cond).AString);
+  AssertNotNull('Statement false branch assigned',I.BFalse);
+  AssertNotNull('Statement true branch assigned',I.Btrue);
+  CheckClass(I.Btrue,TJSEmptyBlockStatement);
+end;
+
+procedure TTestJSParser.TestWhileSimple;
+Var
+  E : TJSElement;
+  W : TJSWhileStatement;
+
+begin
+  CreateParser('while (a) b;');
+  E:=GetFirstStatement;
+  CheckClass(E,TJSWhileStatement);
+  W:=TJSWhileStatement(E);
+  AssertNotNull('Statement condition assigned',W.Cond);
+  CheckClass(W.Cond,TJSPrimaryExpressionIdent);
+  AssertEquals('a',TJSPrimaryExpressionIdent(W.Cond).AString);
+  AssertNotNull('Statement condition assigned',W.body);
+  CheckClass(W.Body,TJSExpressionStatement);
+  AssertNotNull('Expression statement expression',TJSExpressionStatement(W.Body).A);
+  CheckClass(TJSExpressionStatement(W.Body).A,TJSPrimaryExpressionIdent);
+  AssertEquals('b',TJSPrimaryExpressionIdent(TJSExpressionStatement(W.Body).A).AString);
+end;
+
+procedure TTestJSParser.TestWhileBlock;
+
+Var
+  E : TJSElement;
+  W : TJSWhileStatement;
+//  B : TJSBlockStatement;
+
+begin
+  CreateParser('while (a) {b;}');
+  E:=GetFirstStatement;
+  CheckClass(E,TJSWhileStatement);
+  W:=TJSWhileStatement(E);
+  AssertNotNull('Statement condition assigned',W.Cond);
+  CheckClass(W.Cond,TJSPrimaryExpressionIdent);
+  AssertEquals('a',TJSPrimaryExpressionIdent(W.Cond).AString);
+  AssertNotNull('Statement condition assigned',W.body);
+  CheckClass(W.Body,TJSExpressionStatement);
+  AssertNotNull('Expression statement expression',TJSExpressionStatement(W.Body).A);
+  CheckClass(TJSExpressionStatement(W.Body).A,TJSPrimaryExpressionIdent);
+  AssertEquals('b',TJSPrimaryExpressionIdent(TJSExpressionStatement(W.Body).A).AString);
+end;
+
+procedure TTestJSParser.TestDoWhileSimple;
+
+Var
+  E : TJSElement;
+  W : TJSWhileStatement;
+//  B : TJSBlockStatement;
+
+begin
+  CreateParser('do b; while (a);');
+  E:=GetFirstStatement;
+  CheckClass(E,TJSWhileStatement);
+  W:=TJSWhileStatement(E);
+  AssertNotNull('Statement condition assigned',W.Cond);
+  CheckClass(W.Cond,TJSPrimaryExpressionIdent);
+  AssertEquals('a',TJSPrimaryExpressionIdent(W.Cond).AString);
+  AssertNotNull('Statement condition assigned',W.body);
+  CheckClass(W.Body,TJSExpressionStatement);
+  AssertNotNull('Expression statement expression',TJSExpressionStatement(W.Body).A);
+  CheckClass(TJSExpressionStatement(W.Body).A,TJSPrimaryExpressionIdent);
+  AssertEquals('b',TJSPrimaryExpressionIdent(TJSExpressionStatement(W.Body).A).AString);
+end;
+
+procedure TTestJSParser.TestDoWhileBlock;
+
+Var
+  E : TJSElement;
+  W : TJSWhileStatement;
+//  B : TJSBlockStatement;
+
+begin
+  CreateParser('do {b;} while (a);');
+  E:=GetFirstStatement;
+  CheckClass(E,TJSWhileStatement);
+  W:=TJSWhileStatement(E);
+  AssertNotNull('Statement condition assigned',W.Cond);
+  CheckClass(W.Cond,TJSPrimaryExpressionIdent);
+  AssertEquals('a',TJSPrimaryExpressionIdent(W.Cond).AString);
+  AssertNotNull('Statement condition assigned',W.body);
+  CheckClass(W.Body,TJSExpressionStatement);
+  AssertNotNull('Expression statement expression',TJSExpressionStatement(W.Body).A);
+  CheckClass(TJSExpressionStatement(W.Body).A,TJSPrimaryExpressionIdent);
+  AssertEquals('b',TJSPrimaryExpressionIdent(TJSExpressionStatement(W.Body).A).AString);
+end;
+
+procedure TTestJSParser.TestForEmpty;
+
+Var
+  E : TJSElement;
+  F : TJSForStatement;
+
+begin
+  CreateParser('for (;;) a;');
+  E:=GetFirstStatement;
+  CheckClass(E,TJSForStatement);
+  F:=TJSForStatement(E);
+  AssertNull('Statement condition not assigned',F.Cond);
+  AssertNull('Statement init not assigned',F.Init);
+  AssertNull('Statement step not assigned',F.Incr);
+  CheckClass(F.Body,TJSExpressionStatement);
+  AssertNotNull('Expression statement expression',TJSExpressionStatement(F.Body).A);
+  CheckClass(TJSExpressionStatement(F.Body).A,TJSPrimaryExpressionIdent);
+  AssertEquals('a',TJSPrimaryExpressionIdent(TJSExpressionStatement(F.Body).A).AString);
+end;
+
+procedure TTestJSParser.TestForEmptyBody;
+
+Var
+  E : TJSElement;
+  F : TJSForStatement;
+
+begin
+  CreateParser('for (;;) {a;}');
+  E:=GetFirstStatement;
+  CheckClass(E,TJSForStatement);
+  F:=TJSForStatement(E);
+  AssertNull('Statement condition not assigned',F.Cond);
+  AssertNull('Statement init not assigned',F.Init);
+  AssertNull('Statement step not assigned',F.Incr);
+  CheckClass(F.Body,TJSExpressionStatement);
+  AssertNotNull('Expression statement expression',TJSExpressionStatement(F.Body).A);
+  CheckClass(TJSExpressionStatement(F.Body).A,TJSPrimaryExpressionIdent);
+  AssertEquals('a',TJSPrimaryExpressionIdent(TJSExpressionStatement(F.Body).A).AString);
+end;
+
+procedure TTestJSParser.TestForSimpleBody;
+
+Var
+  E : TJSElement;
+  F : TJSForStatement;
+
+begin
+  CreateParser('for (a;b;c) {d;}');
+  E:=GetFirstStatement;
+  CheckClass(E,TJSForStatement);
+  F:=TJSForStatement(E);
+  AssertNotNull('Statement condition not assigned',F.Cond);
+  AssertNotNull('Statement init not assigned',F.Init);
+  AssertNotNull('Statement step not assigned',F.Incr);
+  CheckClass(F.Init,TJSPrimaryExpressionIdent);
+  AssertNotNull('Expression statement expression',TJSPrimaryExpressionIdent(F.Init));
+  AssertEquals('a',TJSPrimaryExpressionIdent(F.Init).AString);
+  CheckClass(F.Incr,TJSPrimaryExpressionIdent);
+  AssertNotNull('Expression statement expression',TJSPrimaryExpressionIdent(F.Incr));
+  AssertEquals('c',TJSPrimaryExpressionIdent(F.Incr).AString);
+  CheckClass(F.Cond,TJSPrimaryExpressionIdent);
+  AssertNotNull('Expression statement expression',TJSPrimaryExpressionIdent(F.Cond));
+  AssertEquals('b',TJSPrimaryExpressionIdent(F.cond).AString);
+  CheckClass(F.Body,TJSExpressionStatement);
+  AssertNotNull('Expression statement expression',TJSExpressionStatement(F.Body).A);
+  CheckClass(TJSExpressionStatement(F.Body).A,TJSPrimaryExpressionIdent);
+  AssertEquals('d',TJSPrimaryExpressionIdent(TJSExpressionStatement(F.Body).A).AString);
+end;
+
+procedure TTestJSParser.TestTryCatch;
+
+Var
+  E : TJSElement;
+  T : TJSTryCatchStatement;
+
+begin
+  CreateParser('try {a;} catch (e) {b;}');
+  E:=GetFirstStatement;
+  CheckClass(E,TJSTryCatchStatement);
+  T:=TJSTryCatchStatement(E);
+  CheckClass(T.Block,TJSExpressionStatement);
+  AssertNotNull('Expression statement expression',TJSExpressionStatement(T.Block).A);
+  CheckClass(TJSExpressionStatement(T.Block).A,TJSPrimaryExpressionIdent);
+  AssertEquals('a',TJSPrimaryExpressionIdent(TJSExpressionStatement(T.Block).A).AString);
+  CheckClass(T.BCatch,TJSExpressionStatement);
+  AssertEquals('Except object identifier name','e',T.Ident);
+  AssertNotNull('Expression statement expression',TJSExpressionStatement(T.BCatch).A);
+  CheckClass(TJSExpressionStatement(T.BCatch).A,TJSPrimaryExpressionIdent);
+  AssertEquals('b',TJSPrimaryExpressionIdent(TJSExpressionStatement(T.BCatch).A).AString);
+  AssertNull('No Finally expression',T.BFinally);
+end;
+
+procedure TTestJSParser.TestTryCatchFinally;
+
+Var
+  E : TJSElement;
+  T : TJSTryCatchFinallyStatement;
+
+begin
+  CreateParser('try {a;} catch (e) {b;} finally {c;}');
+  E:=GetFirstStatement;
+  CheckClass(E,TJSTryCatchFinallyStatement);
+  T:=TJSTryCatchFinallyStatement(E);
+  CheckClass(T.Block,TJSExpressionStatement);
+  AssertNotNull('Expression statement expression',TJSExpressionStatement(T.Block).A);
+  CheckClass(TJSExpressionStatement(T.Block).A,TJSPrimaryExpressionIdent);
+  AssertEquals('a',TJSPrimaryExpressionIdent(TJSExpressionStatement(T.Block).A).AString);
+  AssertEquals('Except object identifier name','e',T.Ident);
+  CheckClass(T.BCatch,TJSExpressionStatement);
+  AssertNotNull('Expression statement expression',TJSExpressionStatement(T.BCatch).A);
+  CheckClass(TJSExpressionStatement(T.BCatch).A,TJSPrimaryExpressionIdent);
+  AssertEquals('b',TJSPrimaryExpressionIdent(TJSExpressionStatement(T.BCatch).A).AString);
+  AssertNotNull('Finally expression',T.BFinally);
+  CheckClass(T.BFinally,TJSExpressionStatement);
+  AssertNotNull('Expression statement expression',TJSExpressionStatement(T.BFinally).A);
+  CheckClass(TJSExpressionStatement(T.BFinally).A,TJSPrimaryExpressionIdent);
+  AssertEquals('c',TJSPrimaryExpressionIdent(TJSExpressionStatement(T.BFinally).A).AString);
+end;
+
+procedure TTestJSParser.TestTryFinally;
+
+Var
+  E : TJSElement;
+  T : TJSTryFinallyStatement;
+
+begin
+  CreateParser('try {a;} finally {c;}');
+  E:=GetFirstStatement;
+  CheckClass(E,TJSTryFinallyStatement);
+  T:=TJSTryFinallyStatement(E);
+  CheckClass(T.Block,TJSExpressionStatement);
+  AssertNotNull('Expression statement expression',TJSExpressionStatement(T.Block).A);
+  CheckClass(TJSExpressionStatement(T.Block).A,TJSPrimaryExpressionIdent);
+  AssertEquals('a',TJSPrimaryExpressionIdent(TJSExpressionStatement(T.Block).A).AString);
+  AssertNull('No catch',T.BCatch);
+  AssertNotNull('Finally expression',T.BFinally);
+  AssertNotNull('Finally expression',TJSExpressionStatement(T.BFinally).A);
+  CheckClass(TJSExpressionStatement(T.BFinally).A,TJSPrimaryExpressionIdent);
+  AssertEquals('c',TJSPrimaryExpressionIdent(TJSExpressionStatement(T.BFinally).A).AString);
+end;
+
+procedure TTestJSParser.TestThrow;
+Var
+  E : TJSElement;
+  T : TJSThrowStatement;
+
+begin
+  CreateParser('throw a;');
+  E:=GetFirstStatement;
+  CheckClass(E,TJSThrowStatement);
+  T:=TJSThrowStatement(E);
+  AssertNotNull('Have throw object',T.A);
+  CheckClass(T.A,TJSPrimaryExpressionIdent);
+  AssertEquals('Correct identifier','a',TJSPrimaryExpressionIdent(T.A).AsTring);
+end;
+
+procedure TTestJSParser.TestReturn;
+
+Var
+  E : TJSSourceElements;
+  N : TJSElement;
+  FD : TJSFunctionDeclarationStatement;
+
+begin
+  CreateParser('function a () { return b; }');
+  E:=GetSourceElements;
+  AssertEquals('1 function defined',1,E.functions.Count);
+  N:=E.Functions.Nodes[0].Node;
+  AssertNotNull('Function element defined ',N);
+  CheckClass(N,TJSFunctionDeclarationStatement);
+  FD:=TJSFunctionDeclarationStatement(N);
+  AssertNotNull('Function definition assigned',FD.AFunction);
+  AssertEquals('Function name OK','a',FD.AFunction.Name);
+  AssertNotNull('Function body assigned', FD.AFunction.Body);
+  AssertEquals('No parameters',0,FD.AFunction.Params.Count);
+  N:=FD.AFunction.Body;
+  CheckClass(N,TJSFunctionBody);
+  AssertNotNull('Function body has element',TJSFunctionBody(N).A);
+  CheckClass(TJSFunctionBody(N).A,  TJSSourceElements);
+  E:=TJSSourceElements(TJSFunctionBody(N).A);
+  AssertEquals('1 statement in functionbody elements',1,E.Statements.Count);
+end;
+
+procedure TTestJSParser.TestIfElseSimple;
+
+Var
+  E : TJSElement;
+  I : TJSIfStatement;
+
+begin
+  CreateParser('if (a) b; else c;');
+  E:=GetFirstStatement;
+  CheckClass(E,TJSIfStatement);
+  I:=TJSIfStatement(E);
+  AssertNotNull('Statement condition assigned',I.Cond);
+  CheckClass(I.Cond,TJSPrimaryExpressionIdent);
+  AssertEquals('a',TJSPrimaryExpressionIdent(I.Cond).AString);
+  AssertNotNull('Statement condition assigned',I.Btrue);
+  CheckClass(I.Btrue,TJSExpressionStatement);
+  AssertNotNull('Expression statement expression',TJSExpressionStatement(I.BTrue).A);
+  CheckClass(TJSExpressionStatement(I.BTrue).A,TJSPrimaryExpressionIdent);
+  AssertEquals('b',TJSPrimaryExpressionIdent(TJSExpressionStatement(I.Btrue).A).AString);
+  AssertNotNull('Else Statement condition assigned',I.BFalse);
+  CheckClass(I.BFalse,TJSExpressionStatement);
+  AssertNotNull('Else statement expression',TJSExpressionStatement(I.BFalse).A);
+  CheckClass(TJSExpressionStatement(I.BFalse).A,TJSPrimaryExpressionIdent);
+  AssertEquals('c',TJSPrimaryExpressionIdent(TJSExpressionStatement(I.BFalse).A).AString);
+end;
+
+
+procedure TTestJSParser.TestExpressionPrecedenceMulNot;
+
+Var
+  X : TJSExpressionStatement;
+  R : TJSUnaryNotExpression;
+  E : TJSMultiplicativeExpressionMul;
+
+begin
+  CreateParser('4 * !2;');
+  X:=GetExpressionStatement;
+  AssertNotNull('Expression statement assigned',X.A);
+  CheckClass(X.A,TJSMultiplicativeExpressionMul);
+  E:=TJSMultiplicativeExpressionMul(X.A);
+  AssertNotNull('Expression left operand assigned',E.A);
+  AssertNotNull('Expression right operand assigned',E.B);
+  CheckClass(E.B,TJSUnaryNotExpression);
+  R:=TJSUnaryNotExpression(E.B);
+  CheckClass(E.A,TJSLiteral);
+  AssertNotNull('Multiplication left operand assigned',R.A);
+  CheckClass(R.A,TJSLiteral);
+  AssertEquals('Not operand type correct', jstNumber, TJSLiteral(R.A).Value.ValueType);
+  AssertEquals('Not operand value correct', 2.0, TJSLiteral(R.A).Value.AsNumber);
+  AssertNotNull('Multiplication left operand value assigned',TJSLiteral(E.A).Value);
+  AssertEquals('Multiplication left operand type correct', jstNumber, TJSLiteral(E.A).Value.ValueType);
+  AssertEquals('Multiplication left operand value correct', 4.0,TJSLiteral(E.A).Value.AsNumber);
+end;
+
+procedure TTestJSParser.TestExpressionPrecedencePlusPreMinusMinus;
+Var
+  X : TJSExpressionStatement;
+  R : TJSUnaryPreMinusMinusExpression;
+  E : TJSAdditiveExpressionPlus;
+
+begin
+  CreateParser('4 + --2;');
+  X:=GetExpressionStatement;
+  AssertNotNull('Expression statement assigned',X.A);
+  CheckClass(X.A,TJSAdditiveExpressionPlus);
+  E:=TJSAdditiveExpressionPlus(X.A);
+  AssertNotNull('Expression left operand assigned',E.A);
+  AssertNotNull('Expression right operand assigned',E.B);
+  CheckClass(E.B,TJSUnaryPreMinusMinusExpression);
+  R:=TJSUnaryPreMinusMinusExpression(E.B);
+  CheckClass(E.A,TJSLiteral);
+  AssertNotNull('Multiplication left operand assigned',R.A);
+  CheckClass(R.A,TJSLiteral);
+  AssertEquals('Multiplication left operand type correct', jstNumber, TJSLiteral(R.A).Value.ValueType);
+  AssertEquals('Multiplication left operand value correct', 2.0, TJSLiteral(R.A).Value.AsNumber);
+  AssertNotNull('Addition right operand value assigned',TJSLiteral(E.A).Value);
+  AssertEquals('Addition left operand type correct', jstNumber, TJSLiteral(E.A).Value.ValueType);
+  AssertEquals('Expression right operand value correct', 4.0,TJSLiteral(E.A).Value.AsNumber);
+end;
+
+procedure TTestJSParser.TestExpressionPrecedenceMulPrePlusPlus;
+
+Var
+  X : TJSExpressionStatement;
+  R : TJSUnaryPrePlusPlusExpression;
+  E : TJSMultiplicativeExpressionMul;
+
+begin
+  CreateParser('4 * ++2;');
+  X:=GetExpressionStatement;
+  AssertNotNull('Expression statement assigned',X.A);
+  CheckClass(X.A,TJSMultiplicativeExpressionMul);
+  E:=TJSMultiplicativeExpressionMul(X.A);
+  AssertNotNull('Expression left operand assigned',E.A);
+  AssertNotNull('Expression right operand assigned',E.B);
+  CheckClass(E.B,TJSUnaryPrePlusPlusExpression);
+  R:=TJSUnaryPrePlusPlusExpression(E.B);
+  CheckClass(E.A,TJSLiteral);
+  AssertNotNull('Multiplication left operand assigned',R.A);
+  CheckClass(R.A,TJSLiteral);
+  AssertEquals('Multiplication left operand type correct', jstNumber, TJSLiteral(R.A).Value.ValueType);
+  AssertEquals('Multiplication left operand value correct', 2.0, TJSLiteral(R.A).Value.AsNumber);
+  AssertNotNull('Addition right operand value assigned',TJSLiteral(E.A).Value);
+  AssertEquals('Addition left operand type correct', jstNumber, TJSLiteral(E.A).Value.ValueType);
+  AssertEquals('Expression right operand value correct', 4.0,TJSLiteral(E.A).Value.AsNumber);
+end;
+
+procedure TTestJSParser.TestExpressionPrecedenceMulPreMinusMinus;
+Var
+  X : TJSExpressionStatement;
+  R : TJSUnaryPreMinusMinusExpression;
+  E : TJSMultiplicativeExpressionMul;
+
+begin
+  CreateParser('4 * --2;');
+  X:=GetExpressionStatement;
+  AssertNotNull('Expression statement assigned',X.A);
+  CheckClass(X.A,TJSMultiplicativeExpressionMul);
+  E:=TJSMultiplicativeExpressionMul(X.A);
+  AssertNotNull('Expression left operand assigned',E.A);
+  AssertNotNull('Expression right operand assigned',E.B);
+  CheckClass(E.B,TJSUnaryPreMinusMinusExpression);
+  R:=TJSUnaryPreMinusMinusExpression(E.B);
+  CheckClass(E.A,TJSLiteral);
+  AssertNotNull('Multiplication left operand assigned',R.A);
+  CheckClass(R.A,TJSLiteral);
+  AssertEquals('Multiplication left operand type correct', jstNumber, TJSLiteral(R.A).Value.ValueType);
+  AssertEquals('Multiplication left operand value correct', 2.0, TJSLiteral(R.A).Value.AsNumber);
+  AssertNotNull('Addition right operand value assigned',TJSLiteral(E.A).Value);
+  AssertEquals('Addition left operand type correct', jstNumber, TJSLiteral(E.A).Value.ValueType);
+  AssertEquals('Expression right operand value correct', 4.0,TJSLiteral(E.A).Value.AsNumber);
+end;
+
+procedure TTestJSParser.TestSimpleExpressionBooleanLiteralTrue;
+
+Var
+  X : TJSExpressionStatement;
+
+begin
+  CreateParser('true;');
+  X:=GetExpressionStatement;
+  AssertNotNull('Expression statement assigned',X.A);
+  CheckClass(X.A,TJSLiteral);
+  AssertNotNull('Expression value assigned',TJSLiteral(X.A).Value);
+  AssertEquals('Expression value type correct', jstBoolean,TJSLiteral(X.A).Value.ValueType);
+  AssertEquals('Expression value correct', True, TJSLiteral(X.A).Value.AsBoolean);
+end;
+
+
+procedure TTestJSParser.TestEmpty;
+
+Var
+  E : TJSElement;
+  FB : TJSFunctionBody;
+  SE : TJSSourceElements;
+
+begin
+  CreateParser('var a;');
+  E:=FParser.Parse;
+  CheckClass(E,TJSFunctionBody);
+  FB:=TJSFunctionBody(E);
+  AssertNotNull(FB.A);
+  CheckClass(FB.A,TJSSourceElements);
+  SE:=TJSSourceElements(FB.A);
+  AssertEquals('1 variable declaration ',1,SE.Vars.Count);
+  CheckClass(FB.A,TJSSourceElements);
+end;
+
+procedure TTestJSParser.SetUp; 
+begin
+  FParser:=Nil;
+  FSource:=Nil;
+end; 
+
+procedure TTestJSParser.TearDown; 
+begin
+//  FreeAndNil(FToFree);
+  FreeAndNil(FParser);
+  FReeAndNil(FSource);
+end;
+
+procedure TTestJSParser.CreateParser(const ASource: string);
+begin
+  FSource:=TStringStream.Create(ASource);
+  FParser:=TJSParser.Create(FSource);
+end;
+
+procedure TTestJSParser.CheckClass(E: TJSElement; C: TJSElementClass);
+begin
+  AssertEquals(C,E.ClassType);
+end;
+
+function TTestJSParser.GetSourceElements: TJSSourceElements;
+
+Var
+  E : TJSElement;
+  FB : TJSFunctionBody;
+
+begin
+  If Not Assigned(FSE) then
+    begin
+    AssertNotNull('Parser assigned',FParser);
+    E:=FParser.Parse;
+    CheckClass(E,TJSFunctionBody);
+    FB:=TJSFunctionBody(E);
+    AssertNotNull(FB.A);
+    CheckClass(FB.A,TJSSourceElements);
+    FSE:=TJSSourceElements(FB.A);
+    end;
+  Result:=FSE;
+  FToFree:=E;
+end;
+
+function TTestJSParser.GetVars: TJSElementNodes;
+begin
+  Result:=GetSourceElements.Vars;
+end;
+
+function TTestJSParser.GetStatements: TJSElementNodes;
+begin
+  Result:=GetSourceElements.Statements;
+end;
+
+function TTestJSParser.GetFunctions: TJSElementNodes;
+begin
+  Result:=GetSourceElements.Functions;
+end;
+
+
+initialization
+
+  RegisterTest(TTestJSParser); 
+end.
+

+ 983 - 0
packages/fcl-js/tests/tcscanner.pp

@@ -0,0 +1,983 @@
+unit tcscanner;
+
+{$mode objfpc}{$H+}
+
+interface
+
+uses
+  Classes, SysUtils, Typinfo, fpcunit, testutils, testregistry, jsscanner;
+
+type
+
+  { TTestLineReader }
+
+  TTestLineReader = Class(TTestCase)
+  Private
+    FData: TStringStream;
+    FReader : TStreamLineReader;
+  protected
+    Procedure CreateReader(AInput : String);
+    procedure TearDown; override;
+  published
+    Procedure TestEmpty;
+    Procedure TestReadLine;
+    Procedure TestReadLines13;
+    Procedure TestReadLines10;
+    Procedure TestReadLines1310;
+    procedure TestReadLinesEOF13;
+    procedure TestReadLinesEOF10;
+    procedure TestReadLinesEOF1310;
+    procedure TestReadEmptyLines101010;
+  end;
+
+  { TTestJSScanner }
+
+  TTestJSScanner = class(TTestCase)
+  Private
+    FStream : TStream;
+    FLineReader : TLineReader;
+    FScanner : TJSScanner;
+    FErrorSource : String;
+    procedure AssertEquals(AMessage: String; AExpected, AActual : TJSToken); overload;
+    procedure CheckToken(AToken: TJSToken; ASource: String);
+    procedure CheckTokens(ASource: String; ATokens: array of TJSToken);
+    procedure DoTestFloat(F: Double);
+    procedure DoTestFloat(F: Double; S: String);
+    procedure DoTestString(S: String);
+    procedure TestErrorSource;
+  protected
+    Function CreateScanner(AInput : String) : TJSScanner;
+    procedure FreeScanner;
+    procedure SetUp; override;
+    procedure TearDown; override;
+
+    Property Scanner : TJSScanner Read FScanner;
+  published
+    Procedure TestEmpty;
+    procedure TestAndAnd;
+    procedure TestAndEq;
+    procedure TestAssign;
+    procedure TestBraceClose;
+    procedure TestBraceOpen;
+    procedure TestColon;
+    procedure TestComma;
+    procedure TestCurlyBraceClose;
+    procedure TestCurlyBraceOpen;
+    procedure TestDiv;
+    procedure TestDiveq;
+    procedure TestXor;
+    procedure TestXoreq;
+    procedure TestDot;
+    procedure TestEq;
+    procedure TestGE;
+    procedure TestFalse;
+    procedure TestInv;
+    procedure TestNot;
+    procedure TestString;
+    procedure TestTrue;
+    procedure TestGreaterThan;
+    procedure TestLE;
+    procedure TestLessThan;
+    procedure TestLSHIFT;
+    procedure TestLSHIFTEQ;
+    procedure TestMinus;
+    procedure TestMinusEQ;
+    procedure TestMinusMinus;
+    procedure TestModeq;
+    procedure TestMul;
+    procedure TestNE;
+    procedure TestNSE;
+    procedure TestOREQ;
+    procedure TestOROR;
+    procedure TestPlus;
+    procedure TestPlusEq;
+    procedure TestPlusPlus;
+    procedure TestRShift;
+    procedure TestRShiftEq;
+    procedure TestSemicolon;
+    procedure TestSEq;
+    procedure TestSquaredBraceClose;
+    procedure TestSquaredBraceOpen;
+    procedure TestStarEq;
+    procedure TestURShift;
+    procedure TestURShiftEq;
+    procedure TestBreak;
+    procedure TestCase;
+    procedure TestCatch;
+    procedure TestContinue;
+    procedure TestDefault;
+    procedure TestDelete;
+    procedure TestDO;
+    procedure TestElse;
+    procedure TestFinally;
+    procedure TestFor;
+    procedure TestFunction;
+    procedure TestIf;
+    procedure TestIn;
+    procedure TestInstanceOf;
+    procedure TestNew;
+    procedure TestReturn;
+    procedure TestSwitch;
+    procedure TestThis;
+    procedure TestThrow;
+    procedure TestTry;
+    procedure TestTypeOf;
+    procedure TestVar;
+    procedure TestVoid;
+    procedure TestWhile;
+    procedure TestWith;
+    Procedure Test2Words;
+    procedure Test3Words;
+    procedure TestIdentifier;
+    procedure TestIdentifier2;
+    procedure TestIdentifier3;
+    procedure TestIdentifier4;
+    procedure TestIdentifier5;
+    procedure TestIdentifierDotIdentifier;
+    procedure TestEOLN;
+    procedure TestEOLN2;
+    procedure TestEOLN3;
+    procedure TestEOLN4;
+    procedure TestComment1;
+    procedure TestComment2;
+    procedure TestComment3;
+    procedure TestComment4;
+    procedure TestComment5;
+    procedure TestComment6;
+    procedure TestFloat;
+    procedure TestStringError;
+    procedure TestFloatError;
+  end;
+
+
+implementation
+
+Function TTestJSScanner.CreateScanner(AInput : String) : TJSScanner;
+
+begin
+  FStream:=TStringStream.Create(AInput);
+  FLineReader:=TStreamLineReader.Create(Fstream);
+  FScanner:=TJSScanner.Create(FLineReader);
+end;
+
+procedure TTestJSScanner.FreeScanner;
+begin
+  FreeAndNil(FScanner);
+  FreeAndNil(FLineReader);
+  FreeAndNil(FStream);
+end;
+
+procedure TTestJSScanner.SetUp;
+begin
+  inherited SetUp;
+end;
+
+
+
+procedure TTestJSScanner.TestEmpty;
+
+Var
+  J : TJSToken;
+
+begin
+  CreateScanner('');
+  J:=Scanner.FetchToken;
+  If (J<>tjsEOF) then
+    Fail('Empty returns EOF');
+end;
+
+procedure TTestJSScanner.AssertEquals(AMessage : String; AExpected, AActual: TJSToken);
+
+Var
+  J : TJSToken;
+  S,EN1,EN2 : String;
+
+begin
+  If (AActual<>AExpected) then
+    begin
+    EN1:=GetEnumName(TypeINfo(TJSToken),Ord(AExpected));
+    EN2:=GetEnumName(TypeINfo(TJSToken),Ord(AActual));
+    S:=Format('%s : %s <> %s',[AMessage,EN1,EN2]);
+    Fail(S);
+    end;
+end;
+
+procedure TTestJSScanner.CheckToken(AToken : TJSToken; ASource : String);
+
+Var
+  J : TJSToken;
+  EN2 : String;
+
+begin
+  CreateScanner(ASource);
+  J:=Scanner.FetchToken;
+  EN2:=GetEnumName(TypeINfo(TJSToken),Ord(AToken));
+  AssertEquals(Format('Source %s should result in %s.',[ASource,EN2]),AToken,J);
+end;
+
+
+procedure TTestJSScanner.TestAndAnd;
+
+begin
+  CheckToken(tjsAndAnd,'&&');
+end;
+
+procedure TTestJSScanner.TestAndEq;
+
+begin
+  CheckToken(tjsAndEq,'&=');
+end;
+
+procedure TTestJSScanner.TestBraceOpen;
+
+begin
+  CheckToken(tjsBraceOpen,'(');
+end;
+
+procedure TTestJSScanner.TestBraceClose;
+
+begin
+  CheckToken(tjsBraceClose,')');
+end;
+
+procedure TTestJSScanner.TestSquaredBraceClose;
+
+begin
+  CheckToken(tjsSquaredBraceClose,']');
+end;
+
+procedure TTestJSScanner.TestSquaredBraceOpen;
+
+begin
+  CheckToken(tjssQuaredBraceOpen,'[');
+end;
+
+procedure TTestJSScanner.TestCurlyBraceOpen;
+
+begin
+  CheckToken(tjsCurlyBraceOpen,'{');
+end;
+
+procedure TTestJSScanner.TestCurlyBraceClose;
+
+begin
+  CheckToken(tjsCurlyBraceClose,'}');
+end;
+
+procedure TTestJSScanner.TestComma;
+
+begin
+  CheckToken(tjsComma,',');
+end;
+
+procedure TTestJSScanner.TestColon;
+
+begin
+  CheckToken(tjsColon,':');
+end;
+
+procedure TTestJSScanner.TestDot;
+
+begin
+  CheckToken(tjsDot,'.');
+end;
+
+procedure TTestJSScanner.TestSemicolon;
+
+begin
+  CheckToken(tjsSemicolon,';');
+end;
+
+procedure TTestJSScanner.TestAssign;
+
+begin
+  CheckToken(tjsAssign,'=');
+end;
+
+procedure TTestJSScanner.TestGreaterThan;
+
+begin
+  CheckToken(tjsGT,'>');
+end;
+
+procedure TTestJSScanner.TestLessThan;
+
+begin
+  CheckToken(tjsLT,'<');
+end;
+
+procedure TTestJSScanner.TestPlus;
+
+begin
+  CheckToken(tjsPlus,'+');
+end;
+
+procedure TTestJSScanner.TestMinus;
+
+begin
+  CheckToken(tjsMinus,'-');
+end;
+
+procedure TTestJSScanner.TestMul;
+
+begin
+  CheckToken(tjsMul,'*');
+end;
+
+procedure TTestJSScanner.TestDiv;
+
+begin
+  CheckToken(tjsDiv,'/');
+end;
+
+procedure TTestJSScanner.TestEq;
+
+begin
+  CheckToken(tjsEq,'==');
+end;
+
+procedure TTestJSScanner.TestGE;
+
+begin
+  CheckToken(tjsGE,'>=');
+end;
+
+procedure TTestJSScanner.TestLE;
+
+begin
+  CheckToken(tjsLE,'<=');
+end;
+
+procedure TTestJSScanner.TestLSHIFT;
+
+begin
+  CheckToken(tjsLShift,'<<');
+end;
+
+procedure TTestJSScanner.TestLSHIFTEQ;
+
+begin
+  CheckToken(tjsLShiftEq,'<<=');
+end;
+
+procedure TTestJSScanner.TestMinusEQ;
+
+begin
+  CheckToken(tjsMinusEq,'-=');
+end;
+
+procedure TTestJSScanner.TestMinusMinus;
+
+begin
+  CheckToken(tjsMinusMinus,'--');
+end;
+
+procedure TTestJSScanner.TestModeq;
+
+begin
+  CheckToken(tjsModeq,'%=');
+end;
+
+
+procedure TTestJSScanner.TestDiveq;
+
+begin
+  CheckToken(tjsDiveq,'/=');
+end;
+
+procedure TTestJSScanner.TestXor;
+begin
+  CheckToken(tjsXOR,'^');
+end;
+
+procedure TTestJSScanner.TestXoreq;
+begin
+  CheckToken(tjsXOREQ,'^=');
+end;
+
+procedure TTestJSScanner.TestNE;
+
+begin
+  CheckToken(tjsNE,'!=');
+end;
+
+procedure TTestJSScanner.TestInv;
+
+begin
+  CheckToken(tjsInv,'~');
+end;
+
+procedure TTestJSScanner.TestNot;
+
+begin
+  CheckToken(tjsNot,'!');
+end;
+
+procedure TTestJSScanner.TestTrue;
+
+begin
+  CheckToken(tjsTrue,'true');
+end;
+
+procedure TTestJSScanner.TestFalse;
+
+begin
+  CheckToken(tjsFalse,'false');
+end;
+
+procedure TTestJSScanner.TestOREQ;
+
+begin
+  CheckToken(tjsOREQ,'|=');
+end;
+
+procedure TTestJSScanner.TestOROR;
+
+begin
+  CheckToken(tjsOROR,'||');
+end;
+
+procedure TTestJSScanner.TestPlusEq;
+
+begin
+  CheckToken(tjsPlusEq,'+=');
+end;
+
+procedure TTestJSScanner.TestPlusPlus;
+
+begin
+  CheckToken(tjsPlusPlus,'++');
+end;
+
+procedure TTestJSScanner.TestURShift;
+
+begin
+  CheckToken(tjsURSHIFT,'>>>');
+end;
+
+procedure TTestJSScanner.TestURShiftEq;
+
+begin
+  CheckToken(tjsURSHIFTEQ,'>>>=');
+end;
+
+procedure TTestJSScanner.TestRShift;
+
+begin
+  CheckToken(tjsRSHIFT,'>>');
+end;
+
+procedure TTestJSScanner.TestRShiftEq;
+
+begin
+  CheckToken(tjsRSHIFTEQ,'>>=');
+end;
+
+procedure TTestJSScanner.TestSEq;
+
+begin
+  CheckToken(tjsSEQ,'===');
+end;
+
+procedure TTestJSScanner.TestNSE;
+
+begin
+  CheckToken(tjsSNE,'!==');
+end;
+
+procedure TTestJSScanner.TestStarEq;
+
+begin
+  CheckToken(tjsMulEq,'*=');
+end;
+
+procedure TTestJSScanner.TestBreak;
+
+begin
+  CheckToken(tjsBreak,'break');
+end;
+
+procedure TTestJSScanner.TestCase;
+
+begin
+  CheckToken(tjscase,'case');
+end;
+
+procedure TTestJSScanner.TestCatch;
+
+begin
+  CheckToken(tjscatch,'catch');
+end;
+
+procedure TTestJSScanner.TestContinue;
+
+begin
+  CheckToken(tjscontinue,'continue');
+end;
+
+procedure TTestJSScanner.TestDefault;
+
+begin
+  CheckToken(tjsdefault,'default');
+end;
+
+procedure TTestJSScanner.TestDelete;
+
+begin
+  CheckToken(tjsdelete,'delete');
+end;
+
+procedure TTestJSScanner.TestDO;
+
+begin
+  CheckToken(tjsdo,'do');
+end;
+
+procedure TTestJSScanner.TestElse;
+
+begin
+  CheckToken(tjselse,'else');
+end;
+
+procedure TTestJSScanner.TestFinally;
+
+begin
+  CheckToken(tjsfinally,'finally');
+end;
+
+procedure TTestJSScanner.TestFor;
+
+begin
+  CheckToken(tjsfor,'for');
+end;
+
+procedure TTestJSScanner.TestFunction;
+
+begin
+  CheckToken(tjsfunction,'function');
+end;
+
+procedure TTestJSScanner.TestIf;
+
+begin
+  CheckToken(tjsif,'if');
+end;
+
+procedure TTestJSScanner.TestIn;
+
+begin
+  CheckToken(tjsin,'in');
+end;
+
+procedure TTestJSScanner.TestInstanceOf;
+
+begin
+  CheckToken(tjsinstanceof,'instanceof');
+end;
+
+procedure TTestJSScanner.TestNew;
+
+begin
+  CheckToken(tjsnew,'new');
+end;
+
+procedure TTestJSScanner.TestReturn;
+
+begin
+  CheckToken(tjsreturn,'return');
+end;
+
+procedure TTestJSScanner.TestSwitch;
+
+begin
+  CheckToken(tjsswitch,'switch');
+end;
+
+procedure TTestJSScanner.TestThis;
+
+begin
+  CheckToken(tjsThis,'this');
+end;
+
+procedure TTestJSScanner.TestThrow;
+
+begin
+  CheckToken(tjsThrow,'throw');
+end;
+
+procedure TTestJSScanner.TestTry;
+
+begin
+  CheckToken(tjsTry,'try');
+end;
+
+procedure TTestJSScanner.TestTypeOf;
+
+begin
+  CheckToken(tjstypeof,'typeof');
+end;
+
+procedure TTestJSScanner.TestVar;
+
+begin
+  CheckToken(tjsvar,'var');
+end;
+
+procedure TTestJSScanner.TestVoid;
+
+begin
+  CheckToken(tjsvoid,'void');
+end;
+
+procedure TTestJSScanner.TestWhile;
+
+begin
+  CheckToken(tjswhile,'while');
+end;
+
+procedure TTestJSScanner.TestWith;
+
+begin
+  CheckToken(tjswith,'with');
+end;
+
+procedure TTestJSScanner.CheckTokens(ASource : String; ATokens : Array of TJSToken);
+
+Var
+  I : Integer;
+  J : TJSToken;
+  S : String;
+
+begin
+  CreateScanner(ASource);
+  For I:=Low(ATokens) to High(ATokens) do
+    begin
+    J:=FScanner.FetchToken;
+    S:=GetEnumName(TypeINfo(TJSToken),Ord(ATokens[i]));
+    S:=Format('Source "%s", token %d (%s): expected %s',[ASource,I,FScanner.CurTokenString,S]);
+    AssertEquals(S,ATokens[i],J);
+    end;
+end;
+
+procedure TTestJSScanner.Test2Words;
+begin
+  CheckTokens('with do',[tjsWith,tjsDo]);
+end;
+
+procedure TTestJSScanner.Test3Words;
+begin
+  CheckTokens('with do for',[tjsWith,tjsDo,tjsFor]);
+end;
+
+procedure TTestJSScanner.TestIdentifier;
+begin
+  CheckToken(tjsIdentifier,'something');
+  AssertEquals('Correct identifier','something',FScanner.CurTokenString);
+end;
+
+procedure TTestJSScanner.TestIdentifier2;
+begin
+  CheckToken(tjsIdentifier,'_something');
+  AssertEquals('Correct identifier','_something',FScanner.CurTokenString);
+end;
+
+procedure TTestJSScanner.TestIdentifier3;
+begin
+  CheckToken(tjsIdentifier,'$');
+  AssertEquals('Correct identifier','$',FScanner.CurTokenString);
+end;
+
+procedure TTestJSScanner.TestIdentifier4;
+begin
+  CheckToken(tjsIdentifier,'_0');
+  AssertEquals('Correct identifier','_0',FScanner.CurTokenString);
+end;
+
+procedure TTestJSScanner.TestIdentifier5;
+begin
+  CheckToken(tjsIdentifier,'$0');
+  AssertEquals('Correct identifier','$0',FScanner.CurTokenString);
+end;
+
+procedure TTestJSScanner.TestIdentifierDotIdentifier;
+begin
+  CheckTokens('something.different',[tjsIdentifier,tjsdot,tjsIdentifier]);
+//  AssertEquals('Correct identifier','something',FScanner.CurTokenString);
+end;
+
+procedure TTestJSScanner.TestEOLN;
+begin
+  CreateScanner('something');
+  FScanner.FetchToken;
+  AssertEquals('Got to end of line after reading single token at EOF',True,FScanner.IsEndOfLine);
+//  AssertEquals('Correct identifier','something',FScanner.CurTokenString);
+end;
+
+procedure TTestJSScanner.TestEOLN2;
+begin
+  CreateScanner('something different');
+  FScanner.FetchToken;
+  AssertEquals('Not yet end of line after reading single token at EOF',False,FScanner.IsEndOfLine);
+end;
+
+procedure TTestJSScanner.TestEOLN3;
+begin
+  CreateScanner('something'#13#10'different');
+  FScanner.FetchToken;
+  AssertEquals('End of line after reading single token',True,FScanner.IsEndOfLine);
+end;
+
+procedure TTestJSScanner.TestEOLN4;
+begin
+  CreateScanner('something'#10'different');
+  FScanner.FetchToken;
+  AssertEquals('End of line after reading first token',True,FScanner.IsEndOfLine);
+  FScanner.FetchToken;
+  AssertEquals('End of line after reading second token',True,FScanner.IsEndOfLine);
+end;
+
+procedure TTestJSScanner.TestComment1;
+begin
+  CreateScanner('// some comment string');
+  AssertEquals('Comment line is skipped',tjsEOF,FScanner.FetchToken);
+end;
+
+procedure TTestJSScanner.TestComment2;
+begin
+  CreateScanner('// some comment string');
+  FScanner.ReturnComments:=True;
+  AssertEquals('Comment line is returned',tjsComment,FScanner.FetchToken);
+  AssertEquals('Comment contents is returned',' some comment string',FScanner.CurTokenString);
+end;
+
+procedure TTestJSScanner.TestComment3;
+begin
+  CreateScanner('/* some comment string */');
+  AssertEquals('Comment line is skipped',tjsEOF,FScanner.FetchToken);
+end;
+
+procedure TTestJSScanner.TestComment4;
+begin
+  CreateScanner('/* some comment string */');
+  FScanner.ReturnComments:=True;
+  AssertEquals('Comment line is returned',tjsComment,FScanner.FetchToken);
+  AssertEquals('Comment contents is returned',' some comment string ',FScanner.CurTokenString);
+end;
+
+procedure TTestJSScanner.TestComment5;
+begin
+  CreateScanner('/* some nested comment // string */');
+  FScanner.ReturnComments:=True;
+  AssertEquals('Comment line is returned',tjsComment,FScanner.FetchToken);
+  AssertEquals('Comment contents is returned',' some nested comment // string ',FScanner.CurTokenString);
+end;
+
+procedure TTestJSScanner.TestComment6;
+begin
+  CreateScanner('// /* some nested comment string */');
+  FScanner.ReturnComments:=True;
+  AssertEquals('Comment line is returned',tjsComment,FScanner.FetchToken);
+  AssertEquals('Comment contents is returned',' /* some nested comment string */',FScanner.CurTokenString);
+end;
+
+procedure TTestJSScanner.TearDown; 
+begin
+  FreeScanner;
+end;
+
+procedure TTestJSScanner.DoTestFloat(F : Double);
+
+Var
+  S : String;
+
+begin
+  Str(F,S);
+  DoTestFloat(F,S);
+end;
+
+procedure TTestJSScanner.DoTestFloat(F : Double; S : String);
+
+Var
+  J : TJSToken;
+  C : Double;
+  I : integer;
+  V : String;
+
+begin
+  CreateScanner(S);
+  J:=FScanner.FetchToken;
+  AssertEquals(S+' is a number',tjsNumber,J);
+  V:=FScanner.CurTokenString;
+  If (Copy(V,1,2)='0x') then
+    begin
+    Flush(output);
+    V:='$'+Copy(V,3,Length(V)-2);
+    C:=StrToInt(V);
+    end
+  else
+    begin
+    Val(V,C,I);
+    If (I<>0) then
+      Fail(FScanner.CurTokenString+' does not contain a float value');
+    end;
+  AssertEquals('Parsed float equals original float',F,C);
+end;
+
+procedure TTestJSScanner.TestFloat;
+
+
+begin
+  DoTestFloat(1.2);
+  DoTestFloat(-1.2);
+  DoTestFloat(0);
+  DoTestFloat(1.2e1);
+  DoTestFloat(-1.2e1);
+  DoTestFloat(0);
+  DoTestFloat(1.2,'1.2');
+  DoTestFloat(-1.2,'-1.2');
+  DoTestFloat(0,'0.0');
+  DoTestFloat(255,'0xff')
+end;
+
+procedure TTestJSScanner.TestFloatError;
+
+begin
+  FErrorSource:='1xz';
+  AssertException('Wrong float',EJSScannerError,@TestErrorSource);
+end;
+
+
+procedure TTestJSScanner.DoTestString(S: String);
+
+Var
+  J : TJSToken;
+  T : String;
+begin
+  CreateScanner(S);
+  J:=FScanner.FetchToken;
+  AssertEquals(S+' is a string',tjsString,J);
+  If (Length(S)>0) and (S[1] in ['"','''']) then
+    S:=Copy(S,2,Length(S)-2);
+  AssertEquals('Correct string is returned',S,FScanner.CurTokenString);
+end;
+
+procedure TTestJSScanner.TestString;
+
+begin
+  DoTestString('"A string"');
+  DoTestString('""');
+  DoTestString('''''');
+  DoTestString('''A string''');
+end;
+
+procedure TTestJSScanner.TestErrorSource;
+
+begin
+  CreateScanner(FErrorSource);
+  While (FScanner.FetchToken<>tjsEOF) do ;
+end;
+
+procedure TTestJSScanner.TestStringError;
+
+begin
+  FErrorSource:='"A string';
+  AssertException('Unterminated string',EJSScannerError,@TestErrorSource);
+  FErrorSource:='''A string';
+  AssertException('Unterminated string',EJSScannerError,@TestErrorSource);
+end;
+
+
+{ TTestLineReader }
+
+procedure TTestLineReader.CreateReader(AInput: String);
+begin
+  FData:=TStringStream.Create(AInput);
+  FReader:=TStreamLineReader.Create(FData);
+end;
+
+
+procedure TTestLineReader.TearDown;
+begin
+  FreeAndNil(FReader);
+  FreeAndNil(FData);
+end;
+
+procedure TTestLineReader.TestEmpty;
+begin
+  CreateReader('');
+  AssertEquals('Empty reader returns EOF',True,FReader.IsEOF);
+  AssertEquals('Empty reader returns empty string','',FReader.ReadLine);
+end;
+
+procedure TTestLineReader.TestReadLine;
+begin
+  CreateReader('Something');
+  AssertEquals('Reader with 1 line returns 1 line','Something',FReader.ReadLine);
+  AssertEquals('EOF true after reading line',True,FReader.IsEOF);
+end;
+
+procedure TTestLineReader.TestReadLines13;
+begin
+  CreateReader('Something'#13'else');
+  AssertEquals('Reader with 2 lines returns 1st line','Something',FReader.ReadLine);
+  AssertEquals('Reader with 2 lines returns 2nd line','else',FReader.ReadLine);
+  AssertEquals('EOF true after reading lines',True,FReader.IsEOF);
+end;
+
+procedure TTestLineReader.TestReadLines10;
+begin
+  CreateReader('Something'#10'else');
+  AssertEquals('Reader with 2 lines returns 1st line','Something',FReader.ReadLine);
+  AssertEquals('Reader with 2 lines returns 2nd line','else',FReader.ReadLine);
+  AssertEquals('EOF true after reading lines',True,FReader.IsEOF);
+end;
+
+procedure TTestLineReader.TestReadLines1310;
+begin
+  CreateReader('Something'#13#10'else');
+  AssertEquals('Reader with 2 lines returns 1st line','Something',FReader.ReadLine);
+  AssertEquals('Reader with 2 lines returns 2nd line','else',FReader.ReadLine);
+  AssertEquals('EOF true after reading lines',True,FReader.IsEOF);
+end;
+
+procedure TTestLineReader.TestReadLinesEOF13;
+begin
+  CreateReader('Something'#13);
+  AssertEquals('Reader with 2 lines + CR returns 1st line','Something',FReader.ReadLine);
+  AssertEquals('Reader with 1 lines + CR returns empty 2nd line','',FReader.ReadLine);
+  AssertEquals('EOF true after reading lines',True,FReader.IsEOF);
+end;
+
+procedure TTestLineReader.TestReadLinesEOF10;
+begin
+  CreateReader('Something'#10);
+  AssertEquals('Reader with 2 lines + LF returns 1st line','Something',FReader.ReadLine);
+  AssertEquals('Reader with 1 lines + LF returns empty 2nd line','',FReader.ReadLine);
+  AssertEquals('EOF true after reading lines',True,FReader.IsEOF);
+end;
+
+procedure TTestLineReader.TestReadLinesEOF1310;
+begin
+  CreateReader('Something'#13#10);
+  AssertEquals('Reader with 2 lines + CRLF returns 1st line','Something',FReader.ReadLine);
+  AssertEquals('Reader with 1 lines + CRLF returns empty 2nd line','',FReader.ReadLine);
+  AssertEquals('EOF true after reading lines',True,FReader.IsEOF);
+end;
+
+procedure TTestLineReader.TestReadEmptyLines101010;
+
+begin
+  CreateReader('Something'#10#10#10);
+  AssertEquals('Reader with 1 line + LFLFLF returns 1st line','Something',FReader.ReadLine);
+  AssertEquals('EOF false after reading line 1',False,FReader.IsEOF);
+  AssertEquals('Reader with 1 line + LFLFLF returns empty 2nd line','',FReader.ReadLine);
+  AssertEquals('EOF false after reading line 2',False,FReader.IsEOF);
+  AssertEquals('Reader with 1 line + LFLFLF returns empty 3nd line','',FReader.ReadLine);
+  AssertEquals('EOF true after reading lines',True,FReader.IsEOF);
+end;
+
+initialization
+
+  RegisterTests([TTestLineReader,TTestJSScanner]);
+end.
+

二進制
packages/fcl-js/tests/testjs.ico


+ 261 - 0
packages/fcl-js/tests/testjs.lpi

@@ -0,0 +1,261 @@
+<?xml version="1.0"?>
+<CONFIG>
+  <ProjectOptions>
+    <Version Value="7"/>
+    <General>
+      <MainUnit Value="0"/>
+      <TargetFileExt Value=""/>
+      <Icon Value="0"/>
+      <UseXPManifest Value="True"/>
+      <ActiveEditorIndexAtStart Value="1"/>
+    </General>
+    <VersionInfo>
+      <ProjectVersion Value=""/>
+      <Language Value=""/>
+      <CharSet Value=""/>
+    </VersionInfo>
+    <PublishOptions>
+      <Version Value="2"/>
+      <IgnoreBinaries Value="False"/>
+      <IncludeFileFilter Value="*.(pas|pp|inc|lfm|lpr|lrs|lpi|lpk|sh|xml)"/>
+      <ExcludeFileFilter Value="*.(bak|ppu|ppw|o|so);*~;backup"/>
+    </PublishOptions>
+    <RunParams>
+      <local>
+        <FormatVersion Value="1"/>
+        <CommandLineParams Value="-a --format=plain"/>
+        <LaunchingApplication PathPlusParams="/usr/X11R6/bin/xterm -T 'Lazarus Run Output' -e $(LazarusDir)/tools/runwait.sh $(TargetCmdLine)"/>
+      </local>
+    </RunParams>
+    <RequiredPackages Count="2">
+      <Item1>
+        <PackageName Value="FPCUnitConsoleRunner"/>
+      </Item1>
+      <Item2>
+        <PackageName Value="FCL"/>
+      </Item2>
+    </RequiredPackages>
+    <Units Count="7">
+      <Unit0>
+        <Filename Value="testjs.lpr"/>
+        <IsPartOfProject Value="True"/>
+        <UnitName Value="testjs"/>
+        <CursorPos X="11" Y="7"/>
+        <TopLine Value="1"/>
+        <EditorIndex Value="0"/>
+        <UsageCount Value="201"/>
+        <Loaded Value="True"/>
+      </Unit0>
+      <Unit1>
+        <Filename Value="tcscanner.pp"/>
+        <IsPartOfProject Value="True"/>
+        <UnitName Value="tcscanner"/>
+        <CursorPos X="27" Y="427"/>
+        <TopLine Value="416"/>
+        <EditorIndex Value="2"/>
+        <UsageCount Value="201"/>
+        <Loaded Value="True"/>
+      </Unit1>
+      <Unit2>
+        <Filename Value="../src/jsbase.pp"/>
+        <IsPartOfProject Value="True"/>
+        <UnitName Value="jsbase"/>
+        <CursorPos X="1" Y="153"/>
+        <TopLine Value="132"/>
+        <EditorIndex Value="1"/>
+        <UsageCount Value="196"/>
+        <Loaded Value="True"/>
+      </Unit2>
+      <Unit3>
+        <Filename Value="../src/jsparser.pp"/>
+        <IsPartOfProject Value="True"/>
+        <UnitName Value="jsparser"/>
+        <CursorPos X="1" Y="1"/>
+        <TopLine Value="1"/>
+        <UsageCount Value="201"/>
+      </Unit3>
+      <Unit4>
+        <Filename Value="../src/jsscanner.pp"/>
+        <IsPartOfProject Value="True"/>
+        <UnitName Value="JSScanner"/>
+        <CursorPos X="1" Y="1"/>
+        <TopLine Value="1"/>
+        <UsageCount Value="201"/>
+      </Unit4>
+      <Unit5>
+        <Filename Value="../src/jstree.pp"/>
+        <IsPartOfProject Value="True"/>
+        <UnitName Value="jstree"/>
+        <CursorPos X="1" Y="1"/>
+        <TopLine Value="1"/>
+        <UsageCount Value="200"/>
+      </Unit5>
+      <Unit6>
+        <Filename Value="tcparser.pp"/>
+        <IsPartOfProject Value="True"/>
+        <UnitName Value="tcparser"/>
+        <CursorPos X="3" Y="2059"/>
+        <TopLine Value="2051"/>
+        <EditorIndex Value="4"/>
+        <UsageCount Value="97"/>
+        <Loaded Value="True"/>
+      </Unit6>
+    </Units>
+    <JumpHistory Count="30" HistoryIndex="29">
+      <Position1>
+        <Filename Value="tcparser.pp"/>
+        <Caret Line="1752" Column="1" TopLine="1730"/>
+      </Position1>
+      <Position2>
+        <Filename Value="tcparser.pp"/>
+        <Caret Line="1767" Column="32" TopLine="1733"/>
+      </Position2>
+      <Position3>
+        <Filename Value="tcparser.pp"/>
+        <Caret Line="1790" Column="30" TopLine="1766"/>
+      </Position3>
+      <Position4>
+        <Filename Value="tcparser.pp"/>
+        <Caret Line="1763" Column="26" TopLine="1736"/>
+      </Position4>
+      <Position5>
+        <Filename Value="tcparser.pp"/>
+        <Caret Line="1791" Column="1" TopLine="1758"/>
+      </Position5>
+      <Position6>
+        <Filename Value="tcparser.pp"/>
+        <Caret Line="114" Column="30" TopLine="93"/>
+      </Position6>
+      <Position7>
+        <Filename Value="tcparser.pp"/>
+        <Caret Line="1806" Column="23" TopLine="1798"/>
+      </Position7>
+      <Position8>
+        <Filename Value="tcparser.pp"/>
+        <Caret Line="1828" Column="3" TopLine="1819"/>
+      </Position8>
+      <Position9>
+        <Filename Value="../../../../source/fcl-js/jsparser.pp"/>
+        <Caret Line="515" Column="28" TopLine="507"/>
+      </Position9>
+      <Position10>
+        <Filename Value="tcparser.pp"/>
+        <Caret Line="1824" Column="24" TopLine="1803"/>
+      </Position10>
+      <Position11>
+        <Filename Value="tcparser.pp"/>
+        <Caret Line="1828" Column="17" TopLine="1803"/>
+      </Position11>
+      <Position12>
+        <Filename Value="tcparser.pp"/>
+        <Caret Line="1849" Column="34" TopLine="1820"/>
+      </Position12>
+      <Position13>
+        <Filename Value="tcparser.pp"/>
+        <Caret Line="118" Column="27" TopLine="96"/>
+      </Position13>
+      <Position14>
+        <Filename Value="tcparser.pp"/>
+        <Caret Line="1900" Column="29" TopLine="1888"/>
+      </Position14>
+      <Position15>
+        <Filename Value="tcparser.pp"/>
+        <Caret Line="1898" Column="12" TopLine="1877"/>
+      </Position15>
+      <Position16>
+        <Filename Value="tcparser.pp"/>
+        <Caret Line="1904" Column="80" TopLine="1883"/>
+      </Position16>
+      <Position17>
+        <Filename Value="tcparser.pp"/>
+        <Caret Line="1914" Column="29" TopLine="1883"/>
+      </Position17>
+      <Position18>
+        <Filename Value="tcparser.pp"/>
+        <Caret Line="1948" Column="18" TopLine="1914"/>
+      </Position18>
+      <Position19>
+        <Filename Value="tcparser.pp"/>
+        <Caret Line="20" Column="1" TopLine="1"/>
+      </Position19>
+      <Position20>
+        <Filename Value="tcparser.pp"/>
+        <Caret Line="2165" Column="1" TopLine="2124"/>
+      </Position20>
+      <Position21>
+        <Filename Value="tcparser.pp"/>
+        <Caret Line="121" Column="27" TopLine="99"/>
+      </Position21>
+      <Position22>
+        <Filename Value="tcparser.pp"/>
+        <Caret Line="1969" Column="3" TopLine="1960"/>
+      </Position22>
+      <Position23>
+        <Filename Value="tcparser.pp"/>
+        <Caret Line="1971" Column="46" TopLine="1950"/>
+      </Position23>
+      <Position24>
+        <Filename Value="tcparser.pp"/>
+        <Caret Line="1986" Column="14" TopLine="1961"/>
+      </Position24>
+      <Position25>
+        <Filename Value="tcparser.pp"/>
+        <Caret Line="1993" Column="33" TopLine="1960"/>
+      </Position25>
+      <Position26>
+        <Filename Value="../../../../source/fcl-js/jsparser.pp"/>
+        <Caret Line="1702" Column="24" TopLine="1685"/>
+      </Position26>
+      <Position27>
+        <Filename Value="tcparser.pp"/>
+        <Caret Line="124" Column="25" TopLine="100"/>
+      </Position27>
+      <Position28>
+        <Filename Value="tcparser.pp"/>
+        <Caret Line="2038" Column="10" TopLine="2035"/>
+      </Position28>
+      <Position29>
+        <Filename Value="tcparser.pp"/>
+        <Caret Line="2075" Column="56" TopLine="2051"/>
+      </Position29>
+      <Position30>
+        <Filename Value="../../../../source/fcl-js/jsparser.pp"/>
+        <Caret Line="1747" Column="29" TopLine="1740"/>
+      </Position30>
+    </JumpHistory>
+  </ProjectOptions>
+  <CompilerOptions>
+    <Version Value="8"/>
+    <SearchPaths>
+      <IncludeFiles Value="$(ProjOutDir)/"/>
+      <OtherUnitFiles Value="/home/michael/source/fcl-js/;../"/>
+    </SearchPaths>
+    <CodeGeneration>
+      <Optimizations>
+        <OptimizationLevel Value="0"/>
+      </Optimizations>
+    </CodeGeneration>
+    <Other>
+      <CompilerPath Value="$(CompPath)"/>
+    </Other>
+  </CompilerOptions>
+  <Debugging>
+    <BreakPoints Count="1">
+      <Item1>
+        <Source Value="../jsscanner.pp"/>
+        <Line Value="717"/>
+      </Item1>
+    </BreakPoints>
+    <Exceptions Count="3">
+      <Item1>
+        <Name Value="EAbort"/>
+      </Item1>
+      <Item2>
+        <Name Value="ECodetoolError"/>
+      </Item2>
+      <Item3>
+        <Name Value="EFOpenError"/>
+      </Item3>
+    </Exceptions>
+  </Debugging>
+</CONFIG>

+ 29 - 0
packages/fcl-js/tests/testjs.lpr

@@ -0,0 +1,29 @@
+program testjs;
+
+{$mode objfpc}{$H+}
+
+uses
+  Classes, consoletestrunner, tcscanner, jsparser, jsscanner, jstree, jsbase,
+  tcparser;
+
+type
+
+  { TLazTestRunner }
+
+  TMyTestRunner = class(TTestRunner)
+  protected
+  // override the protected methods of TTestRunner to customize its behavior
+  end;
+
+var
+  Application: TMyTestRunner;
+
+{$IFDEF WINDOWS}{$R testjs.rc}{$ENDIF}
+
+begin
+  Application := TMyTestRunner.Create(nil);
+  Application.Initialize;
+  Application.Title := 'FPCUnit Console test runner';
+  Application.Run;
+  Application.Free;
+end.

+ 17 - 0
packages/fcl-js/tests/testjs.manifest

@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
+ <assemblyIdentity version="1.0.0.0" processorArchitecture="*" name="CompanyName.ProductName.YourApp" type="win32"/>
+ <description>Your application description here.</description>
+ <dependency>
+  <dependentAssembly>
+   <assemblyIdentity type="win32" name="Microsoft.Windows.Common-Controls" version="6.0.0.0" processorArchitecture="*" publicKeyToken="6595b64144ccf1df" language="*"/>
+  </dependentAssembly>
+ </dependency>
+ <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
+  <security>
+   <requestedPrivileges>
+    <requestedExecutionLevel level="asInvoker" uiAccess="false"/>
+   </requestedPrivileges>
+  </security>
+ </trustInfo>
+</assembly>

+ 1 - 0
packages/fcl-js/tests/testjs.rc

@@ -0,0 +1 @@
+MAINICON ICON "testjs.ico"