xmlui 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/Pdf-DeGhSMXe.mjs +19537 -0
- package/dist/Pdf.css +1 -0
- package/dist/apiInterceptorWorker-CwuUhYyc.mjs +9229 -0
- package/dist/array-USo-Szhp.mjs +12 -0
- package/dist/index-C24dkfpd.mjs +1434 -0
- package/dist/index-ao27SnVp.mjs +145185 -0
- package/dist/index.css +1 -0
- package/dist/nivo-bar.es-CWh0ZlxB.mjs +1666 -0
- package/dist/nivo-geo.es-BTqNt5Db.mjs +1579 -0
- package/dist/nivo-legends.es-BuIxHGSU.mjs +6916 -0
- package/dist/nivo-pie.es-BvCBFA0L.mjs +700 -0
- package/dist/react-apexcharts.min-DqWuDOyO.mjs +8881 -0
- package/dist/scripts/bin/bootstrap.js +11 -0
- package/dist/scripts/bin/build.js +256 -0
- package/dist/scripts/bin/index.js +88 -0
- package/dist/scripts/bin/preview.js +27 -0
- package/dist/scripts/bin/start.js +41 -0
- package/dist/scripts/bin/vite-ueml-plugin.js +113 -0
- package/dist/scripts/bin/viteConfig.js +112 -0
- package/dist/scripts/src/abstractions/ActionDefs.js +2 -0
- package/dist/scripts/src/abstractions/AppContextDefs.js +2 -0
- package/dist/scripts/src/abstractions/BlockScope.js +4 -0
- package/dist/scripts/src/abstractions/ComponentDefs.js +2 -0
- package/dist/scripts/src/abstractions/ComponentDescriptorDefs.js +2 -0
- package/dist/scripts/src/abstractions/ContainerDefs.js +2 -0
- package/dist/scripts/src/abstractions/FunctionDefs.js +2 -0
- package/dist/scripts/src/abstractions/RendererDefs.js +2 -0
- package/dist/scripts/src/abstractions/scripting/ScriptParserError.js +2 -0
- package/dist/scripts/src/abstractions/scripting/ScriptingSourceTree.js +2 -0
- package/dist/scripts/src/abstractions/scripting/Token.js +110 -0
- package/dist/scripts/src/components/App/App.js +253 -0
- package/dist/scripts/src/components/App/AppLayoutContext.js +9 -0
- package/dist/scripts/src/components/App/AppStateContext.js +9 -0
- package/dist/scripts/src/components/App/Sheet.js +89 -0
- package/dist/scripts/src/components/AppHeader/AppHeader.js +121 -0
- package/dist/scripts/src/components/AppState/AppState.js +29 -0
- package/dist/scripts/src/components/Avatar/Avatar.js +81 -0
- package/dist/scripts/src/components/Badge/Badge.js +56 -0
- package/dist/scripts/src/components/BarChart/BarChart.js +199 -0
- package/dist/scripts/src/components/Bookmark/Bookmark.js +11 -0
- package/dist/scripts/src/components/Button/Button.js +196 -0
- package/dist/scripts/src/components/Card/Card.js +65 -0
- package/dist/scripts/src/components/ChangeListener/ChangeListener.js +43 -0
- package/dist/scripts/src/components/Chart/Chart.js +158 -0
- package/dist/scripts/src/components/Checkbox/Checkbox.js +43 -0
- package/dist/scripts/src/components/Combobox/Combobox.js +145 -0
- package/dist/scripts/src/components/ComponentProvider.js +357 -0
- package/dist/scripts/src/components/ContentSeparator/ContentSeparator.js +40 -0
- package/dist/scripts/src/components/DatePicker/DatePicker.js +196 -0
- package/dist/scripts/src/components/DropdownMenu/DropdownMenu.js +175 -0
- package/dist/scripts/src/components/EmojiSelector/EmojiSelector.js +56 -0
- package/dist/scripts/src/components/FileInput/FileInput.js +127 -0
- package/dist/scripts/src/components/FileUploadDropZone/FileUploadDropZone.js +106 -0
- package/dist/scripts/src/components/FlowLayout/FlowLayout.js +139 -0
- package/dist/scripts/src/components/Footer/Footer.js +42 -0
- package/dist/scripts/src/components/Form/Form.js +320 -0
- package/dist/scripts/src/components/Form/FormContext.js +9 -0
- package/dist/scripts/src/components/Form/formActions.js +86 -0
- package/dist/scripts/src/components/FormItem/FormItem.js +204 -0
- package/dist/scripts/src/components/FormItem/HelperText.js +27 -0
- package/dist/scripts/src/components/FormItem/ItemWithLabel.js +39 -0
- package/dist/scripts/src/components/FormItem/Validations.js +346 -0
- package/dist/scripts/src/components/FormSection/FormSection.js +45 -0
- package/dist/scripts/src/components/Heading/Heading.js +206 -0
- package/dist/scripts/src/components/HoverCard/HoverCard.js +45 -0
- package/dist/scripts/src/components/Icon/ApiIcon.js +10 -0
- package/dist/scripts/src/components/Icon/Attach.js +10 -0
- package/dist/scripts/src/components/Icon/Binding.js +11 -0
- package/dist/scripts/src/components/Icon/BoardIcon.js +7 -0
- package/dist/scripts/src/components/Icon/BoxIcon.js +10 -0
- package/dist/scripts/src/components/Icon/CheckIcon.js +7 -0
- package/dist/scripts/src/components/Icon/ChevronDownIcon.js +7 -0
- package/dist/scripts/src/components/Icon/ChevronLeft.js +7 -0
- package/dist/scripts/src/components/Icon/ChevronRight.js +7 -0
- package/dist/scripts/src/components/Icon/ChevronUpIcon.js +7 -0
- package/dist/scripts/src/components/Icon/CodeFileIcon.js +10 -0
- package/dist/scripts/src/components/Icon/CodeSandbox.js +10 -0
- package/dist/scripts/src/components/Icon/CompactListIcon.js +7 -0
- package/dist/scripts/src/components/Icon/ContentCopyIcon.js +7 -0
- package/dist/scripts/src/components/Icon/DatabaseIcon.js +11 -0
- package/dist/scripts/src/components/Icon/DocFileIcon.js +10 -0
- package/dist/scripts/src/components/Icon/DocIcon.js +10 -0
- package/dist/scripts/src/components/Icon/DotMenuHorizontalIcon.js +7 -0
- package/dist/scripts/src/components/Icon/DotMenuIcon.js +7 -0
- package/dist/scripts/src/components/Icon/EmailIcon.js +7 -0
- package/dist/scripts/src/components/Icon/EmptyFolderIcon.js +10 -0
- package/dist/scripts/src/components/Icon/ErrorIcon.js +7 -0
- package/dist/scripts/src/components/Icon/ExpressionIcon.js +10 -0
- package/dist/scripts/src/components/Icon/FillPlusCricleIcon.js +7 -0
- package/dist/scripts/src/components/Icon/FilterIcon.js +10 -0
- package/dist/scripts/src/components/Icon/FolderIcon.js +10 -0
- package/dist/scripts/src/components/Icon/GlobeIcon.js +7 -0
- package/dist/scripts/src/components/Icon/HomeIcon.js +7 -0
- package/dist/scripts/src/components/Icon/HyperLinkIcon.js +7 -0
- package/dist/scripts/src/components/Icon/Icon.js +101 -0
- package/dist/scripts/src/components/Icon/ImageFileIcon.js +10 -0
- package/dist/scripts/src/components/Icon/LinkIcon.js +7 -0
- package/dist/scripts/src/components/Icon/ListIcon.js +7 -0
- package/dist/scripts/src/components/Icon/LooseListIcon.js +7 -0
- package/dist/scripts/src/components/Icon/MoonIcon.js +10 -0
- package/dist/scripts/src/components/Icon/MoreOptionsIcon.js +7 -0
- package/dist/scripts/src/components/Icon/PDFIcon.js +10 -0
- package/dist/scripts/src/components/Icon/PenIcon.js +7 -0
- package/dist/scripts/src/components/Icon/PhoneIcon.js +7 -0
- package/dist/scripts/src/components/Icon/PhotoIcon.js +10 -0
- package/dist/scripts/src/components/Icon/PlusIcon.js +7 -0
- package/dist/scripts/src/components/Icon/SearchIcon.js +7 -0
- package/dist/scripts/src/components/Icon/ShareIcon.js +10 -0
- package/dist/scripts/src/components/Icon/SunIcon.js +10 -0
- package/dist/scripts/src/components/Icon/TrashIcon.js +7 -0
- package/dist/scripts/src/components/Icon/TxtIcon.js +10 -0
- package/dist/scripts/src/components/Icon/UnknownFileIcon.js +10 -0
- package/dist/scripts/src/components/Icon/UnlinkIcon.js +10 -0
- package/dist/scripts/src/components/Icon/UserIcon.js +7 -0
- package/dist/scripts/src/components/Icon/WarningIcon.js +7 -0
- package/dist/scripts/src/components/Icon/XlsIcon.js +10 -0
- package/dist/scripts/src/components/IconProvider.js +249 -0
- package/dist/scripts/src/components/IconRegistryContext.js +307 -0
- package/dist/scripts/src/components/Image/Image.js +34 -0
- package/dist/scripts/src/components/Input/InputAdornment.js +14 -0
- package/dist/scripts/src/components/Input/input-abstractions.js +44 -0
- package/dist/scripts/src/components/Items/Items.js +48 -0
- package/dist/scripts/src/components/Link/Link.js +72 -0
- package/dist/scripts/src/components/List/List.js +442 -0
- package/dist/scripts/src/components/Logo/Logo.js +25 -0
- package/dist/scripts/src/components/Map/Map.js +60 -0
- package/dist/scripts/src/components/Map/world_countries.json +45307 -0
- package/dist/scripts/src/components/Markdown/Markdown.js +120 -0
- package/dist/scripts/src/components/ModalDialog/ConfirmationModalContextProvider.js +106 -0
- package/dist/scripts/src/components/ModalDialog/Dialog.js +20 -0
- package/dist/scripts/src/components/ModalDialog/ModalDialog.js +145 -0
- package/dist/scripts/src/components/MultiCombobox/MultiCombobox.js +249 -0
- package/dist/scripts/src/components/MultiSelect/MultiSelect.js +192 -0
- package/dist/scripts/src/components/NavGroup/NavGroup.js +113 -0
- package/dist/scripts/src/components/NavLink/NavLink.js +115 -0
- package/dist/scripts/src/components/NavPanel/NavPanel.js +101 -0
- package/dist/scripts/src/components/NoResult/NoResult.js +39 -0
- package/dist/scripts/src/components/NumberBox/NumberBox.js +373 -0
- package/dist/scripts/src/components/Option/Option.js +41 -0
- package/dist/scripts/src/components/PageMetaTitle/PageMetaTitle.js +22 -0
- package/dist/scripts/src/components/Pages/Pages.js +74 -0
- package/dist/scripts/src/components/Pdf/LazyPdf.js +44 -0
- package/dist/scripts/src/components/Pdf/Pdf.js +19 -0
- package/dist/scripts/src/components/PieChart/PieChart.js +184 -0
- package/dist/scripts/src/components/PositionedContainer/PositionedContainer.js +29 -0
- package/dist/scripts/src/components/ProgressBar/ProgressBar.js +38 -0
- package/dist/scripts/src/components/Queue/Queue.js +286 -0
- package/dist/scripts/src/components/Queue/queueActions.js +87 -0
- package/dist/scripts/src/components/RadioGroup/RadioGroup.js +144 -0
- package/dist/scripts/src/components/RealTimeAdapter/RealTimeAdapter.js +147 -0
- package/dist/scripts/src/components/Redirect/Redirect.js +10 -0
- package/dist/scripts/src/components/Select/Select.js +139 -0
- package/dist/scripts/src/components/Select/SelectContext.js +45 -0
- package/dist/scripts/src/components/SelectionStore/SelectionStore.js +88 -0
- package/dist/scripts/src/components/SpaceFiller/SpaceFiller.js +22 -0
- package/dist/scripts/src/components/Spinner/Spinner.js +59 -0
- package/dist/scripts/src/components/Splitter/Splitter.js +205 -0
- package/dist/scripts/src/components/Splitter/utils.js +17 -0
- package/dist/scripts/src/components/Stack/Stack.js +117 -0
- package/dist/scripts/src/components/StickyBox/StickyBox.js +33 -0
- package/dist/scripts/src/components/Switch/Switch.js +50 -0
- package/dist/scripts/src/components/Table/Table.js +499 -0
- package/dist/scripts/src/components/Table/useRowSelection.js +169 -0
- package/dist/scripts/src/components/TableColumnDef/TableColumnDef.js +44 -0
- package/dist/scripts/src/components/TableColumnDef/TableContext.js +12 -0
- package/dist/scripts/src/components/Tabs/Tabs.js +85 -0
- package/dist/scripts/src/components/Text/Text.js +175 -0
- package/dist/scripts/src/components/TextArea/TextArea.js +194 -0
- package/dist/scripts/src/components/TextArea/TextAreaResizable.js +63 -0
- package/dist/scripts/src/components/TextArea/useComposedRef.js +50 -0
- package/dist/scripts/src/components/TextBox/TextBox.js +145 -0
- package/dist/scripts/src/components/Theme/NotificationToast.js +39 -0
- package/dist/scripts/src/components/Theme/Theme.js +153 -0
- package/dist/scripts/src/components/ThemeChanger/ThemeChanger.js +125 -0
- package/dist/scripts/src/components/Toggle/Toggle.js +88 -0
- package/dist/scripts/src/components/Tree/TreeComponent.js +79 -0
- package/dist/scripts/src/components/ValidationSummary/ValidationSummary.js +59 -0
- package/dist/scripts/src/components/ViewComponentRegistryContext.js +34 -0
- package/dist/scripts/src/components/abstractions.js +2 -0
- package/dist/scripts/src/components/chart-color-schemes.js +43 -0
- package/dist/scripts/src/components/component-utils.js +32 -0
- package/dist/scripts/src/components/container-helpers.js +18 -0
- package/dist/scripts/src/components-core/ApiBoundComponent.js +189 -0
- package/dist/scripts/src/components-core/AppContext.js +17 -0
- package/dist/scripts/src/components-core/ChildrenSlot.js +10 -0
- package/dist/scripts/src/components-core/Component.js +280 -0
- package/dist/scripts/src/components-core/ComponentDecorator.js +63 -0
- package/dist/scripts/src/components-core/CompoundComponent.js +132 -0
- package/dist/scripts/src/components-core/EngineError.js +91 -0
- package/dist/scripts/src/components-core/ErrorBoundary.js +58 -0
- package/dist/scripts/src/components-core/Fragment.js +14 -0
- package/dist/scripts/src/components-core/InvalidComponent.js +15 -0
- package/dist/scripts/src/components-core/LoaderComponent.js +78 -0
- package/dist/scripts/src/components-core/RestApiProxy.js +341 -0
- package/dist/scripts/src/components-core/RootComponent.js +272 -0
- package/dist/scripts/src/components-core/RouteContext.js +45 -0
- package/dist/scripts/src/components-core/ScrollContext.js +9 -0
- package/dist/scripts/src/components-core/UnknownComponent.js +15 -0
- package/dist/scripts/src/components-core/abstractions/ComponentRenderer.js +2 -0
- package/dist/scripts/src/components-core/abstractions/LoaderRenderer.js +2 -0
- package/dist/scripts/src/components-core/abstractions/containers.js +18 -0
- package/dist/scripts/src/components-core/abstractions/treeAbstractions.js +2 -0
- package/dist/scripts/src/components-core/action/ApiAction.js +276 -0
- package/dist/scripts/src/components-core/action/DownloadFileAction.js +80 -0
- package/dist/scripts/src/components-core/action/NavigateAction.js +20 -0
- package/dist/scripts/src/components-core/action/TimedAction.js +21 -0
- package/dist/scripts/src/components-core/action/UploadAction.js +88 -0
- package/dist/scripts/src/components-core/action/actions.js +15 -0
- package/dist/scripts/src/components-core/appContext/date-functions.js +19 -0
- package/dist/scripts/src/components-core/appContext/misc-utils.js +12 -0
- package/dist/scripts/src/components-core/component-hooks.js +25 -0
- package/dist/scripts/src/components-core/constants.js +18 -0
- package/dist/scripts/src/components-core/container/Container.js +1110 -0
- package/dist/scripts/src/components-core/container/ContainerComponentDef.js +16 -0
- package/dist/scripts/src/components-core/container/buildProxy.js +54 -0
- package/dist/scripts/src/components-core/container/collectFnVarDeps.js +26 -0
- package/dist/scripts/src/components-core/container/valueExtractor.js +195 -0
- package/dist/scripts/src/components-core/descriptorHelper.js +75 -0
- package/dist/scripts/src/components-core/interception/abstractions.js +2 -0
- package/dist/scripts/src/components-core/interception/useApiInterceptorContext.js +9 -0
- package/dist/scripts/src/components-core/loader/ApiLoader.js +46 -0
- package/dist/scripts/src/components-core/loader/DataLoader.js +160 -0
- package/dist/scripts/src/components-core/loader/ExternalDataLoader.js +52 -0
- package/dist/scripts/src/components-core/loader/Loader.js +115 -0
- package/dist/scripts/src/components-core/loader/MockLoaderRenderer.js +32 -0
- package/dist/scripts/src/components-core/loader/PageableLoader.js +240 -0
- package/dist/scripts/src/components-core/renderers.js +45 -0
- package/dist/scripts/src/components-core/reportEngineError.js +59 -0
- package/dist/scripts/src/components-core/script-runner/BindingTreeEvaluationContext.js +35 -0
- package/dist/scripts/src/components-core/script-runner/ICustomOperations.js +34 -0
- package/dist/scripts/src/components-core/script-runner/LogicalThread.js +2 -0
- package/dist/scripts/src/components-core/script-runner/LoopScope.js +2 -0
- package/dist/scripts/src/components-core/script-runner/ParameterParser.js +117 -0
- package/dist/scripts/src/components-core/script-runner/TryScope.js +2 -0
- package/dist/scripts/src/components-core/script-runner/asyncProxy.js +96 -0
- package/dist/scripts/src/components-core/script-runner/bannedFunctions.js +34 -0
- package/dist/scripts/src/components-core/script-runner/custom-operations-registry.js +40 -0
- package/dist/scripts/src/components-core/script-runner/custom-ui-data.js +40 -0
- package/dist/scripts/src/components-core/script-runner/eval-tree-async.js +551 -0
- package/dist/scripts/src/components-core/script-runner/eval-tree-common.js +498 -0
- package/dist/scripts/src/components-core/script-runner/eval-tree-sync.js +434 -0
- package/dist/scripts/src/components-core/script-runner/modules.js +250 -0
- package/dist/scripts/src/components-core/script-runner/process-statement-async.js +818 -0
- package/dist/scripts/src/components-core/script-runner/process-statement-common.js +193 -0
- package/dist/scripts/src/components-core/script-runner/process-statement-sync.js +740 -0
- package/dist/scripts/src/components-core/script-runner/statement-queue.js +62 -0
- package/dist/scripts/src/components-core/script-runner/visitors.js +352 -0
- package/dist/scripts/src/components-core/theming/ThemeContext.js +43 -0
- package/dist/scripts/src/components-core/theming/ThemeProvider.js +334 -0
- package/dist/scripts/src/components-core/theming/abstractions.js +11 -0
- package/dist/scripts/src/components-core/theming/extendThemeUtils.js +114 -0
- package/dist/scripts/src/components-core/theming/hvar.js +105 -0
- package/dist/scripts/src/components-core/theming/themeVars.js +62 -0
- package/dist/scripts/src/components-core/theming/themes/base-utils.js +31 -0
- package/dist/scripts/src/components-core/theming/themes/palette.js +53 -0
- package/dist/scripts/src/components-core/theming/themes/root.js +257 -0
- package/dist/scripts/src/components-core/theming/themes/solid.js +16 -0
- package/dist/scripts/src/components-core/theming/themes/theme-colors.js +407 -0
- package/dist/scripts/src/components-core/theming/themes/xmlui.js +32 -0
- package/dist/scripts/src/components-core/theming/transformThemeVars.js +286 -0
- package/dist/scripts/src/components-core/utils/DataLoaderQueryKeyGenerator.js +34 -0
- package/dist/scripts/src/components-core/utils/LruCache.js +184 -0
- package/dist/scripts/src/components-core/utils/actionUtils.js +32 -0
- package/dist/scripts/src/components-core/utils/classnames.js +58 -0
- package/dist/scripts/src/components-core/utils/css-utils.js +127 -0
- package/dist/scripts/src/components-core/utils/date-utils.js +78 -0
- package/dist/scripts/src/components-core/utils/extractParam.js +148 -0
- package/dist/scripts/src/components-core/utils/hooks.js +221 -0
- package/dist/scripts/src/components-core/utils/mergeProps.js +45 -0
- package/dist/scripts/src/components-core/utils/misc.js +460 -0
- package/dist/scripts/src/components-core/utils/statementUtils.js +205 -0
- package/dist/scripts/src/components-core/utils/treeUtils.js +48 -0
- package/dist/scripts/src/components-core/xmlui-parser.js +52 -0
- package/dist/scripts/src/parsers/scripting/InputStream.js +59 -0
- package/dist/scripts/src/parsers/scripting/Lexer.js +1028 -0
- package/dist/scripts/src/parsers/scripting/Parser.js +2647 -0
- package/dist/scripts/src/parsers/scripting/ParserError.js +46 -0
- package/dist/scripts/src/parsers/scripting/TokenTrait.js +109 -0
- package/dist/scripts/src/parsers/scripting/code-behind-collect.js +118 -0
- package/dist/scripts/src/parsers/scripting/tree-visitor.js +602 -0
- package/dist/scripts/src/parsers/style-parser/StyleInputStream.js +39 -0
- package/dist/scripts/src/parsers/style-parser/StyleLexer.js +621 -0
- package/dist/scripts/src/parsers/style-parser/StyleParser.js +1000 -0
- package/dist/scripts/src/parsers/style-parser/errors.js +37 -0
- package/dist/scripts/src/parsers/style-parser/source-tree.js +2 -0
- package/dist/scripts/src/parsers/style-parser/style-compiler.js +513 -0
- package/dist/scripts/src/parsers/style-parser/tokens.js +42 -0
- package/dist/scripts/src/parsers/ueml/ParserError.js +54 -0
- package/dist/scripts/src/parsers/ueml/UemlHelper.js +579 -0
- package/dist/scripts/src/parsers/ueml/UemlInputStream.js +59 -0
- package/dist/scripts/src/parsers/ueml/UemlLexer.js +868 -0
- package/dist/scripts/src/parsers/ueml/UemlParser.js +1439 -0
- package/dist/scripts/src/parsers/ueml/UemlToken.js +24 -0
- package/dist/scripts/src/parsers/ueml/fileExtensions.js +6 -0
- package/dist/scripts/src/parsers/ueml/source-tree.js +2 -0
- package/dist/scripts/src/parsers/ueml/ueml-tree.js +2 -0
- package/dist/scripts/src/parsers/xmlui-parser/CharacterCodes.js +136 -0
- package/dist/scripts/src/parsers/xmlui-parser/diagnostics.js +100 -0
- package/dist/scripts/src/parsers/xmlui-parser/parser.js +476 -0
- package/dist/scripts/src/parsers/xmlui-parser/scanner.js +415 -0
- package/dist/scripts/src/parsers/xmlui-parser/syntax-kind.js +106 -0
- package/dist/scripts/src/parsers/xmlui-parser/syntax-node.js +2 -0
- package/dist/scripts/src/parsers/xmlui-parser/transform.js +922 -0
- package/dist/scripts/src/parsers/xmlui-parser/utils.js +83 -0
- package/dist/xmlui.es.d.ts +1667 -0
- package/dist/xmlui.es.js +17 -0
- package/dist/xmlui.umd.js +1589 -0
- package/package.json +175 -0
|
@@ -0,0 +1,2647 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Parser = void 0;
|
|
4
|
+
const Token_1 = require("../../abstractions/scripting/Token");
|
|
5
|
+
const InputStream_1 = require("./InputStream");
|
|
6
|
+
const TokenTrait_1 = require("./TokenTrait");
|
|
7
|
+
const Lexer_1 = require("./Lexer");
|
|
8
|
+
const ParserError_1 = require("./ParserError");
|
|
9
|
+
/**
|
|
10
|
+
* States of the string parsing
|
|
11
|
+
*/
|
|
12
|
+
var StrParseState;
|
|
13
|
+
(function (StrParseState) {
|
|
14
|
+
StrParseState[StrParseState["Normal"] = 0] = "Normal";
|
|
15
|
+
StrParseState[StrParseState["Backslash"] = 1] = "Backslash";
|
|
16
|
+
StrParseState[StrParseState["X"] = 2] = "X";
|
|
17
|
+
StrParseState[StrParseState["Xh"] = 3] = "Xh";
|
|
18
|
+
StrParseState[StrParseState["UX1"] = 4] = "UX1";
|
|
19
|
+
StrParseState[StrParseState["UX2"] = 5] = "UX2";
|
|
20
|
+
StrParseState[StrParseState["UX3"] = 6] = "UX3";
|
|
21
|
+
StrParseState[StrParseState["UX4"] = 7] = "UX4";
|
|
22
|
+
StrParseState[StrParseState["Ucp1"] = 8] = "Ucp1";
|
|
23
|
+
StrParseState[StrParseState["Ucp2"] = 9] = "Ucp2";
|
|
24
|
+
StrParseState[StrParseState["Ucp3"] = 10] = "Ucp3";
|
|
25
|
+
StrParseState[StrParseState["Ucp4"] = 11] = "Ucp4";
|
|
26
|
+
StrParseState[StrParseState["Ucp5"] = 12] = "Ucp5";
|
|
27
|
+
StrParseState[StrParseState["Ucp6"] = 13] = "Ucp6";
|
|
28
|
+
StrParseState[StrParseState["UcpTail"] = 14] = "UcpTail";
|
|
29
|
+
})(StrParseState || (StrParseState = {}));
|
|
30
|
+
/**
|
|
31
|
+
* This class parses a binding expression and transforms it into an evaluable expression tree
|
|
32
|
+
*/
|
|
33
|
+
class Parser {
|
|
34
|
+
/**
|
|
35
|
+
* Initializes the parser with the specified source code
|
|
36
|
+
* @param source Source code to parse
|
|
37
|
+
*/
|
|
38
|
+
constructor(source) {
|
|
39
|
+
this.source = source;
|
|
40
|
+
// --- Keep track of error messages
|
|
41
|
+
this._parseErrors = [];
|
|
42
|
+
// --- Indicates the parsing level
|
|
43
|
+
this._statementLevel = 0;
|
|
44
|
+
this._lexer = new Lexer_1.Lexer(new InputStream_1.InputStream(source));
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* The errors raised during the parse phase
|
|
48
|
+
*/
|
|
49
|
+
get errors() {
|
|
50
|
+
return this._parseErrors;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Gets the current token
|
|
54
|
+
*/
|
|
55
|
+
get current() {
|
|
56
|
+
return this._lexer.peek();
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Checks if we're at the end of the expression
|
|
60
|
+
*/
|
|
61
|
+
get isEof() {
|
|
62
|
+
return this._lexer.peek().type === Token_1.TokenType.Eof;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Gets the characters remaining after parsing
|
|
66
|
+
*/
|
|
67
|
+
getTail() {
|
|
68
|
+
return this._lexer.getTail();
|
|
69
|
+
}
|
|
70
|
+
// ==========================================================================
|
|
71
|
+
// Statement parsing
|
|
72
|
+
/**
|
|
73
|
+
* Parses a list of statements:
|
|
74
|
+
*
|
|
75
|
+
* statements
|
|
76
|
+
* : statement*
|
|
77
|
+
* ;
|
|
78
|
+
*
|
|
79
|
+
* statement
|
|
80
|
+
* : emptyStatement
|
|
81
|
+
* | expressionStatement
|
|
82
|
+
* | letStatement
|
|
83
|
+
* | returnStatement
|
|
84
|
+
* ;
|
|
85
|
+
*/
|
|
86
|
+
parseStatements() {
|
|
87
|
+
this._statementLevel = 0;
|
|
88
|
+
const statements = [];
|
|
89
|
+
while (!this.isEof) {
|
|
90
|
+
const statement = this.parseStatement();
|
|
91
|
+
if (!statement)
|
|
92
|
+
return null;
|
|
93
|
+
statements.push(statement);
|
|
94
|
+
if (statement.type !== "EmptyS") {
|
|
95
|
+
this.skipToken(Token_1.TokenType.Semicolon);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
return statements;
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Parses a single statement
|
|
102
|
+
*/
|
|
103
|
+
parseStatement(allowSequence = true) {
|
|
104
|
+
this._statementLevel++;
|
|
105
|
+
try {
|
|
106
|
+
const startToken = this._lexer.peek();
|
|
107
|
+
switch (startToken.type) {
|
|
108
|
+
case Token_1.TokenType.Semicolon:
|
|
109
|
+
return this.parseEmptyStatement();
|
|
110
|
+
case Token_1.TokenType.Let:
|
|
111
|
+
return this.parseLetStatement();
|
|
112
|
+
case Token_1.TokenType.Const:
|
|
113
|
+
return this.parseConstStatement();
|
|
114
|
+
case Token_1.TokenType.Var:
|
|
115
|
+
return this.parseVarStatement();
|
|
116
|
+
case Token_1.TokenType.LBrace:
|
|
117
|
+
return this.parseBlockStatement();
|
|
118
|
+
case Token_1.TokenType.If:
|
|
119
|
+
return this.parseIfStatement();
|
|
120
|
+
case Token_1.TokenType.Do:
|
|
121
|
+
return this.parseDoWhileStatement();
|
|
122
|
+
case Token_1.TokenType.While:
|
|
123
|
+
return this.parseWhileStatement();
|
|
124
|
+
case Token_1.TokenType.Return:
|
|
125
|
+
return this.parseReturnStatement();
|
|
126
|
+
case Token_1.TokenType.Break:
|
|
127
|
+
this._lexer.get();
|
|
128
|
+
return this.createStatementNode("BrkS", {}, startToken, startToken);
|
|
129
|
+
case Token_1.TokenType.Continue:
|
|
130
|
+
this._lexer.get();
|
|
131
|
+
return this.createStatementNode("ContS", {}, startToken, startToken);
|
|
132
|
+
case Token_1.TokenType.For:
|
|
133
|
+
return this.parseForStatement();
|
|
134
|
+
case Token_1.TokenType.Throw:
|
|
135
|
+
return this.parseThrowStatement();
|
|
136
|
+
case Token_1.TokenType.Try:
|
|
137
|
+
return this.parseTryStatement();
|
|
138
|
+
case Token_1.TokenType.Switch:
|
|
139
|
+
return this.parseSwitchStatement();
|
|
140
|
+
case Token_1.TokenType.Function:
|
|
141
|
+
return this.parseFunctionDeclaration();
|
|
142
|
+
case Token_1.TokenType.Export:
|
|
143
|
+
return this.parseExport();
|
|
144
|
+
case Token_1.TokenType.Import:
|
|
145
|
+
return this.parseImport();
|
|
146
|
+
default:
|
|
147
|
+
if (startToken.type === Token_1.TokenType.Eof) {
|
|
148
|
+
this.reportError("W002", startToken, "EOF");
|
|
149
|
+
return null;
|
|
150
|
+
}
|
|
151
|
+
if (this.isExpressionStart(startToken)) {
|
|
152
|
+
return this.parseExpressionStatement(allowSequence);
|
|
153
|
+
}
|
|
154
|
+
this.reportError("W002", startToken, startToken.text);
|
|
155
|
+
return null;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
finally {
|
|
159
|
+
this._statementLevel--;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Parses an empty statement
|
|
164
|
+
*
|
|
165
|
+
* emptyStatement
|
|
166
|
+
* : ";"
|
|
167
|
+
* ;
|
|
168
|
+
*/
|
|
169
|
+
parseEmptyStatement() {
|
|
170
|
+
const startToken = this._lexer.get();
|
|
171
|
+
return this.createStatementNode("EmptyS", {}, startToken, startToken);
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Parses an expression statement
|
|
175
|
+
*
|
|
176
|
+
* expressionStatement
|
|
177
|
+
* : expression
|
|
178
|
+
* ;
|
|
179
|
+
*/
|
|
180
|
+
parseExpressionStatement(allowSequence = true) {
|
|
181
|
+
const startToken = this._lexer.peek();
|
|
182
|
+
const expression = this.getExpression(allowSequence);
|
|
183
|
+
return expression
|
|
184
|
+
? this.createStatementNode("ExprS", {
|
|
185
|
+
expression,
|
|
186
|
+
}, startToken, expression.endToken)
|
|
187
|
+
: null;
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* Parses a let statement
|
|
191
|
+
*
|
|
192
|
+
* letStatement
|
|
193
|
+
* : "let" id ["=" expression] ("," id ["=" expression])*
|
|
194
|
+
* ;
|
|
195
|
+
*/
|
|
196
|
+
parseLetStatement() {
|
|
197
|
+
const startToken = this._lexer.get();
|
|
198
|
+
let endToken = startToken;
|
|
199
|
+
const declarations = [];
|
|
200
|
+
while (true) {
|
|
201
|
+
const declStart = this._lexer.peek();
|
|
202
|
+
let declarationProps = {};
|
|
203
|
+
if (declStart.type === Token_1.TokenType.LBrace) {
|
|
204
|
+
// --- This is object destructure
|
|
205
|
+
endToken = this._lexer.ahead(1);
|
|
206
|
+
const objectDestruct = this.parseObjectDestructure();
|
|
207
|
+
if (objectDestruct === null)
|
|
208
|
+
return null;
|
|
209
|
+
declarationProps = {
|
|
210
|
+
objectDestruct,
|
|
211
|
+
};
|
|
212
|
+
endToken = objectDestruct.length > 0 ? objectDestruct[objectDestruct.length - 1].endToken : endToken;
|
|
213
|
+
}
|
|
214
|
+
else if (declStart.type === Token_1.TokenType.LSquare) {
|
|
215
|
+
// --- This is array destructure
|
|
216
|
+
endToken = this._lexer.ahead(1);
|
|
217
|
+
const arrayDestruct = this.parseArrayDestructure();
|
|
218
|
+
if (arrayDestruct === null)
|
|
219
|
+
return null;
|
|
220
|
+
declarationProps = {
|
|
221
|
+
arrayDestruct,
|
|
222
|
+
};
|
|
223
|
+
endToken = arrayDestruct.length > 0 ? arrayDestruct[arrayDestruct.length - 1].endToken : endToken;
|
|
224
|
+
}
|
|
225
|
+
else if (declStart.type === Token_1.TokenType.Identifier) {
|
|
226
|
+
endToken = this._lexer.get();
|
|
227
|
+
declarationProps = {
|
|
228
|
+
id: declStart.text,
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
else {
|
|
232
|
+
this.reportError("W003");
|
|
233
|
+
return null;
|
|
234
|
+
}
|
|
235
|
+
// --- Optional initialization
|
|
236
|
+
const initToken = this._lexer.peek();
|
|
237
|
+
let expression = null;
|
|
238
|
+
if (initToken.type === Token_1.TokenType.Assignment) {
|
|
239
|
+
this._lexer.get();
|
|
240
|
+
expression = this.getExpression(false);
|
|
241
|
+
if (expression === null)
|
|
242
|
+
return null;
|
|
243
|
+
declarationProps.expression = expression;
|
|
244
|
+
endToken = expression.endToken;
|
|
245
|
+
}
|
|
246
|
+
else if (declarationProps.arrayDestruct || declarationProps.objectDestruct) {
|
|
247
|
+
this.reportError("W009", initToken);
|
|
248
|
+
return null;
|
|
249
|
+
}
|
|
250
|
+
// --- New declaration reached
|
|
251
|
+
declarations.push(this.createExpressionNode("VarD", declarationProps, declStart, endToken));
|
|
252
|
+
// --- Check for more declarations
|
|
253
|
+
if (this._lexer.peek().type !== Token_1.TokenType.Comma)
|
|
254
|
+
break;
|
|
255
|
+
this._lexer.get();
|
|
256
|
+
}
|
|
257
|
+
// --- Done
|
|
258
|
+
return this.createStatementNode("LetS", {
|
|
259
|
+
declarations,
|
|
260
|
+
}, startToken, endToken);
|
|
261
|
+
}
|
|
262
|
+
/**
|
|
263
|
+
* Parses a const statement
|
|
264
|
+
*
|
|
265
|
+
* constStatement
|
|
266
|
+
* : "const" id "=" expression
|
|
267
|
+
* ;
|
|
268
|
+
*/
|
|
269
|
+
parseConstStatement() {
|
|
270
|
+
const startToken = this._lexer.get();
|
|
271
|
+
let endToken = startToken;
|
|
272
|
+
const declarations = [];
|
|
273
|
+
while (true) {
|
|
274
|
+
const declStart = this._lexer.peek();
|
|
275
|
+
let declarationProps = {};
|
|
276
|
+
if (declStart.type === Token_1.TokenType.LBrace) {
|
|
277
|
+
// --- This is object destructure
|
|
278
|
+
endToken = this._lexer.ahead(1);
|
|
279
|
+
const objectDestruct = this.parseObjectDestructure();
|
|
280
|
+
if (objectDestruct === null)
|
|
281
|
+
return null;
|
|
282
|
+
declarationProps = {
|
|
283
|
+
objectDestruct,
|
|
284
|
+
};
|
|
285
|
+
endToken = objectDestruct.length > 0 ? objectDestruct[objectDestruct.length - 1].endToken : endToken;
|
|
286
|
+
}
|
|
287
|
+
else if (declStart.type === Token_1.TokenType.LSquare) {
|
|
288
|
+
// --- This is array destructure
|
|
289
|
+
endToken = this._lexer.ahead(1);
|
|
290
|
+
const arrayDestruct = this.parseArrayDestructure();
|
|
291
|
+
if (arrayDestruct === null)
|
|
292
|
+
return null;
|
|
293
|
+
declarationProps = {
|
|
294
|
+
arrayDestruct,
|
|
295
|
+
};
|
|
296
|
+
endToken = arrayDestruct.length > 0 ? arrayDestruct[arrayDestruct.length - 1].endToken : endToken;
|
|
297
|
+
}
|
|
298
|
+
else if (declStart.type === Token_1.TokenType.Identifier) {
|
|
299
|
+
endToken = this._lexer.get();
|
|
300
|
+
declarationProps = {
|
|
301
|
+
id: declStart.text,
|
|
302
|
+
};
|
|
303
|
+
}
|
|
304
|
+
else {
|
|
305
|
+
this.reportError("W003");
|
|
306
|
+
return null;
|
|
307
|
+
}
|
|
308
|
+
this.expectToken(Token_1.TokenType.Assignment);
|
|
309
|
+
const expression = this.getExpression(false);
|
|
310
|
+
if (expression === null)
|
|
311
|
+
return null;
|
|
312
|
+
declarationProps.expression = expression;
|
|
313
|
+
endToken = expression.endToken;
|
|
314
|
+
// --- New declaration reached
|
|
315
|
+
declarations.push(this.createExpressionNode("VarD", declarationProps, declStart, endToken));
|
|
316
|
+
// --- Check for more declarations
|
|
317
|
+
if (this._lexer.peek().type !== Token_1.TokenType.Comma)
|
|
318
|
+
break;
|
|
319
|
+
this._lexer.get();
|
|
320
|
+
}
|
|
321
|
+
// --- Done
|
|
322
|
+
return this.createStatementNode("ConstS", {
|
|
323
|
+
declarations,
|
|
324
|
+
}, startToken, endToken);
|
|
325
|
+
}
|
|
326
|
+
/**
|
|
327
|
+
* Parses a const statement
|
|
328
|
+
*
|
|
329
|
+
* constStatement
|
|
330
|
+
* : "var" id "=" expression
|
|
331
|
+
* ;
|
|
332
|
+
*/
|
|
333
|
+
parseVarStatement() {
|
|
334
|
+
const startToken = this._lexer.get();
|
|
335
|
+
let endToken = startToken;
|
|
336
|
+
const declarations = [];
|
|
337
|
+
while (true) {
|
|
338
|
+
const declStart = this._lexer.peek();
|
|
339
|
+
let declarationProps = {};
|
|
340
|
+
if (declStart.type === Token_1.TokenType.Identifier) {
|
|
341
|
+
endToken = this._lexer.get();
|
|
342
|
+
declarationProps = {
|
|
343
|
+
id: declStart.text,
|
|
344
|
+
};
|
|
345
|
+
}
|
|
346
|
+
else {
|
|
347
|
+
this.reportError("W003");
|
|
348
|
+
return null;
|
|
349
|
+
}
|
|
350
|
+
// --- Mandatory initialization
|
|
351
|
+
this.expectToken(Token_1.TokenType.Assignment);
|
|
352
|
+
const expression = this.getExpression(false);
|
|
353
|
+
if (expression === null)
|
|
354
|
+
return null;
|
|
355
|
+
declarationProps.expression = expression;
|
|
356
|
+
endToken = expression.endToken;
|
|
357
|
+
// --- New declaration reached
|
|
358
|
+
declarations.push(this.createExpressionNode("RVarD", declarationProps, declStart, endToken));
|
|
359
|
+
// --- Check for more declarations
|
|
360
|
+
if (this._lexer.peek().type !== Token_1.TokenType.Comma)
|
|
361
|
+
break;
|
|
362
|
+
this._lexer.get();
|
|
363
|
+
}
|
|
364
|
+
// --- Done
|
|
365
|
+
return this.createStatementNode("VarS", {
|
|
366
|
+
declarations,
|
|
367
|
+
}, startToken, endToken);
|
|
368
|
+
}
|
|
369
|
+
/**
|
|
370
|
+
* Parses an object destructure expression
|
|
371
|
+
*/
|
|
372
|
+
parseObjectDestructure() {
|
|
373
|
+
const result = [];
|
|
374
|
+
// --- Skip the starting left brace
|
|
375
|
+
const startToken = this._lexer.get();
|
|
376
|
+
let endToken = startToken;
|
|
377
|
+
let nextToken = this._lexer.peek();
|
|
378
|
+
while (nextToken.type === Token_1.TokenType.Identifier) {
|
|
379
|
+
// --- Obtain the ID
|
|
380
|
+
const id = nextToken.text;
|
|
381
|
+
let alias;
|
|
382
|
+
let arrayDestruct;
|
|
383
|
+
let objectDestruct;
|
|
384
|
+
this._lexer.get();
|
|
385
|
+
nextToken = this._lexer.peek();
|
|
386
|
+
if (nextToken.type === Token_1.TokenType.Colon) {
|
|
387
|
+
// --- Check the available cases
|
|
388
|
+
this._lexer.get();
|
|
389
|
+
nextToken = this._lexer.peek();
|
|
390
|
+
if (nextToken.type === Token_1.TokenType.Identifier) {
|
|
391
|
+
alias = nextToken.text;
|
|
392
|
+
endToken = nextToken;
|
|
393
|
+
this._lexer.get();
|
|
394
|
+
}
|
|
395
|
+
else if (nextToken.type === Token_1.TokenType.LSquare) {
|
|
396
|
+
arrayDestruct = this.parseArrayDestructure();
|
|
397
|
+
if (arrayDestruct === null)
|
|
398
|
+
return null;
|
|
399
|
+
endToken = arrayDestruct[arrayDestruct.length - 1].endToken;
|
|
400
|
+
}
|
|
401
|
+
else if (nextToken.type === Token_1.TokenType.LBrace) {
|
|
402
|
+
objectDestruct = this.parseObjectDestructure();
|
|
403
|
+
if (objectDestruct === null)
|
|
404
|
+
return null;
|
|
405
|
+
endToken = objectDestruct[objectDestruct.length - 1].endToken;
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
// --- Check for next segment
|
|
409
|
+
nextToken = this._lexer.peek();
|
|
410
|
+
if (nextToken.type === Token_1.TokenType.Comma || nextToken.type === Token_1.TokenType.RBrace) {
|
|
411
|
+
result.push(this.createExpressionNode("ODestr", { id, alias, arrayDestruct, objectDestruct }, startToken, endToken));
|
|
412
|
+
if (nextToken.type === Token_1.TokenType.Comma) {
|
|
413
|
+
// --- Skip the delimiter comma
|
|
414
|
+
this._lexer.get();
|
|
415
|
+
nextToken = this._lexer.peek();
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
// --- Expect a closing right brace
|
|
420
|
+
this.expectToken(Token_1.TokenType.RBrace, "W004");
|
|
421
|
+
return result;
|
|
422
|
+
}
|
|
423
|
+
parseArrayDestructure() {
|
|
424
|
+
const result = [];
|
|
425
|
+
// --- Skip the starting left square
|
|
426
|
+
const startToken = this._lexer.get();
|
|
427
|
+
let endToken = startToken;
|
|
428
|
+
do {
|
|
429
|
+
let nextToken = this._lexer.peek();
|
|
430
|
+
let id;
|
|
431
|
+
let arrayDestruct;
|
|
432
|
+
let objectDestruct;
|
|
433
|
+
if (nextToken.type === Token_1.TokenType.Identifier) {
|
|
434
|
+
id = nextToken.text;
|
|
435
|
+
endToken = nextToken;
|
|
436
|
+
nextToken = this._lexer.get();
|
|
437
|
+
}
|
|
438
|
+
else if (nextToken.type === Token_1.TokenType.LSquare) {
|
|
439
|
+
arrayDestruct = this.parseArrayDestructure();
|
|
440
|
+
if (arrayDestruct === null)
|
|
441
|
+
return null;
|
|
442
|
+
endToken = arrayDestruct[arrayDestruct.length - 1].endToken;
|
|
443
|
+
}
|
|
444
|
+
else if (nextToken.type === Token_1.TokenType.LBrace) {
|
|
445
|
+
objectDestruct = this.parseObjectDestructure();
|
|
446
|
+
if (objectDestruct === null)
|
|
447
|
+
return null;
|
|
448
|
+
endToken = objectDestruct[objectDestruct.length - 1].endToken;
|
|
449
|
+
}
|
|
450
|
+
nextToken = this._lexer.peek();
|
|
451
|
+
if (nextToken.type === Token_1.TokenType.Comma) {
|
|
452
|
+
// --- Store the segment
|
|
453
|
+
result.push(this.createExpressionNode("ADestr", { id, arrayDestruct, objectDestruct }, startToken, endToken));
|
|
454
|
+
this._lexer.get();
|
|
455
|
+
}
|
|
456
|
+
else if (nextToken.type === Token_1.TokenType.RSquare) {
|
|
457
|
+
if (id || arrayDestruct || objectDestruct) {
|
|
458
|
+
// --- Store a non-empty the segment
|
|
459
|
+
result.push(this.createExpressionNode("ADestr", { id, arrayDestruct, objectDestruct }, startToken, endToken));
|
|
460
|
+
}
|
|
461
|
+
break;
|
|
462
|
+
}
|
|
463
|
+
else {
|
|
464
|
+
this.reportError("W002", nextToken);
|
|
465
|
+
return null;
|
|
466
|
+
}
|
|
467
|
+
} while (true);
|
|
468
|
+
// --- Expect a closing right square
|
|
469
|
+
this.expectToken(Token_1.TokenType.RSquare, "W005");
|
|
470
|
+
return result;
|
|
471
|
+
}
|
|
472
|
+
/**
|
|
473
|
+
* Parses a block statement
|
|
474
|
+
*
|
|
475
|
+
* blockStatement
|
|
476
|
+
* : "{" (statement [";"])* "}"
|
|
477
|
+
* ;
|
|
478
|
+
*/
|
|
479
|
+
parseBlockStatement() {
|
|
480
|
+
const startToken = this._lexer.get();
|
|
481
|
+
const statements = [];
|
|
482
|
+
while (this._lexer.peek().type !== Token_1.TokenType.RBrace) {
|
|
483
|
+
const statement = this.parseStatement();
|
|
484
|
+
if (!statement)
|
|
485
|
+
return null;
|
|
486
|
+
statements.push(statement);
|
|
487
|
+
if (statement.type !== "EmptyS") {
|
|
488
|
+
this.skipToken(Token_1.TokenType.Semicolon);
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
const endToken = this._lexer.get();
|
|
492
|
+
return this.createStatementNode("BlockS", { statements }, startToken, endToken);
|
|
493
|
+
}
|
|
494
|
+
/**
|
|
495
|
+
* Parses an if statement
|
|
496
|
+
*
|
|
497
|
+
* ifStatement
|
|
498
|
+
* : "if" "(" expression ")" statement ["else" statement]
|
|
499
|
+
* ;
|
|
500
|
+
*/
|
|
501
|
+
parseIfStatement() {
|
|
502
|
+
const startToken = this._lexer.get();
|
|
503
|
+
let endToken = startToken;
|
|
504
|
+
this.expectToken(Token_1.TokenType.LParent, "W014");
|
|
505
|
+
const condition = this.getExpression();
|
|
506
|
+
if (!condition)
|
|
507
|
+
return null;
|
|
508
|
+
this.expectToken(Token_1.TokenType.RParent, "W006");
|
|
509
|
+
const thenBranch = this.parseStatement();
|
|
510
|
+
if (!thenBranch)
|
|
511
|
+
return null;
|
|
512
|
+
endToken = thenBranch.endToken;
|
|
513
|
+
let elseCanFollow = true;
|
|
514
|
+
if (thenBranch.type !== "BlockS") {
|
|
515
|
+
// --- We need a closing semicolon before else
|
|
516
|
+
if (this._lexer.peek().type === Token_1.TokenType.Semicolon) {
|
|
517
|
+
this._lexer.get();
|
|
518
|
+
}
|
|
519
|
+
else {
|
|
520
|
+
elseCanFollow = false;
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
let elseBranch = null;
|
|
524
|
+
if (elseCanFollow && this._lexer.peek().type === Token_1.TokenType.Else) {
|
|
525
|
+
this._lexer.get();
|
|
526
|
+
elseBranch = this.parseStatement();
|
|
527
|
+
if (!elseBranch)
|
|
528
|
+
return null;
|
|
529
|
+
endToken = elseBranch.endToken;
|
|
530
|
+
}
|
|
531
|
+
return this.createStatementNode("IfS", {
|
|
532
|
+
condition,
|
|
533
|
+
thenBranch,
|
|
534
|
+
elseBranch,
|
|
535
|
+
}, startToken, endToken);
|
|
536
|
+
}
|
|
537
|
+
/**
|
|
538
|
+
* Parses a while statement
|
|
539
|
+
*
|
|
540
|
+
* whileStatement
|
|
541
|
+
* : "while" "(" condition ")" statement
|
|
542
|
+
* ;
|
|
543
|
+
*/
|
|
544
|
+
parseWhileStatement() {
|
|
545
|
+
const startToken = this._lexer.get();
|
|
546
|
+
this.expectToken(Token_1.TokenType.LParent, "W014");
|
|
547
|
+
const condition = this.getExpression();
|
|
548
|
+
if (!condition)
|
|
549
|
+
return null;
|
|
550
|
+
this.expectToken(Token_1.TokenType.RParent, "W006");
|
|
551
|
+
const body = this.parseStatement();
|
|
552
|
+
if (!body)
|
|
553
|
+
return null;
|
|
554
|
+
return this.createStatementNode("WhileS", {
|
|
555
|
+
condition,
|
|
556
|
+
body,
|
|
557
|
+
}, startToken, body.endToken);
|
|
558
|
+
}
|
|
559
|
+
/**
|
|
560
|
+
* Parses a do-while statement
|
|
561
|
+
*
|
|
562
|
+
* doWhileStatement
|
|
563
|
+
* : "do" statement "while" "(" condition ")"
|
|
564
|
+
* ;
|
|
565
|
+
*/
|
|
566
|
+
parseDoWhileStatement() {
|
|
567
|
+
const startToken = this._lexer.get();
|
|
568
|
+
const body = this.parseStatement();
|
|
569
|
+
if (!body)
|
|
570
|
+
return null;
|
|
571
|
+
if (body.type !== "BlockS" && body.type !== "EmptyS") {
|
|
572
|
+
this.expectToken(Token_1.TokenType.Semicolon);
|
|
573
|
+
}
|
|
574
|
+
this.expectToken(Token_1.TokenType.While);
|
|
575
|
+
this.expectToken(Token_1.TokenType.LParent, "W014");
|
|
576
|
+
const condition = this.getExpression();
|
|
577
|
+
if (!condition)
|
|
578
|
+
return null;
|
|
579
|
+
const endToken = this._lexer.peek();
|
|
580
|
+
this.expectToken(Token_1.TokenType.RParent, "W006");
|
|
581
|
+
return this.createStatementNode("DoWS", {
|
|
582
|
+
condition,
|
|
583
|
+
body,
|
|
584
|
+
}, startToken, endToken);
|
|
585
|
+
}
|
|
586
|
+
/**
|
|
587
|
+
* Parses an expression statement
|
|
588
|
+
*
|
|
589
|
+
* returnStatement
|
|
590
|
+
* : "return" expression?
|
|
591
|
+
* ;
|
|
592
|
+
*/
|
|
593
|
+
parseReturnStatement() {
|
|
594
|
+
const startToken = this._lexer.peek();
|
|
595
|
+
let endToken = this._lexer.get();
|
|
596
|
+
let expression;
|
|
597
|
+
if (TokenTrait_1.tokenTraits[this._lexer.peek().type].expressionStart) {
|
|
598
|
+
expression = this.getExpression();
|
|
599
|
+
if (expression === null)
|
|
600
|
+
return null;
|
|
601
|
+
endToken = expression.endToken;
|
|
602
|
+
}
|
|
603
|
+
return this.createStatementNode("RetS", {
|
|
604
|
+
expression,
|
|
605
|
+
}, startToken, endToken);
|
|
606
|
+
}
|
|
607
|
+
/**
|
|
608
|
+
* forStatement
|
|
609
|
+
* : "for" "(" initStatement? ";" expression? ";" expression? ")" statement
|
|
610
|
+
* | forInOfStatement
|
|
611
|
+
* ;
|
|
612
|
+
*/
|
|
613
|
+
parseForStatement() {
|
|
614
|
+
const startToken = this._lexer.peek();
|
|
615
|
+
this._lexer.get();
|
|
616
|
+
this.expectToken(Token_1.TokenType.LParent, "W014");
|
|
617
|
+
// --- Check for..in and for..of
|
|
618
|
+
let nextToken = this._lexer.peek();
|
|
619
|
+
if (nextToken.type === Token_1.TokenType.Identifier) {
|
|
620
|
+
if (this._lexer.ahead(1).type === Token_1.TokenType.In) {
|
|
621
|
+
return this.parseForInOfStatement(startToken, "none", nextToken.text, "ForInS");
|
|
622
|
+
}
|
|
623
|
+
else if (this._lexer.ahead(1).type === Token_1.TokenType.Of) {
|
|
624
|
+
return this.parseForInOfStatement(startToken, "none", nextToken.text, "ForOfS");
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
else if (nextToken.type === Token_1.TokenType.Let) {
|
|
628
|
+
const idToken = this._lexer.ahead(1);
|
|
629
|
+
if (idToken.type === Token_1.TokenType.Identifier) {
|
|
630
|
+
const inOfToken = this._lexer.ahead(2);
|
|
631
|
+
if (inOfToken.type === Token_1.TokenType.In) {
|
|
632
|
+
return this.parseForInOfStatement(startToken, "let", idToken.text, "ForInS");
|
|
633
|
+
}
|
|
634
|
+
else if (inOfToken.type === Token_1.TokenType.Of) {
|
|
635
|
+
return this.parseForInOfStatement(startToken, "let", idToken.text, "ForOfS");
|
|
636
|
+
}
|
|
637
|
+
}
|
|
638
|
+
}
|
|
639
|
+
else if (nextToken.type === Token_1.TokenType.Const) {
|
|
640
|
+
const idToken = this._lexer.ahead(1);
|
|
641
|
+
if (idToken.type === Token_1.TokenType.Identifier) {
|
|
642
|
+
const inOfToken = this._lexer.ahead(2);
|
|
643
|
+
if (inOfToken.type === Token_1.TokenType.In) {
|
|
644
|
+
return this.parseForInOfStatement(startToken, "const", idToken.text, "ForInS");
|
|
645
|
+
}
|
|
646
|
+
else if (inOfToken.type === Token_1.TokenType.Of) {
|
|
647
|
+
return this.parseForInOfStatement(startToken, "const", idToken.text, "ForOfS");
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
// --- We accept only let statement, empty statement, and expression
|
|
652
|
+
let init;
|
|
653
|
+
nextToken = this._lexer.peek();
|
|
654
|
+
if (nextToken.type === Token_1.TokenType.Semicolon) {
|
|
655
|
+
// --- Empty statement: no init in the for loop
|
|
656
|
+
this._lexer.get();
|
|
657
|
+
}
|
|
658
|
+
else if (nextToken.type === Token_1.TokenType.Let) {
|
|
659
|
+
// --- Let statement
|
|
660
|
+
const letStmt = this.parseLetStatement();
|
|
661
|
+
if (letStmt === null) {
|
|
662
|
+
return null;
|
|
663
|
+
}
|
|
664
|
+
init = letStmt;
|
|
665
|
+
if (init.declarations.some((d) => !d.expression)) {
|
|
666
|
+
this.reportError("W011");
|
|
667
|
+
return null;
|
|
668
|
+
}
|
|
669
|
+
this.expectToken(Token_1.TokenType.Semicolon);
|
|
670
|
+
}
|
|
671
|
+
else if (TokenTrait_1.tokenTraits[nextToken.type].expressionStart) {
|
|
672
|
+
// --- Expression statement
|
|
673
|
+
const exprStmt = this.parseExpressionStatement();
|
|
674
|
+
if (exprStmt === null) {
|
|
675
|
+
return null;
|
|
676
|
+
}
|
|
677
|
+
init = exprStmt;
|
|
678
|
+
this.expectToken(Token_1.TokenType.Semicolon);
|
|
679
|
+
}
|
|
680
|
+
// --- Parse the condition
|
|
681
|
+
let condition;
|
|
682
|
+
nextToken = this._lexer.peek();
|
|
683
|
+
if (nextToken.type === Token_1.TokenType.Semicolon) {
|
|
684
|
+
// --- No condition
|
|
685
|
+
this._lexer.get();
|
|
686
|
+
}
|
|
687
|
+
else {
|
|
688
|
+
condition = this.getExpression();
|
|
689
|
+
if (condition === null) {
|
|
690
|
+
return null;
|
|
691
|
+
}
|
|
692
|
+
this.expectToken(Token_1.TokenType.Semicolon);
|
|
693
|
+
}
|
|
694
|
+
// --- Parse the update expression
|
|
695
|
+
let update;
|
|
696
|
+
nextToken = this._lexer.peek();
|
|
697
|
+
if (nextToken.type !== Token_1.TokenType.RParent) {
|
|
698
|
+
update = this.getExpression();
|
|
699
|
+
if (update === null) {
|
|
700
|
+
return null;
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
// --- Close the declaration part
|
|
704
|
+
this.expectToken(Token_1.TokenType.RParent, "W006");
|
|
705
|
+
// --- Get the body
|
|
706
|
+
const body = this.parseStatement();
|
|
707
|
+
if (!body)
|
|
708
|
+
return null;
|
|
709
|
+
return this.createStatementNode("ForS", {
|
|
710
|
+
init,
|
|
711
|
+
condition,
|
|
712
|
+
update,
|
|
713
|
+
body,
|
|
714
|
+
}, startToken, body.endToken);
|
|
715
|
+
}
|
|
716
|
+
/**
|
|
717
|
+
* forInOfStatement
|
|
718
|
+
* : "for" "(" [ "let" | "const" ] identifier ( "in" | "of" ) expression? ")" statement
|
|
719
|
+
* | forInOfStatement
|
|
720
|
+
* ;
|
|
721
|
+
*
|
|
722
|
+
* @param startToken Statement start token
|
|
723
|
+
* @param varBinding Variable binding of the for..in/of statement
|
|
724
|
+
* @param id ID name
|
|
725
|
+
* @param type Is it a for..in or a for..of?
|
|
726
|
+
*/
|
|
727
|
+
parseForInOfStatement(startToken, varBinding, id, type) {
|
|
728
|
+
if (varBinding !== "none") {
|
|
729
|
+
// --- Skip variable binding type
|
|
730
|
+
this._lexer.get();
|
|
731
|
+
}
|
|
732
|
+
// --- Skip variable name, in/of token
|
|
733
|
+
this._lexer.get();
|
|
734
|
+
this._lexer.get();
|
|
735
|
+
// --- Get the expression
|
|
736
|
+
const expression = this.getExpression(true);
|
|
737
|
+
// --- Close the declaration part
|
|
738
|
+
this.expectToken(Token_1.TokenType.RParent, "W006");
|
|
739
|
+
// --- Get the body
|
|
740
|
+
const body = this.parseStatement();
|
|
741
|
+
if (!body)
|
|
742
|
+
return null;
|
|
743
|
+
return type === "ForInS"
|
|
744
|
+
? this.createStatementNode("ForInS", {
|
|
745
|
+
varBinding,
|
|
746
|
+
id,
|
|
747
|
+
expression,
|
|
748
|
+
body,
|
|
749
|
+
}, startToken, body.endToken)
|
|
750
|
+
: this.createStatementNode("ForOfS", {
|
|
751
|
+
varBinding,
|
|
752
|
+
id,
|
|
753
|
+
expression,
|
|
754
|
+
body,
|
|
755
|
+
}, startToken, body.endToken);
|
|
756
|
+
}
|
|
757
|
+
/**
|
|
758
|
+
* Parses a throw statement
|
|
759
|
+
*
|
|
760
|
+
* throwStatement
|
|
761
|
+
* : "throw" expression
|
|
762
|
+
* ;
|
|
763
|
+
*/
|
|
764
|
+
parseThrowStatement() {
|
|
765
|
+
const startToken = this._lexer.peek();
|
|
766
|
+
this._lexer.get();
|
|
767
|
+
let expression;
|
|
768
|
+
expression = this.getExpression();
|
|
769
|
+
if (expression === null)
|
|
770
|
+
return null;
|
|
771
|
+
return this.createStatementNode("ThrowS", {
|
|
772
|
+
expression,
|
|
773
|
+
}, startToken, expression.endToken);
|
|
774
|
+
}
|
|
775
|
+
/**
|
|
776
|
+
* Parses a try..catch..finally statement
|
|
777
|
+
*
|
|
778
|
+
* tryStatement
|
|
779
|
+
* : "try" blockStatement catchClause finallyClause?
|
|
780
|
+
* | "try" blockStatement catchClause? finallyClause
|
|
781
|
+
* ;
|
|
782
|
+
*
|
|
783
|
+
* catchClause
|
|
784
|
+
* : "catch" [ "(" identifier ") ]? blockStatement
|
|
785
|
+
* ;
|
|
786
|
+
*
|
|
787
|
+
* finallyClause
|
|
788
|
+
* : "finally" blockStatement
|
|
789
|
+
*/
|
|
790
|
+
parseTryStatement() {
|
|
791
|
+
const startToken = this._lexer.peek();
|
|
792
|
+
let endToken = this._lexer.get();
|
|
793
|
+
const parser = this;
|
|
794
|
+
// --- Get "try" block
|
|
795
|
+
const tryBlock = getBlock();
|
|
796
|
+
let catchBlock;
|
|
797
|
+
let catchVariable;
|
|
798
|
+
let finallyBlock;
|
|
799
|
+
let nextToken = this._lexer.peek();
|
|
800
|
+
if (nextToken.type === Token_1.TokenType.Catch) {
|
|
801
|
+
// --- Catch found
|
|
802
|
+
this._lexer.get();
|
|
803
|
+
nextToken = this._lexer.peek();
|
|
804
|
+
if (nextToken.type === Token_1.TokenType.LParent) {
|
|
805
|
+
// --- Catch variable found
|
|
806
|
+
this._lexer.get();
|
|
807
|
+
nextToken = this._lexer.peek();
|
|
808
|
+
if (nextToken.type !== Token_1.TokenType.Identifier) {
|
|
809
|
+
this.reportError("W003", nextToken);
|
|
810
|
+
return null;
|
|
811
|
+
}
|
|
812
|
+
catchVariable = nextToken.text;
|
|
813
|
+
this._lexer.get();
|
|
814
|
+
this.expectToken(Token_1.TokenType.RParent, "W006");
|
|
815
|
+
}
|
|
816
|
+
// --- Get catch block
|
|
817
|
+
catchBlock = getBlock();
|
|
818
|
+
endToken = catchBlock.endToken;
|
|
819
|
+
if (this._lexer.peek().type === Token_1.TokenType.Finally) {
|
|
820
|
+
// --- Finally after catch
|
|
821
|
+
this._lexer.get();
|
|
822
|
+
finallyBlock = getBlock();
|
|
823
|
+
endToken = finallyBlock.endToken;
|
|
824
|
+
}
|
|
825
|
+
}
|
|
826
|
+
else if (nextToken.type === Token_1.TokenType.Finally) {
|
|
827
|
+
// --- Finally found
|
|
828
|
+
this._lexer.get();
|
|
829
|
+
finallyBlock = getBlock();
|
|
830
|
+
endToken = finallyBlock.endToken;
|
|
831
|
+
}
|
|
832
|
+
else {
|
|
833
|
+
this.reportError("W013", nextToken);
|
|
834
|
+
return null;
|
|
835
|
+
}
|
|
836
|
+
return this.createStatementNode("TryS", {
|
|
837
|
+
tryBlock,
|
|
838
|
+
catchBlock,
|
|
839
|
+
catchVariable,
|
|
840
|
+
finallyBlock,
|
|
841
|
+
}, startToken, endToken);
|
|
842
|
+
function getBlock() {
|
|
843
|
+
const nextToken = parser._lexer.peek();
|
|
844
|
+
if (nextToken.type !== Token_1.TokenType.LBrace) {
|
|
845
|
+
parser.reportError("W012", nextToken);
|
|
846
|
+
return null;
|
|
847
|
+
}
|
|
848
|
+
return parser.parseBlockStatement();
|
|
849
|
+
}
|
|
850
|
+
}
|
|
851
|
+
/**
|
|
852
|
+
* Parses a switch statement
|
|
853
|
+
*
|
|
854
|
+
* switchStatement
|
|
855
|
+
* : "switch" "(" expression ")" "{" caseClauses "}"
|
|
856
|
+
* ;
|
|
857
|
+
*
|
|
858
|
+
* caseClauses
|
|
859
|
+
* : "case" expression ":" statement*
|
|
860
|
+
* | "default" ":" statement*
|
|
861
|
+
* ;
|
|
862
|
+
*/
|
|
863
|
+
parseSwitchStatement() {
|
|
864
|
+
const startToken = this._lexer.get();
|
|
865
|
+
// --- Parse the switch expression
|
|
866
|
+
this.expectToken(Token_1.TokenType.LParent, "W014");
|
|
867
|
+
const expression = this.getExpression();
|
|
868
|
+
if (!expression)
|
|
869
|
+
return null;
|
|
870
|
+
this.expectToken(Token_1.TokenType.RParent, "W006");
|
|
871
|
+
// --- Parse the case blocks
|
|
872
|
+
this.expectToken(Token_1.TokenType.LBrace, "W012");
|
|
873
|
+
const cases = [];
|
|
874
|
+
let defaultCaseFound = false;
|
|
875
|
+
while (true) {
|
|
876
|
+
let nextToken = this._lexer.peek();
|
|
877
|
+
let caseExpression;
|
|
878
|
+
if (nextToken.type === Token_1.TokenType.Case) {
|
|
879
|
+
// --- Process "case"
|
|
880
|
+
this._lexer.get();
|
|
881
|
+
caseExpression = this.getExpression();
|
|
882
|
+
if (!caseExpression)
|
|
883
|
+
return null;
|
|
884
|
+
}
|
|
885
|
+
else if (nextToken.type === Token_1.TokenType.Default) {
|
|
886
|
+
// --- Process "default"
|
|
887
|
+
if (defaultCaseFound) {
|
|
888
|
+
this.reportError("W016");
|
|
889
|
+
return null;
|
|
890
|
+
}
|
|
891
|
+
defaultCaseFound = true;
|
|
892
|
+
this._lexer.get();
|
|
893
|
+
}
|
|
894
|
+
else if (nextToken.type === Token_1.TokenType.RBrace) {
|
|
895
|
+
break;
|
|
896
|
+
}
|
|
897
|
+
else {
|
|
898
|
+
this.reportError("W015");
|
|
899
|
+
return null;
|
|
900
|
+
}
|
|
901
|
+
// --- Process label statements
|
|
902
|
+
this.expectToken(Token_1.TokenType.Colon, "W008");
|
|
903
|
+
let statements = [];
|
|
904
|
+
let collected = false;
|
|
905
|
+
while (!collected) {
|
|
906
|
+
const stmtToken = this._lexer.peek();
|
|
907
|
+
switch (stmtToken.type) {
|
|
908
|
+
case Token_1.TokenType.Case:
|
|
909
|
+
case Token_1.TokenType.Default:
|
|
910
|
+
case Token_1.TokenType.RBrace:
|
|
911
|
+
// --- No more case to process
|
|
912
|
+
collected = true;
|
|
913
|
+
break;
|
|
914
|
+
default:
|
|
915
|
+
// --- Try to get the next statement
|
|
916
|
+
const stmt = this.parseStatement();
|
|
917
|
+
if (stmt === null) {
|
|
918
|
+
collected = true;
|
|
919
|
+
break;
|
|
920
|
+
}
|
|
921
|
+
statements.push(stmt);
|
|
922
|
+
if (stmt.type !== "EmptyS") {
|
|
923
|
+
this.skipToken(Token_1.TokenType.Semicolon);
|
|
924
|
+
}
|
|
925
|
+
}
|
|
926
|
+
}
|
|
927
|
+
cases.push(this.createNode("SwitchC", {
|
|
928
|
+
caseExpression,
|
|
929
|
+
statements,
|
|
930
|
+
}, startToken));
|
|
931
|
+
}
|
|
932
|
+
// --- Closing
|
|
933
|
+
const endToken = this._lexer.peek();
|
|
934
|
+
this.expectToken(Token_1.TokenType.RBrace, "W004");
|
|
935
|
+
return this.createStatementNode("SwitchS", {
|
|
936
|
+
expression,
|
|
937
|
+
cases,
|
|
938
|
+
}, startToken, endToken);
|
|
939
|
+
}
|
|
940
|
+
/**
|
|
941
|
+
* Parses a function declaration
|
|
942
|
+
*
|
|
943
|
+
* functionDeclaration
|
|
944
|
+
* : "function" identifier "(" [parameterList] ")" blockStatement
|
|
945
|
+
* ;
|
|
946
|
+
*/
|
|
947
|
+
parseFunctionDeclaration() {
|
|
948
|
+
var _a;
|
|
949
|
+
const startToken = this._lexer.get();
|
|
950
|
+
// --- Get the function name
|
|
951
|
+
const funcId = this._lexer.peek();
|
|
952
|
+
if (funcId.type !== Token_1.TokenType.Identifier) {
|
|
953
|
+
this.reportError("W003", funcId);
|
|
954
|
+
return null;
|
|
955
|
+
}
|
|
956
|
+
this._lexer.get();
|
|
957
|
+
// --- Get the parameter list;
|
|
958
|
+
const nextToken = this._lexer.peek();
|
|
959
|
+
if (nextToken.type !== Token_1.TokenType.LParent) {
|
|
960
|
+
this.reportError("W014", nextToken);
|
|
961
|
+
return null;
|
|
962
|
+
}
|
|
963
|
+
// --- Now, get the parameter list as an expression
|
|
964
|
+
const exprList = this.getExpression(true);
|
|
965
|
+
// --- We turn the expression into a parameter list
|
|
966
|
+
let isValid;
|
|
967
|
+
const args = [];
|
|
968
|
+
switch (exprList.type) {
|
|
969
|
+
case "NoArgE":
|
|
970
|
+
isValid = true;
|
|
971
|
+
break;
|
|
972
|
+
case "IdE":
|
|
973
|
+
isValid = ((_a = exprList.parenthesized) !== null && _a !== void 0 ? _a : 0) <= 1;
|
|
974
|
+
args.push(exprList);
|
|
975
|
+
break;
|
|
976
|
+
case "SeqE":
|
|
977
|
+
isValid = exprList.parenthesized === 1;
|
|
978
|
+
if (isValid) {
|
|
979
|
+
for (const expr of exprList.expressions) {
|
|
980
|
+
switch (expr.type) {
|
|
981
|
+
case "IdE":
|
|
982
|
+
isValid = !expr.parenthesized;
|
|
983
|
+
args.push(expr);
|
|
984
|
+
break;
|
|
985
|
+
case "OLitE": {
|
|
986
|
+
isValid = !expr.parenthesized;
|
|
987
|
+
if (isValid) {
|
|
988
|
+
const des = this.convertToObjectDestructure(expr);
|
|
989
|
+
if (des)
|
|
990
|
+
args.push(des);
|
|
991
|
+
}
|
|
992
|
+
break;
|
|
993
|
+
}
|
|
994
|
+
case "ALitE": {
|
|
995
|
+
isValid = !expr.parenthesized;
|
|
996
|
+
if (isValid) {
|
|
997
|
+
const des = this.convertToArrayDestructure(expr);
|
|
998
|
+
if (des)
|
|
999
|
+
args.push(des);
|
|
1000
|
+
}
|
|
1001
|
+
break;
|
|
1002
|
+
}
|
|
1003
|
+
default:
|
|
1004
|
+
isValid = false;
|
|
1005
|
+
break;
|
|
1006
|
+
}
|
|
1007
|
+
}
|
|
1008
|
+
}
|
|
1009
|
+
break;
|
|
1010
|
+
case "OLitE":
|
|
1011
|
+
isValid = exprList.parenthesized === 1;
|
|
1012
|
+
if (isValid) {
|
|
1013
|
+
const des = this.convertToObjectDestructure(exprList);
|
|
1014
|
+
if (des)
|
|
1015
|
+
args.push(des);
|
|
1016
|
+
}
|
|
1017
|
+
break;
|
|
1018
|
+
case "ALitE":
|
|
1019
|
+
isValid = exprList.parenthesized === 1;
|
|
1020
|
+
if (isValid) {
|
|
1021
|
+
const des = this.convertToArrayDestructure(exprList);
|
|
1022
|
+
if (des)
|
|
1023
|
+
args.push(des);
|
|
1024
|
+
}
|
|
1025
|
+
break;
|
|
1026
|
+
default:
|
|
1027
|
+
isValid = false;
|
|
1028
|
+
}
|
|
1029
|
+
if (!isValid) {
|
|
1030
|
+
this.reportError("W010", startToken);
|
|
1031
|
+
return null;
|
|
1032
|
+
}
|
|
1033
|
+
// --- Get the function body (statement block)
|
|
1034
|
+
if (this._lexer.peek().type !== Token_1.TokenType.LBrace) {
|
|
1035
|
+
this.reportError("W012", this._lexer.peek());
|
|
1036
|
+
return null;
|
|
1037
|
+
}
|
|
1038
|
+
const body = this.parseBlockStatement();
|
|
1039
|
+
if (!body)
|
|
1040
|
+
return null;
|
|
1041
|
+
// --- Done.
|
|
1042
|
+
return this.createStatementNode("FuncD", {
|
|
1043
|
+
name: funcId.text,
|
|
1044
|
+
args,
|
|
1045
|
+
statement: body,
|
|
1046
|
+
}, startToken, body.endToken);
|
|
1047
|
+
}
|
|
1048
|
+
/**
|
|
1049
|
+
* Parses an export statement
|
|
1050
|
+
*
|
|
1051
|
+
* exportStatement
|
|
1052
|
+
* : "export" (constStatement | functionDeclaration)
|
|
1053
|
+
* ;
|
|
1054
|
+
*/
|
|
1055
|
+
parseExport() {
|
|
1056
|
+
this._lexer.get();
|
|
1057
|
+
const nextToken = this._lexer.peek();
|
|
1058
|
+
if (nextToken.type === Token_1.TokenType.Const) {
|
|
1059
|
+
if (this._statementLevel > 1) {
|
|
1060
|
+
this.reportError("W030", nextToken);
|
|
1061
|
+
return null;
|
|
1062
|
+
}
|
|
1063
|
+
const constStmt = this.parseConstStatement();
|
|
1064
|
+
return constStmt === null ? null : Object.assign(Object.assign({}, constStmt), { isExported: true });
|
|
1065
|
+
}
|
|
1066
|
+
else if (nextToken.type === Token_1.TokenType.Function) {
|
|
1067
|
+
if (this._statementLevel > 1) {
|
|
1068
|
+
this.reportError("W030", nextToken);
|
|
1069
|
+
return null;
|
|
1070
|
+
}
|
|
1071
|
+
const funcDecl = this.parseFunctionDeclaration();
|
|
1072
|
+
return funcDecl === null ? null : Object.assign(Object.assign({}, funcDecl), { isExported: true });
|
|
1073
|
+
}
|
|
1074
|
+
this.reportError("W024", nextToken);
|
|
1075
|
+
return null;
|
|
1076
|
+
}
|
|
1077
|
+
/**
|
|
1078
|
+
* Parse an import declaration
|
|
1079
|
+
*
|
|
1080
|
+
* importDeclaration
|
|
1081
|
+
* : "import" "{" importItem ("," importItem)* [ "," ] "}" from module
|
|
1082
|
+
* ;
|
|
1083
|
+
*
|
|
1084
|
+
* importItem
|
|
1085
|
+
* : identifier [ "as" identifier ]
|
|
1086
|
+
* ;
|
|
1087
|
+
*/
|
|
1088
|
+
parseImport() {
|
|
1089
|
+
const startToken = this._lexer.get();
|
|
1090
|
+
this.expectToken(Token_1.TokenType.LBrace, "W012");
|
|
1091
|
+
const imports = {};
|
|
1092
|
+
let nextToken = this._lexer.peek();
|
|
1093
|
+
while (nextToken.type !== Token_1.TokenType.RBrace) {
|
|
1094
|
+
if (nextToken.type !== Token_1.TokenType.Identifier) {
|
|
1095
|
+
this.reportError("W003", nextToken);
|
|
1096
|
+
return null;
|
|
1097
|
+
}
|
|
1098
|
+
const id = nextToken.text;
|
|
1099
|
+
this._lexer.get();
|
|
1100
|
+
nextToken = this._lexer.peek();
|
|
1101
|
+
if (nextToken.type === Token_1.TokenType.As) {
|
|
1102
|
+
this._lexer.get();
|
|
1103
|
+
nextToken = this._lexer.peek();
|
|
1104
|
+
if (nextToken.type !== Token_1.TokenType.Identifier) {
|
|
1105
|
+
this.reportError("W003", nextToken);
|
|
1106
|
+
return null;
|
|
1107
|
+
}
|
|
1108
|
+
if (imports[nextToken.text]) {
|
|
1109
|
+
this.reportError("W019", nextToken, nextToken.text);
|
|
1110
|
+
return null;
|
|
1111
|
+
}
|
|
1112
|
+
imports[nextToken.text] = id;
|
|
1113
|
+
this._lexer.get();
|
|
1114
|
+
}
|
|
1115
|
+
else {
|
|
1116
|
+
if (imports[id]) {
|
|
1117
|
+
this.reportError("W019", nextToken, id);
|
|
1118
|
+
return null;
|
|
1119
|
+
}
|
|
1120
|
+
imports[id] = id;
|
|
1121
|
+
}
|
|
1122
|
+
nextToken = this._lexer.peek();
|
|
1123
|
+
if (nextToken.type === Token_1.TokenType.Comma) {
|
|
1124
|
+
this._lexer.get();
|
|
1125
|
+
nextToken = this._lexer.peek();
|
|
1126
|
+
}
|
|
1127
|
+
}
|
|
1128
|
+
// --- Skip the closing brace
|
|
1129
|
+
this._lexer.get();
|
|
1130
|
+
// --- Check for "from"
|
|
1131
|
+
this.expectToken(Token_1.TokenType.From, "W025");
|
|
1132
|
+
// --- Get the module name
|
|
1133
|
+
const moduleToken = this._lexer.peek();
|
|
1134
|
+
if (moduleToken.type !== Token_1.TokenType.StringLiteral) {
|
|
1135
|
+
this.reportError("W026", moduleToken);
|
|
1136
|
+
return null;
|
|
1137
|
+
}
|
|
1138
|
+
this._lexer.get();
|
|
1139
|
+
const literal = this.parseStringLiteral(moduleToken);
|
|
1140
|
+
// --- Done.
|
|
1141
|
+
return this.createStatementNode("ImportD", {
|
|
1142
|
+
imports,
|
|
1143
|
+
moduleFile: literal.value,
|
|
1144
|
+
}, startToken, moduleToken);
|
|
1145
|
+
}
|
|
1146
|
+
// ==========================================================================
|
|
1147
|
+
// Expression parsing
|
|
1148
|
+
/**
|
|
1149
|
+
* Parses an expression:
|
|
1150
|
+
*
|
|
1151
|
+
* expr
|
|
1152
|
+
* : sequenceExpr
|
|
1153
|
+
* ;
|
|
1154
|
+
*/
|
|
1155
|
+
parseExpr(allowSequence = true) {
|
|
1156
|
+
return allowSequence ? this.parseSequenceExpression() : this.parseCondOrSpreadOrAsgnOrArrowExpr();
|
|
1157
|
+
}
|
|
1158
|
+
/**
|
|
1159
|
+
* sequenceExpr
|
|
1160
|
+
* : conditionalExpr ( "," conditionalExpr )?
|
|
1161
|
+
*/
|
|
1162
|
+
parseSequenceExpression() {
|
|
1163
|
+
const start = this._lexer.peek();
|
|
1164
|
+
let endToken = start;
|
|
1165
|
+
let leftExpr = this.parseCondOrSpreadOrAsgnOrArrowExpr();
|
|
1166
|
+
if (!leftExpr) {
|
|
1167
|
+
return null;
|
|
1168
|
+
}
|
|
1169
|
+
endToken = leftExpr.endToken;
|
|
1170
|
+
const expressions = [];
|
|
1171
|
+
let loose = false;
|
|
1172
|
+
if (this._lexer.peek().type === Token_1.TokenType.Comma) {
|
|
1173
|
+
expressions.push(leftExpr);
|
|
1174
|
+
while (this.skipToken(Token_1.TokenType.Comma)) {
|
|
1175
|
+
if (this._lexer.peek().type === Token_1.TokenType.Comma) {
|
|
1176
|
+
loose = true;
|
|
1177
|
+
endToken = this._lexer.peek();
|
|
1178
|
+
expressions.push(this.createExpressionNode("NoArgE", {}, endToken, endToken));
|
|
1179
|
+
}
|
|
1180
|
+
else {
|
|
1181
|
+
const nextExpr = this.parseCondOrSpreadOrAsgnOrArrowExpr();
|
|
1182
|
+
if (!nextExpr) {
|
|
1183
|
+
break;
|
|
1184
|
+
}
|
|
1185
|
+
endToken = nextExpr.endToken;
|
|
1186
|
+
expressions.push(nextExpr);
|
|
1187
|
+
}
|
|
1188
|
+
}
|
|
1189
|
+
}
|
|
1190
|
+
if (!expressions.length) {
|
|
1191
|
+
// --- No sequence
|
|
1192
|
+
return leftExpr;
|
|
1193
|
+
}
|
|
1194
|
+
// --- Create the sequence expression
|
|
1195
|
+
leftExpr = this.createExpressionNode("SeqE", {
|
|
1196
|
+
expressions,
|
|
1197
|
+
loose,
|
|
1198
|
+
}, start, endToken);
|
|
1199
|
+
// --- Check for "loose" sequence expression
|
|
1200
|
+
if (loose) {
|
|
1201
|
+
leftExpr = this.convertToArrayDestructure(leftExpr);
|
|
1202
|
+
}
|
|
1203
|
+
// --- Done.
|
|
1204
|
+
return leftExpr;
|
|
1205
|
+
}
|
|
1206
|
+
/**
|
|
1207
|
+
* conditionalOrSpreadOrAsgnOrArrowExpr
|
|
1208
|
+
* : nullCoalescingExpr ( "?" expr ":" expr )?
|
|
1209
|
+
* | "..." nullCoalescingExpr
|
|
1210
|
+
* | identifier "=" expr
|
|
1211
|
+
* ;
|
|
1212
|
+
*/
|
|
1213
|
+
parseCondOrSpreadOrAsgnOrArrowExpr() {
|
|
1214
|
+
const startToken = this._lexer.peek();
|
|
1215
|
+
if (startToken.type === Token_1.TokenType.Spread) {
|
|
1216
|
+
// --- Spread expression
|
|
1217
|
+
this._lexer.get();
|
|
1218
|
+
const spreadOperand = this.parseNullCoalescingExpr();
|
|
1219
|
+
return spreadOperand
|
|
1220
|
+
? this.createExpressionNode("SpreadE", {
|
|
1221
|
+
operand: spreadOperand,
|
|
1222
|
+
}, startToken, spreadOperand.endToken)
|
|
1223
|
+
: null;
|
|
1224
|
+
}
|
|
1225
|
+
const otherExpr = this.parseNullCoalescingExpr();
|
|
1226
|
+
if (!otherExpr) {
|
|
1227
|
+
return null;
|
|
1228
|
+
}
|
|
1229
|
+
const nextToken = this._lexer.peek();
|
|
1230
|
+
if (nextToken.type === Token_1.TokenType.Arrow) {
|
|
1231
|
+
// --- It is an arrow expression
|
|
1232
|
+
return this.parseArrowExpression(startToken, otherExpr);
|
|
1233
|
+
}
|
|
1234
|
+
if (nextToken.type === Token_1.TokenType.QuestionMark) {
|
|
1235
|
+
this._lexer.get();
|
|
1236
|
+
// --- Conditional expression
|
|
1237
|
+
const trueExpr = this.getExpression(false);
|
|
1238
|
+
this.expectToken(Token_1.TokenType.Colon);
|
|
1239
|
+
const falseExpr = this.getExpression(false);
|
|
1240
|
+
return this.createExpressionNode("CondE", {
|
|
1241
|
+
condition: otherExpr,
|
|
1242
|
+
consequent: trueExpr,
|
|
1243
|
+
alternate: falseExpr,
|
|
1244
|
+
}, startToken, falseExpr.endToken);
|
|
1245
|
+
}
|
|
1246
|
+
if (TokenTrait_1.tokenTraits[nextToken.type].isAssignment) {
|
|
1247
|
+
// --- Assignment
|
|
1248
|
+
this._lexer.get();
|
|
1249
|
+
const operand = this.getExpression();
|
|
1250
|
+
return operand
|
|
1251
|
+
? this.createExpressionNode("AsgnE", {
|
|
1252
|
+
leftValue: otherExpr,
|
|
1253
|
+
operator: nextToken.text,
|
|
1254
|
+
operand,
|
|
1255
|
+
}, startToken, operand.endToken)
|
|
1256
|
+
: null;
|
|
1257
|
+
}
|
|
1258
|
+
return otherExpr;
|
|
1259
|
+
}
|
|
1260
|
+
/**
|
|
1261
|
+
* Parses an arrow expression
|
|
1262
|
+
* @param start Start token
|
|
1263
|
+
* @param left Expression to the left from the arrow
|
|
1264
|
+
*/
|
|
1265
|
+
parseArrowExpression(start, left) {
|
|
1266
|
+
var _a;
|
|
1267
|
+
// --- Check the left expression
|
|
1268
|
+
let isValid;
|
|
1269
|
+
const args = [];
|
|
1270
|
+
switch (left.type) {
|
|
1271
|
+
case "NoArgE":
|
|
1272
|
+
isValid = true;
|
|
1273
|
+
break;
|
|
1274
|
+
case "IdE":
|
|
1275
|
+
isValid = ((_a = left.parenthesized) !== null && _a !== void 0 ? _a : 0) <= 1;
|
|
1276
|
+
args.push(left);
|
|
1277
|
+
break;
|
|
1278
|
+
case "SeqE":
|
|
1279
|
+
isValid = left.parenthesized === 1;
|
|
1280
|
+
if (isValid) {
|
|
1281
|
+
for (const expr of left.expressions) {
|
|
1282
|
+
switch (expr.type) {
|
|
1283
|
+
case "IdE":
|
|
1284
|
+
isValid = !expr.parenthesized;
|
|
1285
|
+
args.push(expr);
|
|
1286
|
+
break;
|
|
1287
|
+
case "OLitE": {
|
|
1288
|
+
isValid = !expr.parenthesized;
|
|
1289
|
+
if (isValid) {
|
|
1290
|
+
const des = this.convertToObjectDestructure(expr);
|
|
1291
|
+
if (des)
|
|
1292
|
+
args.push(des);
|
|
1293
|
+
}
|
|
1294
|
+
break;
|
|
1295
|
+
}
|
|
1296
|
+
case "ALitE": {
|
|
1297
|
+
isValid = !expr.parenthesized;
|
|
1298
|
+
if (isValid) {
|
|
1299
|
+
const des = this.convertToArrayDestructure(expr);
|
|
1300
|
+
if (des)
|
|
1301
|
+
args.push(des);
|
|
1302
|
+
}
|
|
1303
|
+
break;
|
|
1304
|
+
}
|
|
1305
|
+
default:
|
|
1306
|
+
isValid = false;
|
|
1307
|
+
break;
|
|
1308
|
+
}
|
|
1309
|
+
}
|
|
1310
|
+
}
|
|
1311
|
+
break;
|
|
1312
|
+
case "OLitE":
|
|
1313
|
+
isValid = left.parenthesized === 1;
|
|
1314
|
+
if (isValid) {
|
|
1315
|
+
const des = this.convertToObjectDestructure(left);
|
|
1316
|
+
if (des)
|
|
1317
|
+
args.push(des);
|
|
1318
|
+
}
|
|
1319
|
+
break;
|
|
1320
|
+
case "ALitE":
|
|
1321
|
+
isValid = left.parenthesized === 1;
|
|
1322
|
+
if (isValid) {
|
|
1323
|
+
const des = this.convertToArrayDestructure(left);
|
|
1324
|
+
if (des)
|
|
1325
|
+
args.push(des);
|
|
1326
|
+
}
|
|
1327
|
+
break;
|
|
1328
|
+
default:
|
|
1329
|
+
isValid = false;
|
|
1330
|
+
}
|
|
1331
|
+
if (!isValid) {
|
|
1332
|
+
this.reportError("W010", start);
|
|
1333
|
+
return null;
|
|
1334
|
+
}
|
|
1335
|
+
// --- Skip the arrow token
|
|
1336
|
+
this._lexer.get();
|
|
1337
|
+
// --- Get arrow expression statements
|
|
1338
|
+
const statement = this.parseStatement(false);
|
|
1339
|
+
return statement
|
|
1340
|
+
? this.createExpressionNode("ArrowE", {
|
|
1341
|
+
args,
|
|
1342
|
+
statement,
|
|
1343
|
+
}, start, statement.endToken)
|
|
1344
|
+
: null;
|
|
1345
|
+
}
|
|
1346
|
+
/**
|
|
1347
|
+
* nullCoalescingExpr
|
|
1348
|
+
* : logicalOrExpr ( "??" logicalOrExpr )?
|
|
1349
|
+
* ;
|
|
1350
|
+
*/
|
|
1351
|
+
parseNullCoalescingExpr() {
|
|
1352
|
+
const startToken = this._lexer.peek();
|
|
1353
|
+
let leftExpr = this.parseLogicalOrExpr();
|
|
1354
|
+
if (!leftExpr) {
|
|
1355
|
+
return null;
|
|
1356
|
+
}
|
|
1357
|
+
while (this.skipToken(Token_1.TokenType.NullCoalesce)) {
|
|
1358
|
+
const rightExpr = this.parseLogicalOrExpr();
|
|
1359
|
+
if (!rightExpr) {
|
|
1360
|
+
this.reportError("W001");
|
|
1361
|
+
return null;
|
|
1362
|
+
}
|
|
1363
|
+
let endToken = rightExpr.endToken;
|
|
1364
|
+
leftExpr = this.createExpressionNode("BinaryE", {
|
|
1365
|
+
operator: "??",
|
|
1366
|
+
left: leftExpr,
|
|
1367
|
+
right: rightExpr,
|
|
1368
|
+
}, startToken, endToken);
|
|
1369
|
+
}
|
|
1370
|
+
return leftExpr;
|
|
1371
|
+
}
|
|
1372
|
+
/**
|
|
1373
|
+
* logicalOrExpr
|
|
1374
|
+
* : logicalAndExpr ( "||" logicalAndExpr )?
|
|
1375
|
+
* ;
|
|
1376
|
+
*/
|
|
1377
|
+
parseLogicalOrExpr() {
|
|
1378
|
+
const startToken = this._lexer.peek();
|
|
1379
|
+
let leftExpr = this.parseLogicalAndExpr();
|
|
1380
|
+
if (!leftExpr) {
|
|
1381
|
+
return null;
|
|
1382
|
+
}
|
|
1383
|
+
while (this.skipToken(Token_1.TokenType.LogicalOr)) {
|
|
1384
|
+
const rightExpr = this.parseLogicalAndExpr();
|
|
1385
|
+
if (!rightExpr) {
|
|
1386
|
+
this.reportError("W001");
|
|
1387
|
+
return null;
|
|
1388
|
+
}
|
|
1389
|
+
let endToken = rightExpr.endToken;
|
|
1390
|
+
leftExpr = this.createExpressionNode("BinaryE", {
|
|
1391
|
+
operator: "||",
|
|
1392
|
+
left: leftExpr,
|
|
1393
|
+
right: rightExpr,
|
|
1394
|
+
}, startToken, endToken);
|
|
1395
|
+
}
|
|
1396
|
+
return leftExpr;
|
|
1397
|
+
}
|
|
1398
|
+
/**
|
|
1399
|
+
* logicalAndExpr
|
|
1400
|
+
* : bitwiseOrExpr ( "&&" bitwiseOrExpr )?
|
|
1401
|
+
* ;
|
|
1402
|
+
*/
|
|
1403
|
+
parseLogicalAndExpr() {
|
|
1404
|
+
const startToken = this._lexer.peek();
|
|
1405
|
+
let leftExpr = this.parseBitwiseOrExpr();
|
|
1406
|
+
if (!leftExpr) {
|
|
1407
|
+
return null;
|
|
1408
|
+
}
|
|
1409
|
+
while (this.skipToken(Token_1.TokenType.LogicalAnd)) {
|
|
1410
|
+
const rightExpr = this.parseBitwiseOrExpr();
|
|
1411
|
+
if (!rightExpr) {
|
|
1412
|
+
this.reportError("W001");
|
|
1413
|
+
return null;
|
|
1414
|
+
}
|
|
1415
|
+
let endToken = rightExpr.endToken;
|
|
1416
|
+
leftExpr = this.createExpressionNode("BinaryE", {
|
|
1417
|
+
operator: "&&",
|
|
1418
|
+
left: leftExpr,
|
|
1419
|
+
right: rightExpr,
|
|
1420
|
+
}, startToken, endToken);
|
|
1421
|
+
}
|
|
1422
|
+
return leftExpr;
|
|
1423
|
+
}
|
|
1424
|
+
/**
|
|
1425
|
+
* bitwiseOrExpr
|
|
1426
|
+
* : bitwiseXorExpr ( "|" bitwiseXorExpr )?
|
|
1427
|
+
* ;
|
|
1428
|
+
*/
|
|
1429
|
+
parseBitwiseOrExpr() {
|
|
1430
|
+
const startToken = this._lexer.peek();
|
|
1431
|
+
let leftExpr = this.parseBitwiseXorExpr();
|
|
1432
|
+
if (!leftExpr) {
|
|
1433
|
+
return null;
|
|
1434
|
+
}
|
|
1435
|
+
while (this.skipToken(Token_1.TokenType.BitwiseOr)) {
|
|
1436
|
+
const rightExpr = this.parseBitwiseXorExpr();
|
|
1437
|
+
if (!rightExpr) {
|
|
1438
|
+
this.reportError("W001");
|
|
1439
|
+
return null;
|
|
1440
|
+
}
|
|
1441
|
+
let endToken = rightExpr.endToken;
|
|
1442
|
+
leftExpr = this.createExpressionNode("BinaryE", {
|
|
1443
|
+
operator: "|",
|
|
1444
|
+
left: leftExpr,
|
|
1445
|
+
right: rightExpr,
|
|
1446
|
+
}, startToken, endToken);
|
|
1447
|
+
}
|
|
1448
|
+
return leftExpr;
|
|
1449
|
+
}
|
|
1450
|
+
/**
|
|
1451
|
+
* bitwiseXorExpr
|
|
1452
|
+
* : bitwiseAndExpr ( "^" bitwiseAndExpr )?
|
|
1453
|
+
* ;
|
|
1454
|
+
*/
|
|
1455
|
+
parseBitwiseXorExpr() {
|
|
1456
|
+
const startToken = this._lexer.peek();
|
|
1457
|
+
let leftExpr = this.parseBitwiseAndExpr();
|
|
1458
|
+
if (!leftExpr) {
|
|
1459
|
+
return null;
|
|
1460
|
+
}
|
|
1461
|
+
while (this.skipToken(Token_1.TokenType.BitwiseXor)) {
|
|
1462
|
+
const rightExpr = this.parseBitwiseAndExpr();
|
|
1463
|
+
if (!rightExpr) {
|
|
1464
|
+
this.reportError("W001");
|
|
1465
|
+
return null;
|
|
1466
|
+
}
|
|
1467
|
+
let endToken = rightExpr.endToken;
|
|
1468
|
+
leftExpr = this.createExpressionNode("BinaryE", {
|
|
1469
|
+
operator: "^",
|
|
1470
|
+
left: leftExpr,
|
|
1471
|
+
right: rightExpr,
|
|
1472
|
+
}, startToken, endToken);
|
|
1473
|
+
}
|
|
1474
|
+
return leftExpr;
|
|
1475
|
+
}
|
|
1476
|
+
/**
|
|
1477
|
+
* bitwiseAndExpr
|
|
1478
|
+
* : equExpr ( "&" equExpr )?
|
|
1479
|
+
* ;
|
|
1480
|
+
*/
|
|
1481
|
+
parseBitwiseAndExpr() {
|
|
1482
|
+
const startToken = this._lexer.peek();
|
|
1483
|
+
let leftExpr = this.parseEquExpr();
|
|
1484
|
+
if (!leftExpr) {
|
|
1485
|
+
return null;
|
|
1486
|
+
}
|
|
1487
|
+
while (this.skipToken(Token_1.TokenType.BitwiseAnd)) {
|
|
1488
|
+
const rightExpr = this.parseEquExpr();
|
|
1489
|
+
if (!rightExpr) {
|
|
1490
|
+
this.reportError("W001");
|
|
1491
|
+
return null;
|
|
1492
|
+
}
|
|
1493
|
+
let endToken = rightExpr.endToken;
|
|
1494
|
+
leftExpr = this.createExpressionNode("BinaryE", {
|
|
1495
|
+
operator: "&",
|
|
1496
|
+
left: leftExpr,
|
|
1497
|
+
right: rightExpr,
|
|
1498
|
+
}, startToken, endToken);
|
|
1499
|
+
}
|
|
1500
|
+
return leftExpr;
|
|
1501
|
+
}
|
|
1502
|
+
/**
|
|
1503
|
+
* equExpr
|
|
1504
|
+
* : relOrInExpr ( ( "==" | "!=" | "===" | "!==" ) relOrInExpr )?
|
|
1505
|
+
* ;
|
|
1506
|
+
*/
|
|
1507
|
+
parseEquExpr() {
|
|
1508
|
+
const startToken = this._lexer.peek();
|
|
1509
|
+
let leftExpr = this.parseRelOrInExpr();
|
|
1510
|
+
if (!leftExpr) {
|
|
1511
|
+
return null;
|
|
1512
|
+
}
|
|
1513
|
+
let opType;
|
|
1514
|
+
while ((opType = this.skipTokens(Token_1.TokenType.Equal, Token_1.TokenType.StrictEqual, Token_1.TokenType.NotEqual, Token_1.TokenType.StrictNotEqual))) {
|
|
1515
|
+
const rightExpr = this.parseRelOrInExpr();
|
|
1516
|
+
if (!rightExpr) {
|
|
1517
|
+
this.reportError("W001");
|
|
1518
|
+
return null;
|
|
1519
|
+
}
|
|
1520
|
+
let endToken = rightExpr.endToken;
|
|
1521
|
+
leftExpr = this.createExpressionNode("BinaryE", {
|
|
1522
|
+
type: "BinaryE",
|
|
1523
|
+
operator: opType.text,
|
|
1524
|
+
left: leftExpr,
|
|
1525
|
+
right: rightExpr,
|
|
1526
|
+
}, startToken, endToken);
|
|
1527
|
+
}
|
|
1528
|
+
return leftExpr;
|
|
1529
|
+
}
|
|
1530
|
+
/**
|
|
1531
|
+
* relOrInExpr
|
|
1532
|
+
* : shiftExpr ( ( "<" | "<=" | ">" | ">=", "in" ) shiftExpr )?
|
|
1533
|
+
* ;
|
|
1534
|
+
*/
|
|
1535
|
+
parseRelOrInExpr() {
|
|
1536
|
+
const startToken = this._lexer.peek();
|
|
1537
|
+
let leftExpr = this.parseShiftExpr();
|
|
1538
|
+
if (!leftExpr) {
|
|
1539
|
+
return null;
|
|
1540
|
+
}
|
|
1541
|
+
let opType;
|
|
1542
|
+
while ((opType = this.skipTokens(Token_1.TokenType.LessThan, Token_1.TokenType.LessThanOrEqual, Token_1.TokenType.GreaterThan, Token_1.TokenType.GreaterThanOrEqual, Token_1.TokenType.In))) {
|
|
1543
|
+
const rightExpr = this.parseShiftExpr();
|
|
1544
|
+
if (!rightExpr) {
|
|
1545
|
+
this.reportError("W001");
|
|
1546
|
+
return null;
|
|
1547
|
+
}
|
|
1548
|
+
let endToken = rightExpr.endToken;
|
|
1549
|
+
leftExpr = this.createExpressionNode("BinaryE", {
|
|
1550
|
+
operator: opType.text,
|
|
1551
|
+
left: leftExpr,
|
|
1552
|
+
right: rightExpr,
|
|
1553
|
+
}, startToken, endToken);
|
|
1554
|
+
}
|
|
1555
|
+
return leftExpr;
|
|
1556
|
+
}
|
|
1557
|
+
/**
|
|
1558
|
+
* shiftExpr
|
|
1559
|
+
* : addExpr ( ( "<<" | ">>" | ">>>" ) addExpr )?
|
|
1560
|
+
* ;
|
|
1561
|
+
*/
|
|
1562
|
+
parseShiftExpr() {
|
|
1563
|
+
const startToken = this._lexer.peek();
|
|
1564
|
+
let leftExpr = this.parseAddExpr();
|
|
1565
|
+
if (!leftExpr) {
|
|
1566
|
+
return null;
|
|
1567
|
+
}
|
|
1568
|
+
let opType;
|
|
1569
|
+
while ((opType = this.skipTokens(Token_1.TokenType.ShiftLeft, Token_1.TokenType.ShiftRight, Token_1.TokenType.SignedShiftRight))) {
|
|
1570
|
+
const rightExpr = this.parseAddExpr();
|
|
1571
|
+
if (!rightExpr) {
|
|
1572
|
+
this.reportError("W001");
|
|
1573
|
+
return null;
|
|
1574
|
+
}
|
|
1575
|
+
let endToken = rightExpr.endToken;
|
|
1576
|
+
leftExpr = this.createExpressionNode("BinaryE", {
|
|
1577
|
+
operator: opType.text,
|
|
1578
|
+
left: leftExpr,
|
|
1579
|
+
right: rightExpr,
|
|
1580
|
+
}, startToken, endToken);
|
|
1581
|
+
}
|
|
1582
|
+
return leftExpr;
|
|
1583
|
+
}
|
|
1584
|
+
/**
|
|
1585
|
+
* addExpr
|
|
1586
|
+
* : multExpr ( ( "+" | "-" ) multExpr )?
|
|
1587
|
+
* ;
|
|
1588
|
+
*/
|
|
1589
|
+
parseAddExpr() {
|
|
1590
|
+
const startToken = this._lexer.peek();
|
|
1591
|
+
let leftExpr = this.parseMultExpr();
|
|
1592
|
+
if (!leftExpr) {
|
|
1593
|
+
return null;
|
|
1594
|
+
}
|
|
1595
|
+
let opType;
|
|
1596
|
+
while ((opType = this.skipTokens(Token_1.TokenType.Plus, Token_1.TokenType.Minus))) {
|
|
1597
|
+
const rightExpr = this.parseMultExpr();
|
|
1598
|
+
if (!rightExpr) {
|
|
1599
|
+
this.reportError("W001");
|
|
1600
|
+
return null;
|
|
1601
|
+
}
|
|
1602
|
+
let endToken = rightExpr.endToken;
|
|
1603
|
+
leftExpr = this.createExpressionNode("BinaryE", {
|
|
1604
|
+
operator: opType.text,
|
|
1605
|
+
left: leftExpr,
|
|
1606
|
+
right: rightExpr,
|
|
1607
|
+
}, startToken, endToken);
|
|
1608
|
+
}
|
|
1609
|
+
return leftExpr;
|
|
1610
|
+
}
|
|
1611
|
+
/**
|
|
1612
|
+
* multExpr
|
|
1613
|
+
* : exponentialExpr ( ( "*" | "/" | "%") exponentialExpr )?
|
|
1614
|
+
* ;
|
|
1615
|
+
*/
|
|
1616
|
+
parseMultExpr() {
|
|
1617
|
+
const startToken = this._lexer.peek();
|
|
1618
|
+
let leftExpr = this.parseExponentialExpr();
|
|
1619
|
+
if (!leftExpr) {
|
|
1620
|
+
return null;
|
|
1621
|
+
}
|
|
1622
|
+
let opType;
|
|
1623
|
+
while ((opType = this.skipTokens(Token_1.TokenType.Multiply, Token_1.TokenType.Divide, Token_1.TokenType.Remainder))) {
|
|
1624
|
+
const rightExpr = this.parseExponentialExpr();
|
|
1625
|
+
if (!rightExpr) {
|
|
1626
|
+
this.reportError("W001");
|
|
1627
|
+
return null;
|
|
1628
|
+
}
|
|
1629
|
+
let endToken = rightExpr.endToken;
|
|
1630
|
+
leftExpr = this.createExpressionNode("BinaryE", {
|
|
1631
|
+
operator: opType.text,
|
|
1632
|
+
left: leftExpr,
|
|
1633
|
+
right: rightExpr,
|
|
1634
|
+
}, startToken, endToken);
|
|
1635
|
+
}
|
|
1636
|
+
return leftExpr;
|
|
1637
|
+
}
|
|
1638
|
+
/**
|
|
1639
|
+
* exponentialExpr
|
|
1640
|
+
* : unaryExpr ( "**" unaryExpr )?
|
|
1641
|
+
* ;
|
|
1642
|
+
*/
|
|
1643
|
+
parseExponentialExpr() {
|
|
1644
|
+
const startToken = this._lexer.peek();
|
|
1645
|
+
let leftExpr = this.parseUnaryOrPrefixExpr();
|
|
1646
|
+
if (!leftExpr) {
|
|
1647
|
+
return null;
|
|
1648
|
+
}
|
|
1649
|
+
let opType;
|
|
1650
|
+
let count = 0;
|
|
1651
|
+
while ((opType = this.skipToken(Token_1.TokenType.Exponent))) {
|
|
1652
|
+
let rightExpr = this.parseUnaryOrPrefixExpr();
|
|
1653
|
+
if (!rightExpr) {
|
|
1654
|
+
this.reportError("W001");
|
|
1655
|
+
return null;
|
|
1656
|
+
}
|
|
1657
|
+
let endToken = rightExpr.endToken;
|
|
1658
|
+
if (count === 0) {
|
|
1659
|
+
leftExpr = this.createExpressionNode("BinaryE", {
|
|
1660
|
+
operator: opType.text,
|
|
1661
|
+
left: leftExpr,
|
|
1662
|
+
right: rightExpr,
|
|
1663
|
+
}, startToken, endToken);
|
|
1664
|
+
}
|
|
1665
|
+
else {
|
|
1666
|
+
const prevLeft = leftExpr;
|
|
1667
|
+
leftExpr = this.createExpressionNode("BinaryE", {
|
|
1668
|
+
operator: opType.text,
|
|
1669
|
+
left: prevLeft.left,
|
|
1670
|
+
right: {
|
|
1671
|
+
type: "BinaryE",
|
|
1672
|
+
operator: opType.text,
|
|
1673
|
+
left: prevLeft.right,
|
|
1674
|
+
right: rightExpr,
|
|
1675
|
+
},
|
|
1676
|
+
}, startToken, endToken);
|
|
1677
|
+
}
|
|
1678
|
+
count++;
|
|
1679
|
+
}
|
|
1680
|
+
return leftExpr;
|
|
1681
|
+
}
|
|
1682
|
+
/**
|
|
1683
|
+
* unaryExpr
|
|
1684
|
+
* : ( "typeof" | "delete" | "+" | "-" | "~" | "!" ) memberOrInvocationExpr
|
|
1685
|
+
* | memberOrInvocationExpr
|
|
1686
|
+
* ;
|
|
1687
|
+
*/
|
|
1688
|
+
parseUnaryOrPrefixExpr() {
|
|
1689
|
+
const startToken = this._lexer.peek();
|
|
1690
|
+
if (TokenTrait_1.tokenTraits[startToken.type].canBeUnary) {
|
|
1691
|
+
this._lexer.get();
|
|
1692
|
+
const unaryOperand = this.parseUnaryOrPrefixExpr();
|
|
1693
|
+
if (!unaryOperand) {
|
|
1694
|
+
return null;
|
|
1695
|
+
}
|
|
1696
|
+
return this.createExpressionNode("UnaryE", {
|
|
1697
|
+
operator: startToken.text,
|
|
1698
|
+
operand: unaryOperand,
|
|
1699
|
+
}, startToken, unaryOperand.endToken);
|
|
1700
|
+
}
|
|
1701
|
+
if (startToken.type === Token_1.TokenType.IncOp || startToken.type === Token_1.TokenType.DecOp) {
|
|
1702
|
+
this._lexer.get();
|
|
1703
|
+
const prefixOperand = this.parseMemberOrInvocationExpr();
|
|
1704
|
+
if (!prefixOperand) {
|
|
1705
|
+
return null;
|
|
1706
|
+
}
|
|
1707
|
+
return this.createExpressionNode("PrefE", {
|
|
1708
|
+
operator: startToken.text,
|
|
1709
|
+
operand: prefixOperand,
|
|
1710
|
+
}, startToken, prefixOperand.endToken);
|
|
1711
|
+
}
|
|
1712
|
+
// --- Not unary or prefix
|
|
1713
|
+
return this.parseMemberOrInvocationExpr();
|
|
1714
|
+
}
|
|
1715
|
+
/**
|
|
1716
|
+
* memberOrInvocationExpr
|
|
1717
|
+
* : primaryExpr "(" functionArgs ")"
|
|
1718
|
+
* | primaryExpr "." identifier
|
|
1719
|
+
* | primaryExpr "?." identifier
|
|
1720
|
+
* | primaryExpr "[" expr "]"
|
|
1721
|
+
* ;
|
|
1722
|
+
*/
|
|
1723
|
+
parseMemberOrInvocationExpr() {
|
|
1724
|
+
const startToken = this._lexer.peek();
|
|
1725
|
+
let primary = this.parsePrimaryExpr();
|
|
1726
|
+
if (!primary) {
|
|
1727
|
+
return null;
|
|
1728
|
+
}
|
|
1729
|
+
let exitLoop = false;
|
|
1730
|
+
do {
|
|
1731
|
+
const currentStart = this._lexer.peek();
|
|
1732
|
+
switch (currentStart.type) {
|
|
1733
|
+
case Token_1.TokenType.LParent: {
|
|
1734
|
+
this._lexer.get();
|
|
1735
|
+
let args = [];
|
|
1736
|
+
if (this._lexer.peek().type !== Token_1.TokenType.RParent) {
|
|
1737
|
+
const expr = this.parseExpr();
|
|
1738
|
+
if (!expr) {
|
|
1739
|
+
this.reportError("W001");
|
|
1740
|
+
return null;
|
|
1741
|
+
}
|
|
1742
|
+
args = expr.type === "SeqE" ? expr.expressions : [expr];
|
|
1743
|
+
}
|
|
1744
|
+
const endToken = this._lexer.peek();
|
|
1745
|
+
this.expectToken(Token_1.TokenType.RParent, "W006");
|
|
1746
|
+
primary = this.createExpressionNode("InvokeE", {
|
|
1747
|
+
object: primary,
|
|
1748
|
+
arguments: args,
|
|
1749
|
+
}, startToken, endToken);
|
|
1750
|
+
break;
|
|
1751
|
+
}
|
|
1752
|
+
case Token_1.TokenType.Dot:
|
|
1753
|
+
case Token_1.TokenType.OptionalChaining:
|
|
1754
|
+
this._lexer.get();
|
|
1755
|
+
const member = this._lexer.get();
|
|
1756
|
+
const memberTrait = TokenTrait_1.tokenTraits[member.type];
|
|
1757
|
+
if (!memberTrait.keywordLike) {
|
|
1758
|
+
this.reportError("W003");
|
|
1759
|
+
return null;
|
|
1760
|
+
}
|
|
1761
|
+
primary = this.createExpressionNode("MembE", {
|
|
1762
|
+
object: primary,
|
|
1763
|
+
member: member.text,
|
|
1764
|
+
isOptional: currentStart.type === Token_1.TokenType.OptionalChaining,
|
|
1765
|
+
}, startToken, member);
|
|
1766
|
+
break;
|
|
1767
|
+
case Token_1.TokenType.LSquare:
|
|
1768
|
+
this._lexer.get();
|
|
1769
|
+
const memberExpr = this.getExpression();
|
|
1770
|
+
if (!memberExpr) {
|
|
1771
|
+
return null;
|
|
1772
|
+
}
|
|
1773
|
+
const endToken = this._lexer.peek();
|
|
1774
|
+
this.expectToken(Token_1.TokenType.RSquare, "W005");
|
|
1775
|
+
primary = this.createExpressionNode("CMembE", {
|
|
1776
|
+
object: primary,
|
|
1777
|
+
member: memberExpr,
|
|
1778
|
+
}, startToken, endToken);
|
|
1779
|
+
break;
|
|
1780
|
+
default:
|
|
1781
|
+
exitLoop = true;
|
|
1782
|
+
break;
|
|
1783
|
+
}
|
|
1784
|
+
} while (!exitLoop);
|
|
1785
|
+
// --- Check for postfix operators
|
|
1786
|
+
const nextToken = this._lexer.peek();
|
|
1787
|
+
if (nextToken.type === Token_1.TokenType.IncOp || nextToken.type === Token_1.TokenType.DecOp) {
|
|
1788
|
+
this._lexer.get();
|
|
1789
|
+
return this.createExpressionNode("PostfE", {
|
|
1790
|
+
operator: nextToken.text,
|
|
1791
|
+
operand: primary,
|
|
1792
|
+
}, startToken, nextToken);
|
|
1793
|
+
}
|
|
1794
|
+
return primary;
|
|
1795
|
+
}
|
|
1796
|
+
/**
|
|
1797
|
+
* primaryExpr
|
|
1798
|
+
* : literal
|
|
1799
|
+
* | identifier
|
|
1800
|
+
* | "::" identifier
|
|
1801
|
+
* | "$item"
|
|
1802
|
+
* | "(" expr ")"
|
|
1803
|
+
* ;
|
|
1804
|
+
*/
|
|
1805
|
+
parsePrimaryExpr() {
|
|
1806
|
+
var _a;
|
|
1807
|
+
const start = this._lexer.peek();
|
|
1808
|
+
switch (start.type) {
|
|
1809
|
+
case Token_1.TokenType.LParent:
|
|
1810
|
+
// --- Parenthesised or no-arg expression
|
|
1811
|
+
this._lexer.get();
|
|
1812
|
+
if (this._lexer.peek().type === Token_1.TokenType.RParent) {
|
|
1813
|
+
// --- No-arg
|
|
1814
|
+
const endToken = this._lexer.get();
|
|
1815
|
+
return this.createExpressionNode("NoArgE", {}, start, endToken);
|
|
1816
|
+
}
|
|
1817
|
+
// --- Parenthesized
|
|
1818
|
+
const parenthesizedExpr = this.parseExpr();
|
|
1819
|
+
if (!parenthesizedExpr) {
|
|
1820
|
+
return null;
|
|
1821
|
+
}
|
|
1822
|
+
const endToken = this._lexer.peek();
|
|
1823
|
+
this.expectToken(Token_1.TokenType.RParent, "W006");
|
|
1824
|
+
(_a = parenthesizedExpr.parenthesized) !== null && _a !== void 0 ? _a : (parenthesizedExpr.parenthesized = 0);
|
|
1825
|
+
parenthesizedExpr.parenthesized++;
|
|
1826
|
+
parenthesizedExpr.startToken = start;
|
|
1827
|
+
parenthesizedExpr.startPosition = start.location.startPosition;
|
|
1828
|
+
parenthesizedExpr.startLine = start.location.startLine;
|
|
1829
|
+
parenthesizedExpr.startColumn = start.location.startColumn;
|
|
1830
|
+
parenthesizedExpr.endToken = endToken;
|
|
1831
|
+
parenthesizedExpr.endPosition = endToken.location.endPosition;
|
|
1832
|
+
parenthesizedExpr.endLine = endToken.location.endLine;
|
|
1833
|
+
parenthesizedExpr.endColumn = endToken.location.endColumn;
|
|
1834
|
+
parenthesizedExpr.source = this.getSource(start, endToken);
|
|
1835
|
+
return parenthesizedExpr;
|
|
1836
|
+
case Token_1.TokenType.Identifier: {
|
|
1837
|
+
const idToken = this._lexer.get();
|
|
1838
|
+
return this.createExpressionNode("IdE", {
|
|
1839
|
+
name: idToken.text,
|
|
1840
|
+
}, idToken, idToken);
|
|
1841
|
+
}
|
|
1842
|
+
case Token_1.TokenType.Global: {
|
|
1843
|
+
this._lexer.get();
|
|
1844
|
+
const idToken = this._lexer.get();
|
|
1845
|
+
if (idToken.type !== Token_1.TokenType.Identifier) {
|
|
1846
|
+
this.reportError("W003");
|
|
1847
|
+
return null;
|
|
1848
|
+
}
|
|
1849
|
+
return this.createExpressionNode("IdE", {
|
|
1850
|
+
name: idToken.text,
|
|
1851
|
+
isGlobal: true,
|
|
1852
|
+
}, idToken, idToken);
|
|
1853
|
+
}
|
|
1854
|
+
case Token_1.TokenType.False:
|
|
1855
|
+
case Token_1.TokenType.True:
|
|
1856
|
+
this._lexer.get();
|
|
1857
|
+
return this.createExpressionNode("LitE", {
|
|
1858
|
+
value: start.type === Token_1.TokenType.True,
|
|
1859
|
+
}, start, start);
|
|
1860
|
+
case Token_1.TokenType.BinaryLiteral:
|
|
1861
|
+
this._lexer.get();
|
|
1862
|
+
return this.parseBinaryLiteral(start);
|
|
1863
|
+
case Token_1.TokenType.DecimalLiteral:
|
|
1864
|
+
this._lexer.get();
|
|
1865
|
+
return this.parseDecimalLiteral(start);
|
|
1866
|
+
case Token_1.TokenType.HexadecimalLiteral:
|
|
1867
|
+
this._lexer.get();
|
|
1868
|
+
return this.parseHexadecimalLiteral(start);
|
|
1869
|
+
case Token_1.TokenType.RealLiteral:
|
|
1870
|
+
this._lexer.get();
|
|
1871
|
+
return this.parseRealLiteral(start);
|
|
1872
|
+
case Token_1.TokenType.StringLiteral:
|
|
1873
|
+
this._lexer.get();
|
|
1874
|
+
return this.parseStringLiteral(start);
|
|
1875
|
+
case Token_1.TokenType.Infinity:
|
|
1876
|
+
this._lexer.get();
|
|
1877
|
+
return this.createExpressionNode("LitE", {
|
|
1878
|
+
value: Infinity,
|
|
1879
|
+
}, start, start);
|
|
1880
|
+
case Token_1.TokenType.NaN:
|
|
1881
|
+
this._lexer.get();
|
|
1882
|
+
return this.createExpressionNode("LitE", {
|
|
1883
|
+
value: NaN,
|
|
1884
|
+
}, start, start);
|
|
1885
|
+
case Token_1.TokenType.Null:
|
|
1886
|
+
this._lexer.get();
|
|
1887
|
+
return this.createExpressionNode("LitE", {
|
|
1888
|
+
value: null,
|
|
1889
|
+
}, start, start);
|
|
1890
|
+
case Token_1.TokenType.Undefined:
|
|
1891
|
+
this._lexer.get();
|
|
1892
|
+
return this.createExpressionNode("LitE", {
|
|
1893
|
+
value: undefined,
|
|
1894
|
+
}, start, start);
|
|
1895
|
+
case Token_1.TokenType.LSquare:
|
|
1896
|
+
return this.parseArrayLiteral();
|
|
1897
|
+
case Token_1.TokenType.LBrace:
|
|
1898
|
+
return this.parseObjectLiteral();
|
|
1899
|
+
case Token_1.TokenType.Divide:
|
|
1900
|
+
return this.parseRegExpLiteral();
|
|
1901
|
+
}
|
|
1902
|
+
return null;
|
|
1903
|
+
}
|
|
1904
|
+
/**
|
|
1905
|
+
* Parses an array literal
|
|
1906
|
+
*/
|
|
1907
|
+
parseArrayLiteral() {
|
|
1908
|
+
const start = this._lexer.get();
|
|
1909
|
+
let expressions = [];
|
|
1910
|
+
if (this._lexer.peek().type !== Token_1.TokenType.RSquare) {
|
|
1911
|
+
const expr = this.getExpression();
|
|
1912
|
+
if (expr) {
|
|
1913
|
+
expressions = expr.type === "SeqE" ? expr.expressions : [expr];
|
|
1914
|
+
}
|
|
1915
|
+
}
|
|
1916
|
+
const endToken = this._lexer.peek();
|
|
1917
|
+
this.expectToken(Token_1.TokenType.RSquare);
|
|
1918
|
+
return this.createExpressionNode("ALitE", {
|
|
1919
|
+
items: expressions,
|
|
1920
|
+
}, start, endToken);
|
|
1921
|
+
}
|
|
1922
|
+
/**
|
|
1923
|
+
* Parses an object literal
|
|
1924
|
+
*/
|
|
1925
|
+
parseObjectLiteral() {
|
|
1926
|
+
const start = this._lexer.get();
|
|
1927
|
+
let props = [];
|
|
1928
|
+
if (this._lexer.peek().type !== Token_1.TokenType.RBrace) {
|
|
1929
|
+
while (this._lexer.peek().type !== Token_1.TokenType.RBrace) {
|
|
1930
|
+
// --- Check the next token
|
|
1931
|
+
const nextToken = this._lexer.peek();
|
|
1932
|
+
const traits = TokenTrait_1.tokenTraits[nextToken.type];
|
|
1933
|
+
let nameExpr;
|
|
1934
|
+
// --- Get property name or calculated property name
|
|
1935
|
+
if (traits.expressionStart) {
|
|
1936
|
+
if (nextToken.type === Token_1.TokenType.LSquare) {
|
|
1937
|
+
this._lexer.get();
|
|
1938
|
+
nameExpr = this.getExpression();
|
|
1939
|
+
if (!nameExpr) {
|
|
1940
|
+
return null;
|
|
1941
|
+
}
|
|
1942
|
+
this.expectToken(Token_1.TokenType.RSquare, "W005");
|
|
1943
|
+
nameExpr = this.createExpressionNode("SeqE", {
|
|
1944
|
+
expressions: [nameExpr],
|
|
1945
|
+
}, start);
|
|
1946
|
+
}
|
|
1947
|
+
else if (traits.isPropLiteral) {
|
|
1948
|
+
nameExpr = this.getExpression(false);
|
|
1949
|
+
if (!nameExpr) {
|
|
1950
|
+
return null;
|
|
1951
|
+
}
|
|
1952
|
+
if (nameExpr.type !== "IdE" && nameExpr.type !== "LitE" && nameExpr.type !== "SpreadE") {
|
|
1953
|
+
this.reportError("W007");
|
|
1954
|
+
return null;
|
|
1955
|
+
}
|
|
1956
|
+
}
|
|
1957
|
+
else {
|
|
1958
|
+
this.reportError("W007");
|
|
1959
|
+
return null;
|
|
1960
|
+
}
|
|
1961
|
+
}
|
|
1962
|
+
else if (traits.keywordLike) {
|
|
1963
|
+
nameExpr = {
|
|
1964
|
+
type: "IdE",
|
|
1965
|
+
name: nextToken.text,
|
|
1966
|
+
value: undefined,
|
|
1967
|
+
startPosition: nextToken.location.startPosition,
|
|
1968
|
+
startLine: nextToken.location.startLine,
|
|
1969
|
+
startColumn: nextToken.location.startColumn,
|
|
1970
|
+
endPosition: nextToken.location.endPosition,
|
|
1971
|
+
endLine: nextToken.location.endLine,
|
|
1972
|
+
endColumn: nextToken.location.endColumn,
|
|
1973
|
+
source: nextToken.text,
|
|
1974
|
+
startToken: nextToken,
|
|
1975
|
+
endToken: nextToken,
|
|
1976
|
+
};
|
|
1977
|
+
this._lexer.get();
|
|
1978
|
+
}
|
|
1979
|
+
else {
|
|
1980
|
+
this.reportError("W001");
|
|
1981
|
+
return null;
|
|
1982
|
+
}
|
|
1983
|
+
const nameType = nameExpr.type;
|
|
1984
|
+
if (nameType === "SpreadE") {
|
|
1985
|
+
props.push(nameExpr);
|
|
1986
|
+
}
|
|
1987
|
+
else {
|
|
1988
|
+
if (nameType === "LitE") {
|
|
1989
|
+
const val = nameExpr.value;
|
|
1990
|
+
if (typeof val !== "number" && typeof val !== "string") {
|
|
1991
|
+
this.expectToken(Token_1.TokenType.RBrace, "W007");
|
|
1992
|
+
return null;
|
|
1993
|
+
}
|
|
1994
|
+
}
|
|
1995
|
+
// else if (nameType !== "IdE") {
|
|
1996
|
+
// this.expectToken(TokenType.RBrace, "W007");
|
|
1997
|
+
// return null;
|
|
1998
|
+
// }
|
|
1999
|
+
// --- Value is optional, when we have a name
|
|
2000
|
+
let valueExpr = null;
|
|
2001
|
+
if (nameType === "IdE") {
|
|
2002
|
+
const nameFollowerToken = this._lexer.peek();
|
|
2003
|
+
if (nameFollowerToken.type === Token_1.TokenType.Comma || nameFollowerToken.type === Token_1.TokenType.RBrace) {
|
|
2004
|
+
valueExpr = Object.assign({}, nameExpr);
|
|
2005
|
+
}
|
|
2006
|
+
}
|
|
2007
|
+
// --- Move to property value
|
|
2008
|
+
if (!valueExpr) {
|
|
2009
|
+
this.expectToken(Token_1.TokenType.Colon, "W008");
|
|
2010
|
+
valueExpr = this.getExpression(false);
|
|
2011
|
+
if (!valueExpr) {
|
|
2012
|
+
return null;
|
|
2013
|
+
}
|
|
2014
|
+
}
|
|
2015
|
+
props.push([nameExpr, valueExpr]);
|
|
2016
|
+
}
|
|
2017
|
+
// --- Test property termination
|
|
2018
|
+
const next = this._lexer.peek().type;
|
|
2019
|
+
if (next === Token_1.TokenType.Comma) {
|
|
2020
|
+
this._lexer.get();
|
|
2021
|
+
}
|
|
2022
|
+
else {
|
|
2023
|
+
if (next !== Token_1.TokenType.RBrace) {
|
|
2024
|
+
break;
|
|
2025
|
+
}
|
|
2026
|
+
}
|
|
2027
|
+
}
|
|
2028
|
+
}
|
|
2029
|
+
const endToken = this._lexer.peek();
|
|
2030
|
+
this.expectToken(Token_1.TokenType.RBrace, "W004");
|
|
2031
|
+
return this.createExpressionNode("OLitE", {
|
|
2032
|
+
props,
|
|
2033
|
+
}, start, endToken);
|
|
2034
|
+
}
|
|
2035
|
+
parseRegExpLiteral() {
|
|
2036
|
+
var _a;
|
|
2037
|
+
const startToken = this._lexer.peek();
|
|
2038
|
+
const result = this._lexer.getRegEx();
|
|
2039
|
+
if (result.success) {
|
|
2040
|
+
return this.createExpressionNode("LitE", {
|
|
2041
|
+
value: new RegExp(result.pattern, result.flags),
|
|
2042
|
+
}, startToken, this._lexer.peek());
|
|
2043
|
+
}
|
|
2044
|
+
this.reportError("W002", startToken, (_a = result.pattern) !== null && _a !== void 0 ? _a : "");
|
|
2045
|
+
return null;
|
|
2046
|
+
}
|
|
2047
|
+
/**
|
|
2048
|
+
* Gets an expression
|
|
2049
|
+
*/
|
|
2050
|
+
getExpression(allowSequence = true) {
|
|
2051
|
+
const expr = this.parseExpr(allowSequence);
|
|
2052
|
+
if (expr) {
|
|
2053
|
+
return expr;
|
|
2054
|
+
}
|
|
2055
|
+
this.reportError("W001");
|
|
2056
|
+
return null;
|
|
2057
|
+
}
|
|
2058
|
+
// ==========================================================================
|
|
2059
|
+
// Helpers
|
|
2060
|
+
/**
|
|
2061
|
+
* Tests the type of the next token
|
|
2062
|
+
* @param type Expected token type
|
|
2063
|
+
* @param errorCode Error to raise if the next token is not expected
|
|
2064
|
+
* @param allowEof Allow an EOF instead of the expected token?
|
|
2065
|
+
*/
|
|
2066
|
+
expectToken(type, errorCode, allowEof) {
|
|
2067
|
+
const next = this._lexer.peek();
|
|
2068
|
+
if (next.type === type || (allowEof && next.type === Token_1.TokenType.Eof)) {
|
|
2069
|
+
// --- Skip the expected token
|
|
2070
|
+
return this._lexer.get();
|
|
2071
|
+
}
|
|
2072
|
+
this.reportError(errorCode !== null && errorCode !== void 0 ? errorCode : "W002", next, next.text);
|
|
2073
|
+
return null;
|
|
2074
|
+
}
|
|
2075
|
+
/**
|
|
2076
|
+
* Skips the next token if the type is the specified one
|
|
2077
|
+
* @param type Token type to check
|
|
2078
|
+
*/
|
|
2079
|
+
skipToken(type) {
|
|
2080
|
+
const next = this._lexer.peek();
|
|
2081
|
+
if (next.type === type) {
|
|
2082
|
+
this._lexer.get();
|
|
2083
|
+
return next;
|
|
2084
|
+
}
|
|
2085
|
+
return null;
|
|
2086
|
+
}
|
|
2087
|
+
/**
|
|
2088
|
+
* Skips the next token if the type is the specified one
|
|
2089
|
+
* @param types Token types to check
|
|
2090
|
+
*/
|
|
2091
|
+
skipTokens(...types) {
|
|
2092
|
+
const next = this._lexer.peek();
|
|
2093
|
+
for (const type of types) {
|
|
2094
|
+
if (next.type === type) {
|
|
2095
|
+
this._lexer.get();
|
|
2096
|
+
return next;
|
|
2097
|
+
}
|
|
2098
|
+
}
|
|
2099
|
+
return null;
|
|
2100
|
+
}
|
|
2101
|
+
/**
|
|
2102
|
+
* Reports the specified error
|
|
2103
|
+
* @param errorCode Error code
|
|
2104
|
+
* @param token Token that represents the error's position
|
|
2105
|
+
* @param options Error message options
|
|
2106
|
+
*/
|
|
2107
|
+
reportError(errorCode, token, ...options) {
|
|
2108
|
+
var _a;
|
|
2109
|
+
let errorText = (_a = ParserError_1.errorMessages[errorCode]) !== null && _a !== void 0 ? _a : "Unkonwn error";
|
|
2110
|
+
if (options) {
|
|
2111
|
+
options.forEach((o, idx) => (errorText = replace(errorText, `{${idx}}`, options[idx].toString())));
|
|
2112
|
+
}
|
|
2113
|
+
if (!token) {
|
|
2114
|
+
token = this._lexer.peek();
|
|
2115
|
+
}
|
|
2116
|
+
this._parseErrors.push({
|
|
2117
|
+
code: errorCode,
|
|
2118
|
+
text: errorText,
|
|
2119
|
+
line: token.location.startLine,
|
|
2120
|
+
column: token.location.startColumn,
|
|
2121
|
+
position: token.location.startPosition,
|
|
2122
|
+
});
|
|
2123
|
+
throw new ParserError_1.ParserError(errorText, errorCode);
|
|
2124
|
+
function replace(input, placeholder, replacement) {
|
|
2125
|
+
do {
|
|
2126
|
+
input = input.replace(placeholder, replacement);
|
|
2127
|
+
} while (input.includes(placeholder));
|
|
2128
|
+
return input;
|
|
2129
|
+
}
|
|
2130
|
+
}
|
|
2131
|
+
/**
|
|
2132
|
+
* Creates an expression node
|
|
2133
|
+
* @param type Expression type
|
|
2134
|
+
* @param stump Stump properties
|
|
2135
|
+
* @param startToken The token that starts the expression
|
|
2136
|
+
* @param endToken The token that ends the expression
|
|
2137
|
+
* @param source Expression source code to store to the node
|
|
2138
|
+
*/
|
|
2139
|
+
createNode(type, stump, startToken, endToken, source) {
|
|
2140
|
+
if (!endToken) {
|
|
2141
|
+
endToken = this._lexer.peek();
|
|
2142
|
+
}
|
|
2143
|
+
const startPosition = startToken.location.startPosition;
|
|
2144
|
+
const endPosition = endToken.location.startPosition;
|
|
2145
|
+
return Object.assign({}, stump, {
|
|
2146
|
+
type,
|
|
2147
|
+
startPosition,
|
|
2148
|
+
endPosition,
|
|
2149
|
+
startLine: startToken.location.startLine,
|
|
2150
|
+
startColumn: startToken.location.startColumn,
|
|
2151
|
+
endLine: endToken.location.endLine,
|
|
2152
|
+
endColumn: endToken.location.endColumn,
|
|
2153
|
+
source: source !== null && source !== void 0 ? source : this.getSource(startToken, endToken),
|
|
2154
|
+
});
|
|
2155
|
+
}
|
|
2156
|
+
/**
|
|
2157
|
+
* Creates an expression node
|
|
2158
|
+
* @param type Expression type
|
|
2159
|
+
* @param stump Stump properties
|
|
2160
|
+
* @param startToken The token that starts the expression
|
|
2161
|
+
* @param endToken The token that ends the expression
|
|
2162
|
+
* @param source Expression source code to store to the node
|
|
2163
|
+
*/
|
|
2164
|
+
createExpressionNode(type, stump = {}, startToken, endToken, source) {
|
|
2165
|
+
if (!endToken) {
|
|
2166
|
+
endToken = this._lexer.peek();
|
|
2167
|
+
}
|
|
2168
|
+
if (!startToken) {
|
|
2169
|
+
startToken = endToken;
|
|
2170
|
+
}
|
|
2171
|
+
const startPosition = startToken.location.startPosition;
|
|
2172
|
+
const endPosition = endToken.location.endPosition;
|
|
2173
|
+
return Object.assign({}, stump, {
|
|
2174
|
+
type,
|
|
2175
|
+
startPosition,
|
|
2176
|
+
endPosition,
|
|
2177
|
+
startLine: startToken.location.startLine,
|
|
2178
|
+
startColumn: startToken.location.startColumn,
|
|
2179
|
+
endLine: endToken.location.endLine,
|
|
2180
|
+
endColumn: endToken.location.endColumn,
|
|
2181
|
+
source: source !== null && source !== void 0 ? source : this.getSource(startToken, endToken),
|
|
2182
|
+
startToken,
|
|
2183
|
+
endToken,
|
|
2184
|
+
});
|
|
2185
|
+
}
|
|
2186
|
+
/**
|
|
2187
|
+
* Creates a statement node
|
|
2188
|
+
* @param type Statement type
|
|
2189
|
+
* @param stump Stump properties
|
|
2190
|
+
* @param startToken The token that starts the statement
|
|
2191
|
+
* @param endToken The token that ends the statement
|
|
2192
|
+
*/
|
|
2193
|
+
createStatementNode(type, stump, startToken, endToken) {
|
|
2194
|
+
var _a, _b, _c, _d, _e;
|
|
2195
|
+
const startPosition = (_a = startToken === null || startToken === void 0 ? void 0 : startToken.location) === null || _a === void 0 ? void 0 : _a.startPosition;
|
|
2196
|
+
const currentToken = this._lexer.peek();
|
|
2197
|
+
const endPosition = endToken
|
|
2198
|
+
? endToken.location.endPosition
|
|
2199
|
+
: currentToken.type === Token_1.TokenType.Eof
|
|
2200
|
+
? currentToken.location.startPosition + 1
|
|
2201
|
+
: currentToken.location.startPosition;
|
|
2202
|
+
return Object.assign({}, stump, {
|
|
2203
|
+
type,
|
|
2204
|
+
startPosition,
|
|
2205
|
+
endPosition,
|
|
2206
|
+
startLine: (_b = startToken === null || startToken === void 0 ? void 0 : startToken.location) === null || _b === void 0 ? void 0 : _b.startLine,
|
|
2207
|
+
startColumn: (_c = startToken === null || startToken === void 0 ? void 0 : startToken.location) === null || _c === void 0 ? void 0 : _c.startColumn,
|
|
2208
|
+
endLine: endToken ? endToken.location.endLine : (_d = startToken === null || startToken === void 0 ? void 0 : startToken.location) === null || _d === void 0 ? void 0 : _d.endLine,
|
|
2209
|
+
endColumn: endToken ? endToken.location.endColumn : (_e = startToken === null || startToken === void 0 ? void 0 : startToken.location) === null || _e === void 0 ? void 0 : _e.endColumn,
|
|
2210
|
+
source: this.source && startPosition !== undefined && endPosition !== undefined
|
|
2211
|
+
? this.source.substring(startPosition, endPosition)
|
|
2212
|
+
: undefined,
|
|
2213
|
+
startToken,
|
|
2214
|
+
endToken,
|
|
2215
|
+
});
|
|
2216
|
+
}
|
|
2217
|
+
/**
|
|
2218
|
+
* Gets the source code for the specified token range
|
|
2219
|
+
* @param start Start token
|
|
2220
|
+
* @param end Optional end token
|
|
2221
|
+
* @returns The source code for the token range
|
|
2222
|
+
*/
|
|
2223
|
+
getSource(start, end) {
|
|
2224
|
+
return this.source.substring(start.location.startPosition, end.type === Token_1.TokenType.Eof ? end.location.startPosition : end.location.endPosition);
|
|
2225
|
+
}
|
|
2226
|
+
/**
|
|
2227
|
+
* Parses a binary literal
|
|
2228
|
+
* @param token Literal token
|
|
2229
|
+
*/
|
|
2230
|
+
parseBinaryLiteral(token) {
|
|
2231
|
+
let value;
|
|
2232
|
+
const bigValue = BigInt(token.text.replace(/[_']/g, ""));
|
|
2233
|
+
if (bigValue < Number.MIN_SAFE_INTEGER || bigValue > Number.MAX_SAFE_INTEGER) {
|
|
2234
|
+
value = bigValue;
|
|
2235
|
+
}
|
|
2236
|
+
else {
|
|
2237
|
+
value = parseInt(token.text.substring(2).replace(/[_']/g, ""), 2);
|
|
2238
|
+
}
|
|
2239
|
+
return this.createExpressionNode("LitE", {
|
|
2240
|
+
value,
|
|
2241
|
+
}, token, token);
|
|
2242
|
+
}
|
|
2243
|
+
/**
|
|
2244
|
+
* Parses a decimal literal
|
|
2245
|
+
* @param token Literal token
|
|
2246
|
+
*/
|
|
2247
|
+
parseDecimalLiteral(token) {
|
|
2248
|
+
let value;
|
|
2249
|
+
const bigValue = BigInt(token.text.replace(/[_']/g, ""));
|
|
2250
|
+
if (bigValue < Number.MIN_SAFE_INTEGER || bigValue > Number.MAX_SAFE_INTEGER) {
|
|
2251
|
+
value = bigValue;
|
|
2252
|
+
}
|
|
2253
|
+
else {
|
|
2254
|
+
value = parseInt(token.text.replace(/[_']/g, ""), 10);
|
|
2255
|
+
}
|
|
2256
|
+
return this.createExpressionNode("LitE", {
|
|
2257
|
+
value,
|
|
2258
|
+
}, token, token);
|
|
2259
|
+
}
|
|
2260
|
+
/**
|
|
2261
|
+
* Parses a hexadecimal literal
|
|
2262
|
+
* @param token Literal token
|
|
2263
|
+
*/
|
|
2264
|
+
parseHexadecimalLiteral(token) {
|
|
2265
|
+
let value;
|
|
2266
|
+
const bigValue = BigInt(token.text.replace(/[_']/g, ""));
|
|
2267
|
+
if (bigValue < Number.MIN_SAFE_INTEGER || bigValue > Number.MAX_SAFE_INTEGER) {
|
|
2268
|
+
value = bigValue;
|
|
2269
|
+
}
|
|
2270
|
+
else {
|
|
2271
|
+
value = parseInt(token.text.substring(2).replace(/[_']/g, ""), 16);
|
|
2272
|
+
}
|
|
2273
|
+
return this.createExpressionNode("LitE", {
|
|
2274
|
+
value,
|
|
2275
|
+
}, token, token);
|
|
2276
|
+
}
|
|
2277
|
+
/**
|
|
2278
|
+
* Parses a real literal
|
|
2279
|
+
* @param token Literal token
|
|
2280
|
+
*/
|
|
2281
|
+
parseRealLiteral(token) {
|
|
2282
|
+
let value = parseFloat(token.text.replace(/[_']/g, ""));
|
|
2283
|
+
return this.createExpressionNode("LitE", {
|
|
2284
|
+
value,
|
|
2285
|
+
}, token, token);
|
|
2286
|
+
}
|
|
2287
|
+
/**
|
|
2288
|
+
* Converts a string token to intrinsic string
|
|
2289
|
+
* @param token Literal token
|
|
2290
|
+
*/
|
|
2291
|
+
parseStringLiteral(token) {
|
|
2292
|
+
const input = token.text.length < 2 ? "" : token.text.substring(1, token.text.length - 1);
|
|
2293
|
+
let result = "";
|
|
2294
|
+
let state = StrParseState.Normal;
|
|
2295
|
+
let collect = 0;
|
|
2296
|
+
for (const ch of input) {
|
|
2297
|
+
switch (state) {
|
|
2298
|
+
case StrParseState.Normal:
|
|
2299
|
+
if (ch === "\\") {
|
|
2300
|
+
state = StrParseState.Backslash;
|
|
2301
|
+
}
|
|
2302
|
+
else {
|
|
2303
|
+
result += ch;
|
|
2304
|
+
}
|
|
2305
|
+
break;
|
|
2306
|
+
case StrParseState.Backslash:
|
|
2307
|
+
state = StrParseState.Normal;
|
|
2308
|
+
switch (ch) {
|
|
2309
|
+
case "b":
|
|
2310
|
+
result += "\b";
|
|
2311
|
+
break;
|
|
2312
|
+
case "f":
|
|
2313
|
+
result += "\f";
|
|
2314
|
+
break;
|
|
2315
|
+
case "n":
|
|
2316
|
+
result += "\n";
|
|
2317
|
+
break;
|
|
2318
|
+
case "r":
|
|
2319
|
+
result += "\r";
|
|
2320
|
+
break;
|
|
2321
|
+
case "t":
|
|
2322
|
+
result += "\t";
|
|
2323
|
+
break;
|
|
2324
|
+
case "v":
|
|
2325
|
+
result += "\v";
|
|
2326
|
+
break;
|
|
2327
|
+
case "S":
|
|
2328
|
+
result += "\xa0";
|
|
2329
|
+
break;
|
|
2330
|
+
case "0":
|
|
2331
|
+
result += String.fromCharCode(0x00);
|
|
2332
|
+
break;
|
|
2333
|
+
case "'":
|
|
2334
|
+
result += "'";
|
|
2335
|
+
break;
|
|
2336
|
+
case '"':
|
|
2337
|
+
result += '"';
|
|
2338
|
+
break;
|
|
2339
|
+
case "\\":
|
|
2340
|
+
result += "\\";
|
|
2341
|
+
break;
|
|
2342
|
+
case "x":
|
|
2343
|
+
state = StrParseState.X;
|
|
2344
|
+
break;
|
|
2345
|
+
case "u":
|
|
2346
|
+
state = StrParseState.UX1;
|
|
2347
|
+
break;
|
|
2348
|
+
default:
|
|
2349
|
+
result += "\\" + ch;
|
|
2350
|
+
break;
|
|
2351
|
+
}
|
|
2352
|
+
break;
|
|
2353
|
+
case StrParseState.X:
|
|
2354
|
+
if (isHexaDecimal(ch)) {
|
|
2355
|
+
collect = parseInt(ch, 16);
|
|
2356
|
+
state = StrParseState.Xh;
|
|
2357
|
+
}
|
|
2358
|
+
else {
|
|
2359
|
+
result += "x";
|
|
2360
|
+
state = StrParseState.Normal;
|
|
2361
|
+
}
|
|
2362
|
+
break;
|
|
2363
|
+
case StrParseState.Xh:
|
|
2364
|
+
if (isHexaDecimal(ch)) {
|
|
2365
|
+
collect = collect * 0x10 + parseInt(ch, 16);
|
|
2366
|
+
result += String.fromCharCode(collect);
|
|
2367
|
+
state = StrParseState.Normal;
|
|
2368
|
+
}
|
|
2369
|
+
else {
|
|
2370
|
+
result += String.fromCharCode(collect);
|
|
2371
|
+
result += ch;
|
|
2372
|
+
state = StrParseState.Normal;
|
|
2373
|
+
}
|
|
2374
|
+
break;
|
|
2375
|
+
case StrParseState.UX1:
|
|
2376
|
+
if (ch === "{") {
|
|
2377
|
+
state = StrParseState.Ucp1;
|
|
2378
|
+
break;
|
|
2379
|
+
}
|
|
2380
|
+
if (isHexaDecimal(ch)) {
|
|
2381
|
+
collect = parseInt(ch, 16);
|
|
2382
|
+
state = StrParseState.UX2;
|
|
2383
|
+
}
|
|
2384
|
+
else {
|
|
2385
|
+
result += "x";
|
|
2386
|
+
state = StrParseState.Normal;
|
|
2387
|
+
}
|
|
2388
|
+
break;
|
|
2389
|
+
case StrParseState.UX2:
|
|
2390
|
+
if (isHexaDecimal(ch)) {
|
|
2391
|
+
collect = collect * 0x10 + parseInt(ch, 16);
|
|
2392
|
+
state = StrParseState.UX3;
|
|
2393
|
+
}
|
|
2394
|
+
else {
|
|
2395
|
+
result += String.fromCharCode(collect);
|
|
2396
|
+
result += ch;
|
|
2397
|
+
state = StrParseState.Normal;
|
|
2398
|
+
}
|
|
2399
|
+
break;
|
|
2400
|
+
case StrParseState.UX3:
|
|
2401
|
+
if (isHexaDecimal(ch)) {
|
|
2402
|
+
collect = collect * 0x10 + parseInt(ch, 16);
|
|
2403
|
+
state = StrParseState.UX4;
|
|
2404
|
+
}
|
|
2405
|
+
else {
|
|
2406
|
+
result += String.fromCharCode(collect);
|
|
2407
|
+
result += ch;
|
|
2408
|
+
state = StrParseState.Normal;
|
|
2409
|
+
}
|
|
2410
|
+
break;
|
|
2411
|
+
case StrParseState.UX4:
|
|
2412
|
+
if (isHexaDecimal(ch)) {
|
|
2413
|
+
collect = collect * 0x10 + parseInt(ch, 16);
|
|
2414
|
+
result += String.fromCharCode(collect);
|
|
2415
|
+
state = StrParseState.Normal;
|
|
2416
|
+
}
|
|
2417
|
+
else {
|
|
2418
|
+
result += String.fromCharCode(collect);
|
|
2419
|
+
result += ch;
|
|
2420
|
+
state = StrParseState.Normal;
|
|
2421
|
+
}
|
|
2422
|
+
break;
|
|
2423
|
+
case StrParseState.Ucp1:
|
|
2424
|
+
if (isHexaDecimal(ch)) {
|
|
2425
|
+
collect = parseInt(ch, 16);
|
|
2426
|
+
state = StrParseState.Ucp2;
|
|
2427
|
+
}
|
|
2428
|
+
else {
|
|
2429
|
+
result += "x";
|
|
2430
|
+
state = StrParseState.Normal;
|
|
2431
|
+
}
|
|
2432
|
+
break;
|
|
2433
|
+
case StrParseState.Ucp2:
|
|
2434
|
+
if (isHexaDecimal(ch)) {
|
|
2435
|
+
collect = collect * 0x10 + parseInt(ch, 16);
|
|
2436
|
+
state = StrParseState.Ucp3;
|
|
2437
|
+
}
|
|
2438
|
+
else {
|
|
2439
|
+
result += String.fromCharCode(collect);
|
|
2440
|
+
result += ch;
|
|
2441
|
+
state = StrParseState.Normal;
|
|
2442
|
+
}
|
|
2443
|
+
break;
|
|
2444
|
+
case StrParseState.Ucp3:
|
|
2445
|
+
if (isHexaDecimal(ch)) {
|
|
2446
|
+
collect = collect * 0x10 + parseInt(ch, 16);
|
|
2447
|
+
state = StrParseState.Ucp4;
|
|
2448
|
+
}
|
|
2449
|
+
else {
|
|
2450
|
+
result += String.fromCharCode(collect);
|
|
2451
|
+
result += ch;
|
|
2452
|
+
state = StrParseState.Normal;
|
|
2453
|
+
}
|
|
2454
|
+
break;
|
|
2455
|
+
case StrParseState.Ucp4:
|
|
2456
|
+
if (isHexaDecimal(ch)) {
|
|
2457
|
+
collect = collect * 0x10 + parseInt(ch, 16);
|
|
2458
|
+
state = StrParseState.Ucp5;
|
|
2459
|
+
}
|
|
2460
|
+
else {
|
|
2461
|
+
result += String.fromCharCode(collect);
|
|
2462
|
+
result += ch;
|
|
2463
|
+
state = StrParseState.Normal;
|
|
2464
|
+
}
|
|
2465
|
+
break;
|
|
2466
|
+
case StrParseState.Ucp5:
|
|
2467
|
+
if (isHexaDecimal(ch)) {
|
|
2468
|
+
collect = collect * 0x10 + parseInt(ch, 16);
|
|
2469
|
+
state = StrParseState.Ucp6;
|
|
2470
|
+
}
|
|
2471
|
+
else {
|
|
2472
|
+
result += String.fromCharCode(collect);
|
|
2473
|
+
result += ch;
|
|
2474
|
+
state = StrParseState.Normal;
|
|
2475
|
+
}
|
|
2476
|
+
break;
|
|
2477
|
+
case StrParseState.Ucp6:
|
|
2478
|
+
if (isHexaDecimal(ch)) {
|
|
2479
|
+
collect = collect * 0x10 + parseInt(ch, 16);
|
|
2480
|
+
state = StrParseState.UcpTail;
|
|
2481
|
+
}
|
|
2482
|
+
else {
|
|
2483
|
+
result += String.fromCharCode(collect);
|
|
2484
|
+
result += ch;
|
|
2485
|
+
state = StrParseState.Normal;
|
|
2486
|
+
}
|
|
2487
|
+
break;
|
|
2488
|
+
case StrParseState.UcpTail:
|
|
2489
|
+
result += String.fromCharCode(collect);
|
|
2490
|
+
if (ch !== "}") {
|
|
2491
|
+
result += ch;
|
|
2492
|
+
}
|
|
2493
|
+
state = StrParseState.Normal;
|
|
2494
|
+
break;
|
|
2495
|
+
}
|
|
2496
|
+
}
|
|
2497
|
+
// --- Handle the final machine state
|
|
2498
|
+
switch (state) {
|
|
2499
|
+
case StrParseState.Backslash:
|
|
2500
|
+
result += "\\";
|
|
2501
|
+
break;
|
|
2502
|
+
case StrParseState.X:
|
|
2503
|
+
result += "x";
|
|
2504
|
+
break;
|
|
2505
|
+
case StrParseState.Xh:
|
|
2506
|
+
result += String.fromCharCode(collect);
|
|
2507
|
+
break;
|
|
2508
|
+
}
|
|
2509
|
+
// --- Done
|
|
2510
|
+
return this.createExpressionNode("LitE", {
|
|
2511
|
+
value: result,
|
|
2512
|
+
}, token, token);
|
|
2513
|
+
function isHexaDecimal(ch) {
|
|
2514
|
+
return (ch >= "0" && ch <= "9") || (ch >= "a" && ch <= "f") || (ch >= "A" && ch <= "F");
|
|
2515
|
+
}
|
|
2516
|
+
}
|
|
2517
|
+
convertToArrayDestructure(seq) {
|
|
2518
|
+
var _a;
|
|
2519
|
+
const items = seq.type === "SeqE" ? seq.expressions : seq.items;
|
|
2520
|
+
const result = this.createExpressionNode("Destr", { arrayDestruct: [] }, seq.startToken, seq.endToken);
|
|
2521
|
+
// --- Convert all items
|
|
2522
|
+
for (const item of items) {
|
|
2523
|
+
let arrayD;
|
|
2524
|
+
switch (item.type) {
|
|
2525
|
+
case "NoArgE":
|
|
2526
|
+
arrayD = this.createExpressionNode("ADestr", {}, item.startToken, item.endToken);
|
|
2527
|
+
break;
|
|
2528
|
+
case "IdE":
|
|
2529
|
+
arrayD = this.createExpressionNode("ADestr", { id: item.name }, item.startToken, item.endToken);
|
|
2530
|
+
break;
|
|
2531
|
+
case "Destr":
|
|
2532
|
+
result.arrayDestruct.push(...item.arrayDestruct);
|
|
2533
|
+
break;
|
|
2534
|
+
case "ADestr":
|
|
2535
|
+
arrayD = item;
|
|
2536
|
+
break;
|
|
2537
|
+
case "ALitE": {
|
|
2538
|
+
const destructure = this.convertToArrayDestructure(item);
|
|
2539
|
+
if (destructure) {
|
|
2540
|
+
arrayD = this.createExpressionNode("ADestr", {
|
|
2541
|
+
arrayDestruct: destructure.arrayDestruct,
|
|
2542
|
+
}, item.startToken, item.endToken);
|
|
2543
|
+
}
|
|
2544
|
+
break;
|
|
2545
|
+
}
|
|
2546
|
+
case "ODestr":
|
|
2547
|
+
arrayD = this.createExpressionNode("ADestr", {
|
|
2548
|
+
objectDestruct: item,
|
|
2549
|
+
}, item.startToken, item.endToken);
|
|
2550
|
+
break;
|
|
2551
|
+
case "OLitE": {
|
|
2552
|
+
const destructure = this.convertToObjectDestructure(item);
|
|
2553
|
+
if (destructure) {
|
|
2554
|
+
arrayD = this.createExpressionNode("ADestr", {
|
|
2555
|
+
objectDestruct: destructure.objectDestruct,
|
|
2556
|
+
}, item.startToken, item.endToken);
|
|
2557
|
+
}
|
|
2558
|
+
break;
|
|
2559
|
+
}
|
|
2560
|
+
default:
|
|
2561
|
+
this.reportError("W017");
|
|
2562
|
+
return null;
|
|
2563
|
+
}
|
|
2564
|
+
if (arrayD)
|
|
2565
|
+
(_a = result.arrayDestruct) === null || _a === void 0 ? void 0 : _a.push(arrayD);
|
|
2566
|
+
}
|
|
2567
|
+
// --- Done.
|
|
2568
|
+
return result;
|
|
2569
|
+
}
|
|
2570
|
+
convertToObjectDestructure(objLit) {
|
|
2571
|
+
var _a;
|
|
2572
|
+
const result = this.createExpressionNode("Destr", { objectDestruct: [] }, objLit.startToken, objLit.endToken);
|
|
2573
|
+
// --- Convert all items
|
|
2574
|
+
for (const prop of objLit.props) {
|
|
2575
|
+
if (Array.isArray(prop)) {
|
|
2576
|
+
}
|
|
2577
|
+
else {
|
|
2578
|
+
reportError("W018");
|
|
2579
|
+
return null;
|
|
2580
|
+
}
|
|
2581
|
+
const [propKey, propValue] = prop;
|
|
2582
|
+
if (propKey.type !== "IdE") {
|
|
2583
|
+
reportError("W018");
|
|
2584
|
+
return null;
|
|
2585
|
+
}
|
|
2586
|
+
let objD;
|
|
2587
|
+
switch (propValue.type) {
|
|
2588
|
+
case "IdE":
|
|
2589
|
+
if (propValue.name === propKey.name) {
|
|
2590
|
+
objD = this.createExpressionNode("ODestr", { id: propKey.name }, propValue.startToken, propValue.endToken);
|
|
2591
|
+
}
|
|
2592
|
+
else {
|
|
2593
|
+
objD = this.createExpressionNode("ODestr", {
|
|
2594
|
+
id: propKey.name,
|
|
2595
|
+
alias: propValue.name,
|
|
2596
|
+
}, propValue.startToken, propValue.endToken);
|
|
2597
|
+
}
|
|
2598
|
+
break;
|
|
2599
|
+
case "ADestr": {
|
|
2600
|
+
objD = this.createExpressionNode("ODestr", {
|
|
2601
|
+
id: propKey.name,
|
|
2602
|
+
arrayDestruct: propValue,
|
|
2603
|
+
}, propKey.startToken, propValue.endToken);
|
|
2604
|
+
break;
|
|
2605
|
+
}
|
|
2606
|
+
case "ALitE": {
|
|
2607
|
+
const destructure = this.convertToArrayDestructure(propValue);
|
|
2608
|
+
if (destructure) {
|
|
2609
|
+
objD = this.createExpressionNode("ODestr", {
|
|
2610
|
+
id: propKey.name,
|
|
2611
|
+
arrayDestruct: destructure.arrayDestruct,
|
|
2612
|
+
}, propKey.startToken, propValue.endToken);
|
|
2613
|
+
}
|
|
2614
|
+
break;
|
|
2615
|
+
}
|
|
2616
|
+
case "ODestr":
|
|
2617
|
+
objD = propValue;
|
|
2618
|
+
break;
|
|
2619
|
+
case "OLitE": {
|
|
2620
|
+
const destructure = this.convertToObjectDestructure(propValue);
|
|
2621
|
+
if (destructure) {
|
|
2622
|
+
objD = this.createExpressionNode("ODestr", {
|
|
2623
|
+
id: propKey.name,
|
|
2624
|
+
objectDestruct: destructure.objectDestruct,
|
|
2625
|
+
}, propKey.startToken, propValue.endToken);
|
|
2626
|
+
}
|
|
2627
|
+
break;
|
|
2628
|
+
}
|
|
2629
|
+
default:
|
|
2630
|
+
this.reportError("W018");
|
|
2631
|
+
return null;
|
|
2632
|
+
}
|
|
2633
|
+
if (objD)
|
|
2634
|
+
(_a = result.objectDestruct) === null || _a === void 0 ? void 0 : _a.push(objD);
|
|
2635
|
+
}
|
|
2636
|
+
// --- Done.
|
|
2637
|
+
return result;
|
|
2638
|
+
}
|
|
2639
|
+
/**
|
|
2640
|
+
* Tests if the specified token can be the start of an expression
|
|
2641
|
+
*/
|
|
2642
|
+
isExpressionStart(token) {
|
|
2643
|
+
var _a, _b;
|
|
2644
|
+
return (_b = (_a = TokenTrait_1.tokenTraits[token.type]) === null || _a === void 0 ? void 0 : _a.expressionStart) !== null && _b !== void 0 ? _b : false;
|
|
2645
|
+
}
|
|
2646
|
+
}
|
|
2647
|
+
exports.Parser = Parser;
|