From 7597663d76a0568401a88e8fe34bcc40d63c1d2d Mon Sep 17 00:00:00 2001 From: wingsummer <1326224942@qq.com> Date: Sun, 6 Apr 2025 20:11:30 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=95=B0=E5=80=BC=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E6=97=A0=E7=AC=A6=E5=8F=B7=E5=88=87=E6=8D=A2=E6=A0=BC=E5=BC=8F?= =?UTF-8?q?=EF=BC=9B=E5=88=9D=E6=AD=A5=E4=BB=A3=E7=A0=81=E5=86=85=E5=AE=B9?= =?UTF-8?q?=E6=8F=90=E7=A4=BA=EF=BC=9B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lang/zh_CN/winghex_zh_CN.ts | 585 ++++---- lang/zh_TW/winghex_zh_TW.ts | 585 ++++---- src/class/asbuilder.cpp | 4 +- src/class/ascompletion.cpp | 70 +- src/class/asconsolecompletion.cpp | 24 +- src/class/asconsolecompletion.h | 21 +- src/class/aspreprocesser.cpp | 83 +- src/class/aspreprocesser.h | 38 +- src/class/qascodeparser.cpp | 2223 ++++++++++++++++------------- src/class/qascodeparser.h | 192 +-- src/class/scriptmachine.cpp | 12 +- src/dialog/mainwindow.cpp | 55 +- src/dialog/mainwindow.h | 8 +- 13 files changed, 2160 insertions(+), 1740 deletions(-) diff --git a/lang/zh_CN/winghex_zh_CN.ts b/lang/zh_CN/winghex_zh_CN.ts index 6593daf..7f6ba1e 100644 --- a/lang/zh_CN/winghex_zh_CN.ts +++ b/lang/zh_CN/winghex_zh_CN.ts @@ -871,7 +871,7 @@ - + View 视图 @@ -908,8 +908,8 @@ - - + + Plugin 插件 @@ -920,7 +920,7 @@ - + Log 日志 @@ -943,23 +943,23 @@ - - - - - + + + + + Copy 复制 - - - - - - + + + + + + CopyToClipBoard 数据已拷贝到粘贴板 @@ -974,270 +974,270 @@ 大端 - + Number 数值 - - + + CheckSum 校验和 - - + + DeleteBookMark 删除书签 - - + + ClearBookMark 清空书签 - - - - + + + + BookMark 书签 - - + + DecodeText 解码字符串 - + ScriptConsole 脚本控制台 - - + + DVList 可视化列表 - - + + DVTree 可视化树数据 - - + + DVTable 可视化表格 - - + + DVText 可视化文本 - - + + Basic 基础 - + New 新建 - + OpenF 打开文件 - + OpenWorkSpace 打开工作区 - + RecentFiles 最近打开 - + Reload 重新加载 - - + + Save 保存 - + SaveAs 另存为 - + ConvertWS 转为工作区 - + Export 导出 - + SaveSel 保存选区字节 - - - - + + + + General 基本 - + Undo 撤销 - + Redo 恢复 - + Cut 剪切 - + Paste 粘贴 - + Delete 删除 - + Clone 克隆 - + Lookup 查询 - + Find 查找 - + Goto 跳转 - + Encoding 编码 - + FileInfo 文件信息 - - + + Hex 十六进制 - + CutHex 剪切(十六进制) - + CopyHex 复制(十六进制) - + PasteHex 粘贴(十六进制) - - + + Fill 填充 - + FillZero 填充零 - - - - - + + + + + MetaData 标注 - + DeleteMetadata 删除标注 - + ClearMetadata 清空标注 - + MetaDataEdit 编辑标注 - + DeleteMetaData 删除标注 - + ClearMetaData 清空标注 - + Display 显示 - + ViewText 文本预览 - + Scale 缩放 @@ -1322,742 +1322,747 @@ 无扩展 - - - - - - + + + + + + ExportResult 导出结果 - - - + + + NothingToSave 没有保存的数据 - - - - + + + + ClearResult 清空结果 - + OpenExt 打开 - 拓展 - + ResetScale 重置缩放 - + ShowMetafg 标注前景色 - + ShowMetabg 标注背景色 - + ShowMetaComment 批注 - + MetaShowAll 显示所有标注 - + MetaHideAll 隐藏所有标注 - + FileStatus 文件状态 - + InfoSave 是否保存 - + ReadOnly 可读写 - + SetLocked 启用/禁用锁定编辑 - + ErrUnLock 锁定编辑失败 - + SetOver 启用/禁用改变大小 - + + UnsignedHex + 无符号 Hex + + + ErrUnOver 锁定文件大小失败 - + Window 窗体 - + Editor 编辑器 - + Tools 工具 - + HexEditorLayout 编辑器布局 - + SetBaseAddr 设置基址 - + addressBase 基址 - + inputAddressBase 请输入基址 - + WarnBigBaseAddress 基址过大,你得到的地址将会不正确! - + ErrBaseAddress 非法基址输入 - + SetColInfo 显示/隐藏地址栏 - + SetHeaderInfo 显示/隐藏表头 - + SetAsciiString 显示/隐藏解码字符串 - + Layout 布局 - + Fullscreen 全屏 - + Default 默认 - - - + + + LayoutRestoring... 恢复布局中... - + RestoreLayout 恢复布局 - - + + SaveLayout 保存布局 - + ExportLog 导出日志 - + ClearLog 清空日志 - + InsepctQt 监视 Qt - + ScriptEditor 脚本编辑器 - + Scripts 脚本仓库 - + PluginFunctions 插件功能 - + ScriptSetting 脚本设置 - + PluginSettings 插件设置 - + Info 信息 - + Software 软件 - + Sponsor 赞助 - + CheckUpdate 检查更新 - + Wiki 网页 Wiki - + AboutQT 关于 QT - + SetPageIDEmptyTryUseName 设置页 ID 为空,尝试使用名称作为 ID - + SetPageDupNameIgnored 设置页重复的 ID 名称,已忽略加载 - + Plugin %1 contains a duplicate ID (%2) that is already registered by plugin %3 插件 %1 包含重复 ID (%2),该 ID 已被插件 %3 注册 - - + + ChooseFile 选择文件 - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + Error 错误 - - + + FileNotExist 文件不存在! - - - - - - - - + + + + + + + + FilePermission 因文件权限无法继续! - + ProjectFile (*.wingpro) 项目文件 (*.wingpro) - + ReloadSuccessfully 文件重新加载成功! - + ReloadUnSuccessfully 文件重新加载失败! - - - - - - - + + + + + + + ChooseSaveFile 请选择保存文件路径: - + NoMoreClone 克隆已到上限,无法继续操作! - + FindFininishBusy 查找任务繁忙,请勿重复查找! - + MayTooMuchFindResult 搜索数量已到达上限,结果可能不全,建议请按区段搜索。 - + SaveLayoutSuccess 保存布局成功 - + SaveLayoutError 保存布局失败 - + HasClonedView 该编辑页已被克隆编辑,如果关闭,相关联的页也会被关闭,你确认继续吗? - + SaveWorkSpace 保存工作区 - + WingHexWorkSpace (*.wingpro) 羽云十六进制工作区 (*.wingpro) - + ConfirmSave 正在关闭未保存的文件或工作区,你确定保存吗? - + Column %1 列 %1 - + ConfirmAPPSave 你尝试关闭程序,但仍存在未保存的文件或工作区,你确定保存这些更改吗? - - - - - - + + + + + + SaveSuccessfully 保存成功! - - + + SaveWSError 保存工作区错误! - - + + Warn 警告 - + ScriptObjShow 脚本对象 - + Opening... 打开文件中... - + WorkSpaceOpening... 打开工作区中... - + Reloading... 重载文件中... - + Saving... 保存中... - + SaveNewFirst 请首先保存新建的文件 - + AlreadyWorkSpace 已经是工作区,无需转化 - + ConvWorkSpaceFailed 转化为工作区失败 - + ConvWorkSpaceSuccess 转化为工作区成功 - + SavingAs... 另存为中... - + SaveUnSuccessfully 保存失败! - + Exporting... 导出中... - + ChooseExportFile 请选择导出文件路径: - + ExportSuccessfully 导出成功! - + ExportUnSuccessfully 导出失败! - + SavingSel... 保存选中字节中... - + SaveSelSuccess 保存选区字节成功! - + SaveSelError 保存选区字节失败,因文件不具有可写权限! - - + + CutToClipBoard 数据已剪切到粘贴板! - - + + UnCutToClipBoard 由于保持大小限制,数据剪切到粘贴板失败! - - + + UnCopyToClipBoard 由于保持大小限制,数据剪切到复制板失败! - - + + Finding... 查找中... - + DeleteSuccess 删除成功 - + DeleteFailed 删除失败 - + FindFininish 查找结果完毕! - + PleaseInputFill 请输入填充字节值 - + FillInputTruncWarn 填充输入数值过大,将会被截断填充 - + FillInputError 填充字节输入错误 - - + + InputComment 请输入批注: - - + + BookmarkDelSuccess 删除书签成功 - + BookmarkDelNoItem 无书签可删除 - + BookmarkClearSuccess 书签清空完毕 - - - + + + NoSelection 没有选区,无法继续的操作! - + NoMetaData 无可编辑标记 - + PleaseClearSel 请清空选择 - + MetaDelSuccess 元数据删除成功 - + MetaDelNoItem 无元数据可删除 - + MetaClearSuccess 元数据清空完毕 - + FindResultExporting... 查找结果导出中... - - + + EmptyFindResult 没有可导出的搜索结果! - + SaveFindResult 导出搜索结果成功! - + SaveFindResultError 导出结果失败! - + TooManyBytesDecode 超出解码字节限制…… - + NoTextFileMayInvalid 该文件不是文本文件,以文本方式预览并不是一个好的方式,你确认继续吗? - + LayoutSaving... 布局保存中... - + PleaseInput 请输入 - + LogExporting... 日志导出中... - + ExportLogError 导出日志失败! - + ExportLogSuccess 导出日志成功,路径: - + ClearLogSuccess 清空日志成功! - + BadNetwork 无法与远程服务器的更新检查建立连接,请检查网络。 - + NewestVersion 当前软件为最新版本 - + OlderVersion 你使用的软件为老版本,建议到 Github 和 Gitee 的仓库发行版下载更新。 - + CheckingUpdate 检查更新中…… - + Too much opened files 打开的文件过多,无法继续操作! - + FilePermissionSure2Quit 因文件权限无法保存,你确认要退出吗? - + UnknownErrorSure2Quit 因未知错误无法保存,你确认要退出吗? - + WorkSpaceUnSavedSure2Quit 工作区文件无法保存,你确认要退出吗? - + CopyLimit 拷贝字节超出限制 - + ErrOpenFileBelow 打开文件出现错误(由于权限不足),如下为打开错误的文件: @@ -2696,23 +2701,23 @@ 关闭标签 - + Failed to open script file 打开脚本文件失败 - - + + Invalid file name for #include; it contains a line-break: #include 的文件名无效;它包含换行符: - + Invalid file name for #include; it contains a line-break or unpaired symbol #include 的文件名无效;它包含换行符或不成对的符号 - + Invalid #pragma directive #pragma 指令无效 diff --git a/lang/zh_TW/winghex_zh_TW.ts b/lang/zh_TW/winghex_zh_TW.ts index 663ddd0..12c02d7 100644 --- a/lang/zh_TW/winghex_zh_TW.ts +++ b/lang/zh_TW/winghex_zh_TW.ts @@ -871,7 +871,7 @@ - + View 視圖 @@ -908,8 +908,8 @@ - - + + Plugin 插件 @@ -920,7 +920,7 @@ - + Log 日誌 @@ -943,23 +943,23 @@ - - - - - + + + + + Copy 複製 - - - - - - + + + + + + CopyToClipBoard 數據已拷貝到粘貼板 @@ -974,270 +974,270 @@ 大端 - + Number 數值 - - + + CheckSum 校驗和 - - + + DeleteBookMark 刪除書簽 - - + + ClearBookMark 清空書簽 - - - - + + + + BookMark 書簽 - - + + DecodeText 解碼字串 - + ScriptConsole 腳本控制臺 - - + + DVList 可視化列表 - - + + DVTree 可視化樹數據 - - + + DVTable 可視化表格 - - + + DVText 可視化文本 - - + + Basic 基礎 - + New 新建 - + OpenF 打開檔 - + OpenWorkSpace 打開工作區 - + RecentFiles 最近打開 - + Reload 重新加載 - - + + Save 保存 - + SaveAs 另存為 - + ConvertWS 轉為工作區 - + Export 導出 - + SaveSel 保存選區位元組 - - - - + + + + General 基本 - + Undo 撤銷 - + Redo 恢復 - + Cut 剪切 - + Paste 粘貼 - + Delete 刪除 - + Clone 克隆 - + Lookup 查詢 - + Find 查找 - + Goto 跳轉 - + Encoding 編碼 - + FileInfo 檔資訊 - - + + Hex 十六進制 - + CutHex 剪切(十六進制) - + CopyHex 複製(十六進制) - + PasteHex 粘貼(十六進制) - - + + Fill 填充 - + FillZero 填充零 - - - - - + + + + + MetaData 標注 - + DeleteMetadata 刪除標注 - + ClearMetadata 清空標注 - + MetaDataEdit 編輯標注 - + DeleteMetaData 刪除標注 - + ClearMetaData 清空標注 - + Display 顯示 - + ViewText 文本預覽 - + Scale 縮放 @@ -1322,742 +1322,747 @@ 無擴展 - - - - - - + + + + + + ExportResult 導出結果 - - - + + + NothingToSave 沒有保存的數據 - - - - + + + + ClearResult 清空結果 - + OpenExt 打開 - 拓展 - + ResetScale 重置縮放 - + ShowMetafg 標注前景色 - + ShowMetabg 標注背景色 - + ShowMetaComment 批註 - + MetaShowAll 顯示所有標注 - + MetaHideAll 隱藏所有標注 - + FileStatus 檔狀態 - + InfoSave 是否保存 - + ReadOnly 可讀寫 - + SetLocked 啟用/禁用鎖定編輯 - + ErrUnLock 鎖定編輯失敗 - + SetOver 啟用/禁用改變大小 - + + UnsignedHex + 無符號 Hex + + + ErrUnOver 鎖定檔大小失敗 - + Window 窗體 - + Editor 編輯器 - + Tools 工具 - + HexEditorLayout 編輯器佈局 - + SetBaseAddr 設置基址 - + addressBase 基址 - + inputAddressBase 請輸入基址 - + WarnBigBaseAddress 基址過大,你得到的地址將會不正確! - + ErrBaseAddress 非法基址輸入 - + SetColInfo 顯示/隱藏地址欄 - + SetHeaderInfo 顯示/隱藏表頭 - + SetAsciiString 顯示/隱藏解碼字串 - + Layout 佈局 - + Fullscreen 全屏 - + Default 默認 - - - + + + LayoutRestoring... 恢復佈局中... - + RestoreLayout 恢復佈局 - - + + SaveLayout 保存佈局 - + ExportLog 導出日誌 - + ClearLog 清空日誌 - + InsepctQt 監視 Qt - + ScriptEditor 腳本編輯器 - + Scripts 腳本倉庫 - + PluginFunctions 插件功能 - + ScriptSetting 腳本設置 - + PluginSettings 插件設置 - + Info 資訊 - + Software 軟體 - + Sponsor 贊助 - + CheckUpdate 檢查更新 - + Wiki 網頁 Wiki - + AboutQT 關於 QT - + SetPageIDEmptyTryUseName 設置頁 ID 為空,嘗試使用名稱作為 ID - + SetPageDupNameIgnored 設置頁重複的 ID 名稱,已忽略加載 - + Plugin %1 contains a duplicate ID (%2) that is already registered by plugin %3 插件 %1 包含重複 ID (%2),該 ID 已被插件 %3 註冊 - - + + ChooseFile 選擇檔 - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + Error 錯誤 - - + + FileNotExist 檔不存在! - - - - - - - - + + + + + + + + FilePermission 因檔許可權無法繼續! - + ProjectFile (*.wingpro) 專案檔 (*.wingpro) - + ReloadSuccessfully 檔重新加載成功! - + ReloadUnSuccessfully 檔重新加載失敗! - - - - - - - + + + + + + + ChooseSaveFile 請選擇保存檔路徑: - + NoMoreClone 克隆已到上限,無法繼續操作! - + FindFininishBusy 查找任務繁忙,請勿重複查找! - + MayTooMuchFindResult 搜索數量已到達上限,結果可能不全,建議請按區段搜索。 - + SaveLayoutSuccess 保存佈局成功 - + SaveLayoutError 保存佈局失敗 - + HasClonedView 該編輯頁已被克隆編輯,如果關閉,相關聯的頁也會被關閉,你確認繼續嗎? - + SaveWorkSpace 保存工作區 - + WingHexWorkSpace (*.wingpro) 羽雲十六進制工作區 (*.wingpro) - + ConfirmSave 正在關閉未保存的檔或工作區,你確定保存嗎? - + Column %1 列 %1 - + ConfirmAPPSave 你嘗試關閉程式,但仍存在未保存的檔或工作區,你確定保存這些更改嗎? - - - - - - + + + + + + SaveSuccessfully 保存成功! - - + + SaveWSError 保存工作區錯誤! - - + + Warn 警告 - + ScriptObjShow 腳本對象 - + Opening... 打開檔中... - + WorkSpaceOpening... 打開工作區中... - + Reloading... 重載檔中... - + Saving... 保存中... - + SaveNewFirst 請首先保存新建的檔 - + AlreadyWorkSpace 已經是工作區,無需轉化 - + ConvWorkSpaceFailed 轉化為工作區失敗 - + ConvWorkSpaceSuccess 轉化為工作區成功 - + SavingAs... 另存為中... - + SaveUnSuccessfully 保存失敗! - + Exporting... 導出中... - + ChooseExportFile 請選擇導出檔路徑: - + ExportSuccessfully 導出成功! - + ExportUnSuccessfully 導出失敗! - + SavingSel... 保存選中位元組中... - + SaveSelSuccess 保存選區位元組成功! - + SaveSelError 保存選區位元組失敗,因檔不具有可寫許可權! - - + + CutToClipBoard 數據已剪切到粘貼板! - - + + UnCutToClipBoard 由於保持大小限制,數據剪切到粘貼板失敗! - - + + UnCopyToClipBoard 由於保持大小限制,數據剪切到複製板失敗! - - + + Finding... 查找中... - + DeleteSuccess 刪除成功 - + DeleteFailed 刪除失敗 - + FindFininish 查找結果完畢! - + PleaseInputFill 請輸入填充位元組值 - + FillInputTruncWarn 填充輸入數值過大,將會被截斷填充 - + FillInputError 填充位元組輸入錯誤 - - + + InputComment 請輸入批註: - - + + BookmarkDelSuccess 刪除書簽成功 - + BookmarkDelNoItem 無書簽可刪除 - + BookmarkClearSuccess 書簽清空完畢 - - - + + + NoSelection 沒有選區,無法繼續的操作! - + NoMetaData 無可編輯標記 - + PleaseClearSel 請清空選擇 - + MetaDelSuccess 元數據刪除成功 - + MetaDelNoItem 無元數據可刪除 - + MetaClearSuccess 元數據清空完畢 - + FindResultExporting... 查找結果導出中... - - + + EmptyFindResult 沒有可導出的搜索結果! - + SaveFindResult 導出搜索結果成功! - + SaveFindResultError 導出結果失敗! - + TooManyBytesDecode 超出解碼位元組限制…… - + NoTextFileMayInvalid 該檔不是文本檔,以文本方式預覽並不是一個好的方式,你確認繼續嗎? - + LayoutSaving... 佈局保存中... - + PleaseInput 請輸入 - + LogExporting... 日誌導出中... - + ExportLogError 導出日誌失敗! - + ExportLogSuccess 導出日誌成功,路徑: - + ClearLogSuccess 清空日誌成功! - + BadNetwork 無法與遠程伺服器的更新檢查建立連接,請檢查網路。 - + NewestVersion 當前軟體為最新版本 - + OlderVersion 你使用的軟體為老版本,建議到 Github 和 Gitee 的倉庫發行版下載更新。 - + CheckingUpdate 檢查更新中…… - + Too much opened files 打開的檔過多,無法繼續操作! - + FilePermissionSure2Quit 因檔許可權無法保存,你確認要退出嗎? - + UnknownErrorSure2Quit 因未知錯誤無法保存,你確認要退出嗎? - + WorkSpaceUnSavedSure2Quit 工作區檔無法保存,你確認要退出嗎? - + CopyLimit 拷貝位元組超出限制 - + ErrOpenFileBelow 打開檔出現錯誤(由於許可權不足),如下為打開錯誤的檔: @@ -2696,23 +2701,23 @@ 關閉標籤 - + Failed to open script file 打開腳本檔失敗 - - + + Invalid file name for #include; it contains a line-break: #include 的檔案名無效;它包含換行符: - + Invalid file name for #include; it contains a line-break or unpaired symbol #include 的檔案名無效;它包含換行符或不成對的符號 - + Invalid #pragma directive #pragma 指令無效 diff --git a/src/class/asbuilder.cpp b/src/class/asbuilder.cpp index 6f40e1f..e5cceee 100644 --- a/src/class/asbuilder.cpp +++ b/src/class/asbuilder.cpp @@ -39,7 +39,7 @@ int asBuilder::StartNewModule(const char *moduleName) { if (module == nullptr) return -1; - ClearAll(); + clearAll(); return 0; } @@ -53,7 +53,7 @@ int asBuilder::Build() { for (auto &mod : modifiedScripts) { module->AddScriptSection(mod.section.toUtf8(), mod.script.data(), - mod.script.size(), mod.lineOffset); + mod.script.size()); } int r = module->Build(); diff --git a/src/class/ascompletion.cpp b/src/class/ascompletion.cpp index 346825c..9463b59 100644 --- a/src/class/ascompletion.cpp +++ b/src/class/ascompletion.cpp @@ -18,6 +18,8 @@ #include "ascompletion.h" #include "asdatabase.h" +#include "class/aspreprocesser.h" +#include "class/qascodeparser.h" #include "model/codecompletionmodel.h" #include "wingcodeedit.h" @@ -38,8 +40,7 @@ Q_GLOBAL_STATIC_WITH_ARGS(QByteArray, LEFT_PARE_TRIGGER, ("(")) Q_GLOBAL_STATIC_WITH_ARGS(QByteArray, SEMI_COLON_TRIGGER, (";")) AsCompletion::AsCompletion(asIScriptEngine *engine, WingCodeEdit *p) - : WingCompleter(p), parser(engine), _engine(engine), - m_parseDocument(false) { + : WingCompleter(p), parser(engine), _engine(engine), m_parseDocument(true) { Q_ASSERT(engine); setTriggerList({*DOT_TRIGGER, *DBL_COLON_TRIGGER, @@ -80,7 +81,7 @@ void AsCompletion::applyEmptyNsNode(QList &nodes) { } emptyNsNodes.append(parser.keywordNodes()); } - nodes = emptyNsNodes; + nodes.append(emptyNsNodes); } void AsCompletion::applyClassNodes(QList &nodes) { @@ -134,10 +135,6 @@ void AsCompletion::processTrigger(const QString &trigger, QList nodes; - // TODO: PRs are welcomed !!! - // If this software is well-known or brings me lots of - // financial support, I will implement it myself. - // PARSING THE DOCUMENT if (m_parseDocument) { nodes.append(parseDocument()); } @@ -286,7 +283,64 @@ void AsCompletion::processTrigger(const QString &trigger, setCompletionPrefix(prefix); } -QList AsCompletion::parseDocument() { return {}; } +QList AsCompletion::parseDocument() { + auto editor = qobject_cast(widget()); + if (editor == nullptr) { + return {}; + } + + auto code = editor->toPlainText(); + + // first preprocess the code + AsPreprocesser prepc(_engine); + // TODO: set include callback + // prepc.setIncludeCallback(); + + auto r = prepc.loadSectionFromMemory(QStringLiteral("ASCOMPLETION"), + code.toUtf8()); + if (r <= 0) { + return {}; + } + + auto data = prepc.scriptData(); + QList ret; + + for (auto &d : data) { + QAsCodeParser parser(_engine); + auto syms = + parser.parseAndIntell(editor->textCursor().position(), d.script); + + for (auto &sym : syms) { + CodeInfoTip tip; + tip.name = sym.name; + tip.nameSpace = QString::fromUtf8(sym.scope.join("::")); + + switch (sym.symtype) { + case QAsCodeParser::SymbolType::Function: + tip.type = CodeInfoTip::Type::Function; + tip.addinfo.insert(CodeInfoTip::RetType, + QString::fromUtf8(sym.type)); + tip.addinfo.insert(CodeInfoTip::Args, + QString::fromUtf8(sym.additonalInfo)); + break; + case QAsCodeParser::SymbolType::Enum: + tip.type = CodeInfoTip::Type::Enum; + break; + case QAsCodeParser::SymbolType::Variable: + case QAsCodeParser::SymbolType::Class: + case QAsCodeParser::SymbolType::TypeDef: + case QAsCodeParser::SymbolType::FnDef: + case QAsCodeParser::SymbolType::VarsDecl: + case QAsCodeParser::SymbolType::Invalid: + continue; + } + + ret.append(tip); + } + } + + return ret; +} bool AsCompletion::eventFilter(QObject *watched, QEvent *event) { if (event->type() == QEvent::KeyPress) { diff --git a/src/class/asconsolecompletion.cpp b/src/class/asconsolecompletion.cpp index 639a602..a5386e8 100644 --- a/src/class/asconsolecompletion.cpp +++ b/src/class/asconsolecompletion.cpp @@ -1,12 +1,26 @@ +/*============================================================================== +** Copyright (C) 2024-2027 WingSummer +** +** This program is free software: you can redistribute it and/or modify it under +** the terms of the GNU Affero General Public License as published by the Free +** Software Foundation, version 3. +** +** This program is distributed in the hope that it will be useful, but WITHOUT +** ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +** FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more +** details. +** +** You should have received a copy of the GNU Affero General Public License +** along with this program. If not, see . +** ============================================================================= +*/ + #include "asconsolecompletion.h" #include "control/scriptingconsole.h" AsConsoleCompletion::AsConsoleCompletion(asIScriptEngine *engine, ScriptingConsole *p) - : AsCompletion(engine, p), _console(p) {} - -QList AsConsoleCompletion::parseDocument() { - // TODO - return {}; + : AsCompletion(engine, p), _console(p) { + setParseDocument(false); } diff --git a/src/class/asconsolecompletion.h b/src/class/asconsolecompletion.h index 53ccda1..7f7caf5 100644 --- a/src/class/asconsolecompletion.h +++ b/src/class/asconsolecompletion.h @@ -1,3 +1,20 @@ +/*============================================================================== +** Copyright (C) 2024-2027 WingSummer +** +** This program is free software: you can redistribute it and/or modify it under +** the terms of the GNU Affero General Public License as published by the Free +** Software Foundation, version 3. +** +** This program is distributed in the hope that it will be useful, but WITHOUT +** ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +** FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more +** details. +** +** You should have received a copy of the GNU Affero General Public License +** along with this program. If not, see . +** ============================================================================= +*/ + #ifndef ASCONSOLECOMPLETION_H #define ASCONSOLECOMPLETION_H @@ -11,10 +28,6 @@ public: explicit AsConsoleCompletion(asIScriptEngine *engine, ScriptingConsole *p); virtual ~AsConsoleCompletion() = default; - // AsCompletion interface -protected: - virtual QList parseDocument() override; - private: ScriptingConsole *_console; }; diff --git a/src/class/aspreprocesser.cpp b/src/class/aspreprocesser.cpp index 9d75f90..62f49cc 100644 --- a/src/class/aspreprocesser.cpp +++ b/src/class/aspreprocesser.cpp @@ -41,14 +41,14 @@ AsPreprocesser::AsPreprocesser(asIScriptEngine *engine) : engine(engine) { AsPreprocesser::~AsPreprocesser() { void ClearAll(); } -int AsPreprocesser::AddSectionFromFile(const QString &filename) { +int AsPreprocesser::loadSectionFromFile(const QString &filename) { // The file name stored in the set should be the fully resolved name because // it is possible to name the same file in multiple ways using relative // paths. auto fullpath = QFileInfo(filename).absoluteFilePath(); - if (IncludeIfNotAlreadyIncluded(fullpath)) { - int r = LoadScriptSection(fullpath); + if (includeIfNotAlreadyIncluded(fullpath)) { + int r = loadScriptSection(fullpath); if (r < 0) return r; else @@ -58,55 +58,57 @@ int AsPreprocesser::AddSectionFromFile(const QString &filename) { return 0; } -QList AsPreprocesser::GetScriptData() const { +int AsPreprocesser::loadSectionFromMemory(const QString §ion, + const QByteArray &code) { + int r = processScriptSection(code, section); + if (r < 0) + return r; + else + return 1; +} + +QList AsPreprocesser::scriptData() const { return modifiedScripts; } -asIScriptEngine *AsPreprocesser::GetEngine() { return engine; } +asIScriptEngine *AsPreprocesser::getEngine() { return engine; } -void AsPreprocesser::SetIncludeCallback(INCLUDECALLBACK_t callback, +void AsPreprocesser::setIncludeCallback(INCLUDECALLBACK_t callback, void *userParam) { includeCallback = callback; includeParam = userParam; } -void AsPreprocesser::SetPragmaCallback(PRAGMACALLBACK_t callback, +void AsPreprocesser::setPragmaCallback(PRAGMACALLBACK_t callback, void *userParam) { pragmaCallback = callback; pragmaParam = userParam; } -void AsPreprocesser::DefineWord(const QString &word) { +void AsPreprocesser::defineWord(const QString &word) { if (!definedWords.contains(word)) { definedWords.append(word); } } -unsigned int AsPreprocesser::GetSectionCount() const { +unsigned int AsPreprocesser::sectionCount() const { return (unsigned int)(includedScripts.size()); } -QString AsPreprocesser::GetSectionName(unsigned int idx) const { +QString AsPreprocesser::sectionName(unsigned int idx) const { if (qsizetype(idx) >= qsizetype(includedScripts.size())) return {}; return includedScripts.at(idx); } -void AsPreprocesser::ClearAll() { includedScripts.clear(); } +void AsPreprocesser::clearAll() { includedScripts.clear(); } -int AsPreprocesser::ProcessScriptSection(const QByteArray &script, int length, - const QString §ionname, - int lineOffset) { +int AsPreprocesser::processScriptSection(const QByteArray &script, + const QString §ionname) { QVector> includes; - QByteArray modifiedScript; - - // Perform a superficial parsing of the script first to store the metadata - if (length) - modifiedScript = script.left(length); - else - modifiedScript = script; + QByteArray modifiedScript = script; // First perform the checks for #if directives to exclude code that // shouldn't be compiled @@ -144,13 +146,13 @@ int AsPreprocesser::ProcessScriptSection(const QByteArray &script, int length, // Overwrite the #if directive with space characters to // avoid compiler error pos += len; - OverwriteCode(modifiedScript, start, pos - start); + overwriteCode(modifiedScript, start, pos - start); // Has this identifier been defined by the application or // not? if (!definedWords.contains(word)) { // Exclude all the code until and including the #endif - pos = ExcludeCode(modifiedScript, pos); + pos = excludeCode(modifiedScript, pos); } else { nested++; } @@ -158,7 +160,7 @@ int AsPreprocesser::ProcessScriptSection(const QByteArray &script, int length, } else if (token == "endif") { // Only remove the #endif if there was a matching #if if (nested > 0) { - OverwriteCode(modifiedScript, start, pos - start); + overwriteCode(modifiedScript, start, pos - start); nested--; } } @@ -231,7 +233,7 @@ int AsPreprocesser::ProcessScriptSection(const QByteArray &script, int length, // Overwrite the include directive with space // characters to avoid compiler error - OverwriteCode(modifiedScript, start, pos - start); + overwriteCode(modifiedScript, start, pos - start); } } @@ -279,7 +281,7 @@ int AsPreprocesser::ProcessScriptSection(const QByteArray &script, int length, // Overwrite the include directive with // space characters to avoid compiler error - OverwriteCode(modifiedScript, start, + overwriteCode(modifiedScript, start, pos - start); } } else { @@ -305,7 +307,7 @@ int AsPreprocesser::ProcessScriptSection(const QByteArray &script, int length, // Overwrite the pragma directive with space characters // to avoid compiler error - OverwriteCode(modifiedScript, start, pos - start); + overwriteCode(modifiedScript, start, pos - start); int r = pragmaCallback ? pragmaCallback(pragmaText, this, sectionname, @@ -324,14 +326,14 @@ int AsPreprocesser::ProcessScriptSection(const QByteArray &script, int length, // Don't search for includes within statement blocks or // between tokens in statements else { - pos = SkipStatement(modifiedScript, pos); + pos = skipStatement(modifiedScript, pos); } } // Build the actual script engine->SetEngineProperty(asEP_COPY_SCRIPT_SECTIONS, true); - AddScriptSection(sectionname, modifiedScript, lineOffset); + addScriptSection(sectionname, modifiedScript); if (includes.size() > 0) { // If the callback has been set, then call it for each included file @@ -362,7 +364,7 @@ int AsPreprocesser::ProcessScriptSection(const QByteArray &script, int length, } // Include the script section - int r = AddSectionFromFile(includes[n].first); + int r = loadSectionFromFile(includes[n].first); if (r < 0) return r; } @@ -372,7 +374,7 @@ int AsPreprocesser::ProcessScriptSection(const QByteArray &script, int length, return 0; } -int AsPreprocesser::LoadScriptSection(const QString &filename) { +int AsPreprocesser::loadScriptSection(const QString &filename) { // Open the script file QFile f(filename); @@ -396,10 +398,10 @@ int AsPreprocesser::LoadScriptSection(const QString &filename) { // Process the script section even if it is zero length so that the name is // registered - return ProcessScriptSection(code, code.length(), filename, 0); + return processScriptSection(code, filename); } -bool AsPreprocesser::IncludeIfNotAlreadyIncluded(const QString &filename) { +bool AsPreprocesser::includeIfNotAlreadyIncluded(const QString &filename) { if (includedScripts.contains(filename)) { // Already included return false; @@ -410,7 +412,7 @@ bool AsPreprocesser::IncludeIfNotAlreadyIncluded(const QString &filename) { return true; } -int AsPreprocesser::SkipStatement(const QByteArray &modifiedScript, int pos) { +int AsPreprocesser::skipStatement(const QByteArray &modifiedScript, int pos) { asUINT len = 0; // Skip until ; or { whichever comes first @@ -445,7 +447,7 @@ int AsPreprocesser::SkipStatement(const QByteArray &modifiedScript, int pos) { return pos; } -int AsPreprocesser::ExcludeCode(QByteArray &modifiedScript, int pos) { +int AsPreprocesser::excludeCode(QByteArray &modifiedScript, int pos) { asUINT len = 0; int nested = 0; while (pos < (int)modifiedScript.size()) { @@ -459,7 +461,7 @@ int AsPreprocesser::ExcludeCode(QByteArray &modifiedScript, int pos) { engine->ParseToken(modifiedScript.data() + pos, modifiedScript.size() - pos, &len); QString token = modifiedScript.mid(pos, len); - OverwriteCode(modifiedScript, pos, len); + overwriteCode(modifiedScript, pos, len); if (token == "if") { nested++; @@ -470,7 +472,7 @@ int AsPreprocesser::ExcludeCode(QByteArray &modifiedScript, int pos) { } } } else if (modifiedScript[pos] != '\n') { - OverwriteCode(modifiedScript, pos, len); + overwriteCode(modifiedScript, pos, len); } pos += len; } @@ -478,7 +480,7 @@ int AsPreprocesser::ExcludeCode(QByteArray &modifiedScript, int pos) { return pos; } -void AsPreprocesser::OverwriteCode(QByteArray &modifiedScript, int start, +void AsPreprocesser::overwriteCode(QByteArray &modifiedScript, int start, int len) { auto code = modifiedScript.data() + start; for (int n = 0; n < len; n++) { @@ -488,11 +490,10 @@ void AsPreprocesser::OverwriteCode(QByteArray &modifiedScript, int start, } } -void AsPreprocesser::AddScriptSection(const QString §ion, - const QByteArray &code, int lineOffset) { +void AsPreprocesser::addScriptSection(const QString §ion, + const QByteArray &code) { ScriptData data; data.section = section; - data.lineOffset = lineOffset; data.script = code; modifiedScripts.append(data); } diff --git a/src/class/aspreprocesser.h b/src/class/aspreprocesser.h index 3681cf4..d5e856d 100644 --- a/src/class/aspreprocesser.h +++ b/src/class/aspreprocesser.h @@ -70,7 +70,6 @@ public: public: struct ScriptData { QString section; - int lineOffset = -1; QByteArray script; }; @@ -79,41 +78,40 @@ public: // Returns 1 if the file was included // 0 if the file had already been included before // <0 on error - int AddSectionFromFile(const QString &filename); + int loadSectionFromFile(const QString &filename); + int loadSectionFromMemory(const QString §ion, const QByteArray &code); - QList GetScriptData() const; + QList scriptData() const; // Returns the engine - asIScriptEngine *GetEngine(); + asIScriptEngine *getEngine(); // Register the callback for resolving include directive - void SetIncludeCallback(INCLUDECALLBACK_t callback, void *userParam); + void setIncludeCallback(INCLUDECALLBACK_t callback, void *userParam); // Register the callback for resolving pragma directive - void SetPragmaCallback(PRAGMACALLBACK_t callback, void *userParam); + void setPragmaCallback(PRAGMACALLBACK_t callback, void *userParam); // Add a pre-processor define for conditional compilation - void DefineWord(const QString &word); + void defineWord(const QString &word); // Enumerate included script sections - unsigned int GetSectionCount() const; + unsigned int sectionCount() const; - QString GetSectionName(unsigned int idx) const; + QString sectionName(unsigned int idx) const; protected: - void ClearAll(); - int ProcessScriptSection(const QByteArray &script, int length, - const QString §ionname, int lineOffset); - int LoadScriptSection(const QString &filename); - bool IncludeIfNotAlreadyIncluded(const QString &filename); + void clearAll(); + void addScriptSection(const QString §ion, const QByteArray &code); + int processScriptSection(const QByteArray &script, + const QString §ionname); + int loadScriptSection(const QString &filename); + bool includeIfNotAlreadyIncluded(const QString &filename); - int SkipStatement(const QByteArray &modifiedScript, int pos); + int skipStatement(const QByteArray &modifiedScript, int pos); - int ExcludeCode(QByteArray &modifiedScript, int pos); - void OverwriteCode(QByteArray &modifiedScript, int start, int len); - - void AddScriptSection(const QString §ion, const QByteArray &code, - int lineOffset); + int excludeCode(QByteArray &modifiedScript, int pos); + void overwriteCode(QByteArray &modifiedScript, int start, int len); asIScriptEngine *engine; QList modifiedScripts; diff --git a/src/class/qascodeparser.cpp b/src/class/qascodeparser.cpp index 5cd2365..c35bacc 100644 --- a/src/class/qascodeparser.cpp +++ b/src/class/qascodeparser.cpp @@ -20,6 +20,13 @@ #include "AngelScript/sdk/angelscript/source/as_scriptengine.h" #include "AngelScript/sdk/angelscript/source/as_tokenizer.h" +/* Some information about AngelScript and this class: + * * This class is designed to get variables and functions symbol. + * * Strings are also included. + * * AngelScript's class and enum can not be nested unlike C++. + * * We only support class / mixin class / interface / function / enum. + */ + QAsCodeParser::QAsCodeParser(asCScriptEngine *engine) : engine(engine) { Q_ASSERT(engine); checkValidTypes = false; @@ -35,69 +42,58 @@ QAsCodeParser::QAsCodeParser(asIScriptEngine *engine) { QAsCodeParser::~QAsCodeParser() {} -QAsCodeParser::SymbolTable QAsCodeParser::parse(const QByteArray &codes) { - Reset(); +QList +QAsCodeParser::parse(const QByteArray &codes) { + reset(); code = codes; - ParseScript(false); + return parseScript(false); +} - SymbolTable ret = _symtable; +QList +QAsCodeParser::parseAndIntell(qsizetype offset, const QByteArray &codes) { + return parseIntell(offset, parse(codes)); +} - if (!m_segs.isEmpty()) { - // only add function signature as symbol - // you can extend it with more features - // PRS are welcomed. - for (auto p = m_segs.constKeyValueBegin(); - p != m_segs.constKeyValueEnd(); ++p) { - auto v = p->second; +QList +QAsCodeParser::parseIntell(qsizetype offset, + const QList &segs) { - Symbol fn; - fn.type = SymbolType::Function; - fn.name = v.name; - fn.nameInSrc = v.nameInSrc; - fn.content = v.args; - // fn.ns = v.ns; - fn.typeStr = v.ret; - ret.insert(p->first, fn); + QList ret; + + // first: global entries + for (auto &seg : segs) { + Symbol sym; + sym.symtype = seg.type; + sym.scope = seg.scope; + sym.offset = seg.offset; + sym.name = seg.name; + + switch (seg.type) { + case SymbolType::Function: { + sym.type = seg.additonalInfos.at(0); + sym.additonalInfo = seg.additonalInfos.at(1); + sym.name = seg.name; + } break; + case SymbolType::Enum: + break; + case SymbolType::Variable: + case SymbolType::Class: + case SymbolType::TypeDef: + case SymbolType::FnDef: + case SymbolType::VarsDecl: + case SymbolType::Invalid: + continue; } + + ret.append(sym); } + // TODO: deep parsing with offset + return ret; } -QAsCodeParser::SymbolTable QAsCodeParser::parseIntell(qsizetype offset, - const QByteArray &codes) { - parse(codes); - // then we will parse the symbols we want - - SymbolTable ret; - auto pend = _symtable.lowerBound(offset); - for (auto p = _symtable.begin(); p != pend; p++) { - ret.insert(p.key(), p.value()); - } - - if (!m_segs.isEmpty()) { - // only add function signature as symbol - // you can extend it with more features - // PRS are welcomed. - auto pend = m_segs.lowerBound(offset); - for (auto p = m_segs.begin(); p != pend; ++p) { - auto v = p.value(); - - Symbol fn; - fn.type = SymbolType::Function; - fn.name = v.name; - fn.nameInSrc = v.nameInSrc; - fn.content = v.args; - // fn.ns = v.ns; - fn.typeStr = v.ret; - ret.insert(p.key(), fn); - } - } - - return _symtable; -} - -void QAsCodeParser::Reset() { +void QAsCodeParser::reset() { errorWhileParsing = false; isSyntaxError = false; checkValidTypes = false; @@ -108,7 +104,7 @@ void QAsCodeParser::Reset() { lastToken.pos = size_t(-1); } -void QAsCodeParser::GetToken(sToken *token) { +void QAsCodeParser::getToken(sToken *token) { // Check if the token has already been parsed if (lastToken.pos == sourcePos) { *token = lastToken; @@ -116,7 +112,7 @@ void QAsCodeParser::GetToken(sToken *token) { if (token->type == ttWhiteSpace || token->type == ttOnelineComment || token->type == ttMultilineComment) - GetToken(token); + getToken(token); return; } @@ -142,7 +138,7 @@ void QAsCodeParser::GetToken(sToken *token) { token->type == ttMultilineComment); } -void QAsCodeParser::RewindTo(const sToken *token) { +void QAsCodeParser::rewindTo(const sToken *token) { // TODO: optimize: Perhaps we can optimize this further by having the parser // set an explicit return point, after which each token will // be stored. That way not just one token will be reused but @@ -159,15 +155,15 @@ void QAsCodeParser::SetPos(size_t pos) { sourcePos = pos; } -void QAsCodeParser::RewindErrorTo(sToken *token) { - RewindTo(token); +void QAsCodeParser::rewindErrorTo(sToken *token) { + rewindTo(token); isSyntaxError = true; errorWhileParsing = true; } -QAsCodeParser::Symbol QAsCodeParser::ParseFunctionDefinition() { - auto ret = ParseType(true); +QAsCodeParser::Symbol QAsCodeParser::parseFunctionDefinition() { + auto ret = parseType(true); if (isSyntaxError) return {}; @@ -177,48 +173,48 @@ QAsCodeParser::Symbol QAsCodeParser::ParseFunctionDefinition() { auto ns = ParseOptionalScope(); - auto id = ParseIdentifier(); + auto id = parseIdentifier(); if (isSyntaxError) return {}; - auto params = ParseParameterList(); + auto params = parseParameterListContent(); if (isSyntaxError) return {}; // ok, add symbol Symbol se; - se.type = SymbolType::FnDecl; - se.typeStr = getSymbolString(id); - se.name = getSymbolString(id); - se.nameInSrc = id.pos; - se.content = params; + // se.type = SymbolType::FnDecl; + // se.typeStr = getSymbolString(id); + // se.name = getSymbolString(id); + // se.nameInSrc = id.pos; + // se.content = params; // se.ns = getRealNamespace(ns); // Parse an optional 'const' after the function definition (used for // object methods) sToken t1; - GetToken(&t1); - RewindTo(&t1); + getToken(&t1); + rewindTo(&t1); if (t1.type == ttConst) - ParseToken(ttConst); + parseToken(ttConst); // Parse optional attributes - ParseMethodAttributes(); + parseMethodAttributes(); return se; } -QList QAsCodeParser::ParseParameterList() { +QList QAsCodeParser::parseParameterListContent() { QList ret; sToken t1; - GetToken(&t1); + getToken(&t1); if (t1.type != ttOpenParenthesis) { - RewindErrorTo(&t1); + rewindErrorTo(&t1); return ret; } - GetToken(&t1); + getToken(&t1); if (t1.type == ttCloseParenthesis) { // Statement block is finished return ret; @@ -227,17 +223,17 @@ QList QAsCodeParser::ParseParameterList() { // ignored if (t1.type == ttVoid) { sToken t2; - GetToken(&t2); + getToken(&t2); if (t2.type == ttCloseParenthesis) { return ret; } } - RewindTo(&t1); + rewindTo(&t1); for (;;) { // Parse data type - auto t = ParseType(true, isParsingAppInterface); + auto t = parseType(true, isParsingAppInterface); if (isSyntaxError) return ret; @@ -246,21 +242,21 @@ QList QAsCodeParser::ParseParameterList() { return ret; // Parse optional identifier - GetToken(&t1); + getToken(&t1); if (t1.type == ttIdentifier) { - RewindTo(&t1); + rewindTo(&t1); - auto iden = ParseIdentifier(); + auto iden = parseIdentifier(); Symbol se; se.name = getSymbolString(iden); - se.type = SymbolType::Variable; - se.typeStr = getSymbolString(t); + // se.type = SymbolType::Variable; + // se.typeStr = getSymbolString(t); ret.append(se); if (isSyntaxError) return ret; - GetToken(&t1); + getToken(&t1); } // Parse optional expression for the default arg @@ -268,11 +264,11 @@ QList QAsCodeParser::ParseParameterList() { // Do a superficial parsing of the default argument // The actual parsing will be done when the argument is compiled // for a function call - SuperficiallyParseExpression(); + superficiallyParseExpression(); if (isSyntaxError) return ret; - GetToken(&t1); + getToken(&t1); } // Check if list continues @@ -281,7 +277,7 @@ QList QAsCodeParser::ParseParameterList() { } else if (t1.type == ttListSeparator) continue; else { - RewindErrorTo(&t1); + rewindErrorTo(&t1); return ret; } } @@ -289,38 +285,38 @@ QList QAsCodeParser::ParseParameterList() { UNREACHABLE_RETURN; } -void QAsCodeParser::SuperficiallyParseExpression() { +void QAsCodeParser::superficiallyParseExpression() { // Simply parse everything until the first , or ), whichever comes first. // Keeping in mind that () and {} can group expressions. sToken start; - GetToken(&start); - RewindTo(&start); + getToken(&start); + rewindTo(&start); asCString stack; sToken t; for (;;) { - GetToken(&t); + getToken(&t); if (t.type == ttOpenParenthesis) stack += "("; else if (t.type == ttCloseParenthesis) { if (stack == "") { // Expression has ended. This token is not part of expression - RewindTo(&t); + rewindTo(&t); break; } else if (stack[stack.GetLength() - 1] == '(') { // Group has ended stack.SetLength(stack.GetLength() - 1); } else { // Wrong syntax - RewindTo(&t); - RewindErrorTo(&t); + rewindTo(&t); + rewindErrorTo(&t); return; } } else if (t.type == ttListSeparator) { if (stack == "") { // Expression has ended. This token is not part of expression - RewindTo(&t); + rewindTo(&t); break; } } else if (t.type == ttStartStatementBlock) @@ -328,7 +324,7 @@ void QAsCodeParser::SuperficiallyParseExpression() { else if (t.type == ttEndStatementBlock) { if (stack == "" || stack[stack.GetLength() - 1] != '{') { // Wrong syntax - RewindErrorTo(&t); + rewindErrorTo(&t); return; } else { // Group has ended @@ -336,14 +332,14 @@ void QAsCodeParser::SuperficiallyParseExpression() { } } else if (t.type == ttEndStatement) { // Wrong syntax (since we're parsing a default arg expression) - RewindErrorTo(&t); + rewindErrorTo(&t); return; } else if (t.type == ttNonTerminatedStringConstant) { - RewindErrorTo(&t); + rewindErrorTo(&t); return; } else if (t.type == ttEnd) { // Wrong syntax - RewindErrorTo(&start); + rewindErrorTo(&start); return; } @@ -351,15 +347,15 @@ void QAsCodeParser::SuperficiallyParseExpression() { } } -sToken QAsCodeParser::ParseType(bool allowConst, bool allowVariableType, +sToken QAsCodeParser::parseType(bool allowConst, bool allowVariableType, bool allowAuto) { sToken t; if (allowConst) { - GetToken(&t); - RewindTo(&t); + getToken(&t); + rewindTo(&t); if (t.type == ttConst) { - ParseToken(ttConst); + parseToken(ttConst); if (isSyntaxError) return t; } @@ -369,51 +365,51 @@ sToken QAsCodeParser::ParseType(bool allowConst, bool allowVariableType, ParseOptionalScope(); // Parse the actual type - auto dt = ParseDataType(allowVariableType, allowAuto); + auto dt = parseDataType(allowVariableType, allowAuto); if (isSyntaxError) return t; // If the datatype is a template type, then parse the subtype within the < > - GetToken(&t); - RewindTo(&t); + getToken(&t); + rewindTo(&t); tempString = getSymbolString(dt); if (engine->IsTemplateType(tempString) && t.type == ttLessThan) { - ParseTemplTypeList(); + parseTemplTypeList(); if (isSyntaxError) return t; } // Parse [] and @ - GetToken(&t); - RewindTo(&t); + getToken(&t); + rewindTo(&t); while (t.type == ttOpenBracket || t.type == ttHandle) { if (t.type == ttOpenBracket) { - ParseToken(ttOpenBracket); + parseToken(ttOpenBracket); if (isSyntaxError) return t; - GetToken(&t); + getToken(&t); if (t.type != ttCloseBracket) { - RewindErrorTo(&t); + rewindErrorTo(&t); return t; } } else { - ParseToken(ttHandle); + parseToken(ttHandle); if (isSyntaxError) return t; - GetToken(&t); - RewindTo(&t); + getToken(&t); + rewindTo(&t); if (t.type == ttConst) { - ParseToken(ttConst); + parseToken(ttConst); if (isSyntaxError) return t; } } - GetToken(&t); - RewindTo(&t); + getToken(&t); + rewindTo(&t); } return dt; @@ -423,38 +419,38 @@ void QAsCodeParser::ParseTypeMod(bool isParam) { sToken t; // Parse possible & token - GetToken(&t); - RewindTo(&t); + getToken(&t); + rewindTo(&t); if (t.type == ttAmp) { - ParseToken(ttAmp); + parseToken(ttAmp); if (isSyntaxError) return; if (isParam) { - GetToken(&t); - RewindTo(&t); + getToken(&t); + rewindTo(&t); if (t.type == ttIn || t.type == ttOut || t.type == ttInOut) { int tokens[3] = {ttIn, ttOut, ttInOut}; - ParseOneOf(tokens, 3); + parseOneOf(tokens, 3); } } } // Parse possible + token - GetToken(&t); - RewindTo(&t); + getToken(&t); + rewindTo(&t); if (t.type == ttPlus) { - ParseToken(ttPlus); + parseToken(ttPlus); if (isSyntaxError) return; } // Parse possible if_handle_then_const token - GetToken(&t); - RewindTo(&t); - if (IdentifierIs(t, IF_HANDLE_TOKEN)) { - ParseToken(ttIdentifier); + getToken(&t); + rewindTo(&t); + if (identifierIs(t, IF_HANDLE_TOKEN)) { + parseToken(ttIdentifier); if (isSyntaxError) return; } @@ -464,31 +460,31 @@ QByteArrayList QAsCodeParser::ParseOptionalScope() { QByteArrayList scopes; sToken t1, t2; - GetToken(&t1); - GetToken(&t2); + getToken(&t1); + getToken(&t2); if (t1.type == ttScope) { - RewindTo(&t1); - ParseToken(ttScope); - GetToken(&t1); - GetToken(&t2); + rewindTo(&t1); + parseToken(ttScope); + getToken(&t1); + getToken(&t2); } while (t1.type == ttIdentifier && t2.type == ttScope) { - RewindTo(&t1); - auto id = ParseIdentifier(); + rewindTo(&t1); + auto id = parseIdentifier(); scopes.append(getSymbolString(id)); - ParseToken(ttScope); - GetToken(&t1); - GetToken(&t2); + parseToken(ttScope); + getToken(&t1); + getToken(&t2); } // The innermost scope may be a template type if (t1.type == ttIdentifier && t2.type == ttLessThan) { tempString = getSymbolString(t1); if (engine->IsTemplateType(tempString)) { - RewindTo(&t1); - ParseIdentifier(); - if (ParseTemplTypeList(false)) { - GetToken(&t2); + rewindTo(&t1); + parseIdentifier(); + if (parseTemplTypeList(false)) { + getToken(&t2); if (t2.type == ttScope) { // Template type is part of the scope // Nothing more needs to be done @@ -497,7 +493,7 @@ QByteArrayList QAsCodeParser::ParseOptionalScope() { } else { // The template type is not part of the scope // Rewind to the template type and end the scope - RewindTo(&t1); + rewindTo(&t1); return scopes; } } @@ -505,47 +501,47 @@ QByteArrayList QAsCodeParser::ParseOptionalScope() { } // The identifier is not part of the scope - RewindTo(&t1); + rewindTo(&t1); return scopes; } -sToken QAsCodeParser::ParseRealType() { +sToken QAsCodeParser::parseRealType() { sToken t1; - GetToken(&t1); - if (!IsRealType(t1.type)) { - RewindErrorTo(&t1); + getToken(&t1); + if (!isRealType(t1.type)) { + rewindErrorTo(&t1); } return t1; } -sToken QAsCodeParser::ParseDataType(bool allowVariableType, bool allowAuto) { +sToken QAsCodeParser::parseDataType(bool allowVariableType, bool allowAuto) { sToken t1; - GetToken(&t1); - if (!IsDataType(t1) && !(allowVariableType && t1.type == ttQuestion) && + getToken(&t1); + if (!isDataType(t1) && !(allowVariableType && t1.type == ttQuestion) && !(allowAuto && t1.type == ttAuto)) { - RewindErrorTo(&t1); + rewindErrorTo(&t1); return t1; } return t1; } -sToken QAsCodeParser::ParseIdentifier() { +sToken QAsCodeParser::parseIdentifier() { sToken t1; - GetToken(&t1); + getToken(&t1); if (t1.type != ttIdentifier) { - RewindErrorTo(&t1); + rewindErrorTo(&t1); } return t1; } -bool QAsCodeParser::ParseTemplTypeList(bool required) { +bool QAsCodeParser::parseTemplTypeList(bool required) { sToken t; bool isValid = true; @@ -553,29 +549,29 @@ bool QAsCodeParser::ParseTemplTypeList(bool required) { // asCScriptNode *last = node->lastChild; // Starts with '<' - GetToken(&t); + getToken(&t); if (t.type != ttLessThan) { if (required) { - RewindErrorTo(&t); + rewindErrorTo(&t); } return false; } // At least one type // TODO: child funcdef: Make this work with !required - ParseType(true, false); + parseType(true, false); if (isSyntaxError) return false; - GetToken(&t); + getToken(&t); // Parse template types by list separator while (t.type == ttListSeparator) { // TODO: child funcdef: Make this work with !required - ParseType(true, false); + parseType(true, false); if (isSyntaxError) return false; - GetToken(&t); + getToken(&t); } // End with '>' @@ -583,7 +579,7 @@ bool QAsCodeParser::ParseTemplTypeList(bool required) { // only 1 character ahead (thus splitting the token in two). if (code[QString::size_type(t.pos)] != '>') { if (required) { - RewindErrorTo(&t); + rewindErrorTo(&t); } else isValid = false; } else { @@ -599,16 +595,16 @@ bool QAsCodeParser::ParseTemplTypeList(bool required) { return true; } -void QAsCodeParser::ParseMethodAttributes() { +void QAsCodeParser::parseMethodAttributes() { sToken t1; for (;;) { - GetToken(&t1); - RewindTo(&t1); + getToken(&t1); + rewindTo(&t1); - if (IdentifierIs(t1, FINAL_TOKEN) || IdentifierIs(t1, OVERRIDE_TOKEN) || - IdentifierIs(t1, EXPLICIT_TOKEN) || - IdentifierIs(t1, PROPERTY_TOKEN) || IdentifierIs(t1, DELETE_TOKEN)) + if (identifierIs(t1, FINAL_TOKEN) || identifierIs(t1, OVERRIDE_TOKEN) || + identifierIs(t1, EXPLICIT_TOKEN) || + identifierIs(t1, PROPERTY_TOKEN) || identifierIs(t1, DELETE_TOKEN)) ; else break; @@ -618,9 +614,9 @@ void QAsCodeParser::ParseMethodAttributes() { void QAsCodeParser::ParseListPattern() { sToken t1; - GetToken(&t1); + getToken(&t1); if (t1.type != ttStartStatementBlock) { - RewindErrorTo(&t1); + rewindErrorTo(&t1); return; } @@ -629,42 +625,42 @@ void QAsCodeParser::ParseListPattern() { bool isBeginning = true; bool afterType = false; while (!isSyntaxError) { - GetToken(&t1); + getToken(&t1); if (t1.type == ttEndStatementBlock) { if (!afterType) { - RewindErrorTo(&t1); + rewindErrorTo(&t1); } break; } else if (t1.type == ttStartStatementBlock) { if (afterType) { - RewindErrorTo(&t1); + rewindErrorTo(&t1); } - RewindTo(&t1); + rewindTo(&t1); ParseListPattern(); afterType = true; } else if (t1.type == ttIdentifier && - (IdentifierIs(t1, "repeat") || - IdentifierIs(t1, "repeat_same"))) { + (identifierIs(t1, "repeat") || + identifierIs(t1, "repeat_same"))) { if (!isBeginning) { - RewindErrorTo(&t1); + rewindErrorTo(&t1); } - RewindTo(&t1); - ParseIdentifier(); + rewindTo(&t1); + parseIdentifier(); } else if (t1.type == ttEnd) { - RewindErrorTo(&start); + rewindErrorTo(&start); break; } else if (t1.type == ttListSeparator) { if (!afterType) { - RewindErrorTo(&t1); + rewindErrorTo(&t1); } afterType = false; } else { if (afterType) { - RewindErrorTo(&t1); + rewindErrorTo(&t1); } - RewindTo(&t1); + rewindTo(&t1); // NOTE - ParseType(true, true); + parseType(true, true); afterType = true; } @@ -672,7 +668,7 @@ void QAsCodeParser::ParseListPattern() { } } -bool QAsCodeParser::IsRealType(int tokenType) { +bool QAsCodeParser::isRealType(int tokenType) { if (tokenType == ttVoid || tokenType == ttInt || tokenType == ttInt8 || tokenType == ttInt16 || tokenType == ttInt64 || tokenType == ttUInt || tokenType == ttUInt8 || tokenType == ttUInt16 || @@ -683,68 +679,262 @@ bool QAsCodeParser::IsRealType(int tokenType) { return false; } -bool QAsCodeParser::IsDataType(const sToken &token) { +bool QAsCodeParser::isDataType(const sToken &token) { if (token.type == ttIdentifier) { #ifndef AS_NO_COMPILER if (checkValidTypes) { // Check if this is an existing type, regardless of namespace tempString = getSymbolString(token); - if (!DoesTypeExist(tempString)) + if (!typeExist(tempString)) return false; } #endif return true; } - if (IsRealType(token.type)) + if (isRealType(token.type)) return true; return false; } -bool QAsCodeParser::IdentifierIs(const sToken &t, const char *str) { +bool QAsCodeParser::identifierIs(const sToken &t, const char *str) { if (t.type != ttIdentifier) return false; - return code.mid(t.pos, t.length) == QByteArray(str); + return code.sliced(t.pos, t.length) == QByteArray(str); } -void QAsCodeParser::SuperficiallyParseStatementBlock() { +sToken QAsCodeParser::superficiallyParseStatementBlock() { // This function will only superficially parse the statement block in order // to find the end of it sToken t1; - GetToken(&t1); + getToken(&t1); if (t1.type != ttStartStatementBlock) { - RewindErrorTo(&t1); - return; + rewindErrorTo(&t1); + return t1; } sToken start = t1; int level = 1; while (level > 0 && !isSyntaxError) { - GetToken(&t1); + getToken(&t1); if (t1.type == ttEndStatementBlock) level--; else if (t1.type == ttStartStatementBlock) level++; else if (t1.type == ttNonTerminatedStringConstant) { - RewindErrorTo(&t1); - break; + rewindErrorTo(&t1); + return t1; } else if (t1.type == ttEnd) { - RewindErrorTo(&start); - break; + rewindErrorTo(&start); + return start; } } + + return t1; } -sToken QAsCodeParser::SuperficiallyParseVarInit() { +QAsCodeParser::CodeSegment QAsCodeParser::parseFunction() { + CodeSegment seg; + + sToken t1; + getToken(&t1); + + // A global function can be marked as shared and external + while (t1.type == ttIdentifier) { + if (identifierIs(t1, SHARED_TOKEN) || + identifierIs(t1, EXTERNAL_TOKEN)) { + rewindTo(&t1); + parseIdentifier(); + if (isSyntaxError) + return seg; + } else + break; + + getToken(&t1); + } + + if (isSyntaxError) + return seg; + + // If it is a global function, or a method, except constructor and + // destructor, then the return type is parsed + sToken t2; + getToken(&t2); + rewindTo(&t1); + + QByteArray rettype; + + if (t1.type != ttBitNot && t2.type != ttOpenParenthesis) { + auto id = parseType(true); + if (isSyntaxError) + return seg; + rettype = getSymbolString(id); + + ParseTypeMod(false); + if (isSyntaxError) + return seg; + } else { + rewindErrorTo(&t1); + return seg; + } + + // the first is returning value type + seg.additonalInfos.append(rettype); + + auto iden = parseIdentifier(); + if (isSyntaxError) + return seg; + seg.name = getSymbolString(iden); + seg.offset = iden.pos; + + getToken(&t1); + if (t1.type != ttOpenParenthesis) { + rewindErrorTo(&t1); + return seg; + } + + getToken(&t1); + // the second is params raw string + if (t1.type == ttCloseParenthesis) { + // Statement block is finished + seg.additonalInfos.append(QByteArray()); + } else { + auto begin = t1.pos; + while (true) { + getToken(&t1); + if (t1.type == ttCloseParenthesis) { + break; + } + // just some easier way to dectect errors + switch (t1.type) { + case ttStartStatementBlock: + case ttEndStatementBlock: + case ttEndStatement: + case ttEnd: + rewindErrorTo(&t1); + return seg; + default: + break; + } + } + + auto end = t1.pos; + seg.additonalInfos.append(code.sliced(begin, end - begin)); + } + + // TODO: Should support abstract methods, in which case no statement block + // should be provided + parseMethodAttributes(); + if (isSyntaxError) + return seg; + + // External shared functions must be ended with ';' + getToken(&t1); + rewindTo(&t1); + + seg.scope = currentNs; + seg.type = SymbolType::Function; + + if (t1.type == ttEndStatement) { + parseToken(ttEndStatement); + return seg; + } + + auto begin = t1.pos; + // We should just find the end of the statement block here. + t1 = superficiallyParseStatementBlock(); + auto end = t1.pos; + seg.codes = code.sliced(begin, end - begin + 1); + return seg; +} + +QAsCodeParser::CodeSegment QAsCodeParser::parseFuncDef() { + CodeSegment seg; + sToken t1; + + // Allow keywords 'external' and 'shared' before 'interface' + getToken(&t1); + while (identifierIs(t1, SHARED_TOKEN) || identifierIs(t1, EXTERNAL_TOKEN)) { + rewindTo(&t1); + + if (isSyntaxError) + return seg; + + getToken(&t1); + } + + if (t1.type != ttFuncDef) { + rewindErrorTo(&t1); + return seg; + } + + auto begin = t1.pos; + skipCodeBlock(); + getToken(&t1); + auto end = t1.pos; + + // seg.name is empty + seg.scope = currentNs; + seg.offset = begin; + seg.type = SymbolType::FnDef; + seg.codes = code.sliced(begin, end - begin + 1); + return seg; +} + +QAsCodeParser::CodeSegment QAsCodeParser::parseInterface() { + CodeSegment seg; sToken t; - GetToken(&t); + + // Allow keywords 'external' and 'shared' before 'interface' + getToken(&t); + while (identifierIs(t, SHARED_TOKEN) || identifierIs(t, EXTERNAL_TOKEN)) { + rewindTo(&t); + parseIdentifier(); + + if (isSyntaxError) + return seg; + + getToken(&t); + } + + if (t.type != ttInterface) { + rewindErrorTo(&t); + return seg; + } + + auto id = parseIdentifier(); + seg.name = getSymbolString(id); + seg.offset = id.pos; + seg.scope = currentNs; + seg.type = SymbolType::Class; + + // External shared declarations are ended with ';' + getToken(&t); + if (t.type == ttEndStatement) { + rewindTo(&t); + parseToken(ttEndStatement); + return seg; + } + + auto begin = t.pos; + rewindTo(&t); + t = superficiallyParseStatementBlock(); + auto end = t.pos; + seg.codes = code.sliced(begin, end - begin + 1); + + return seg; +} + +sToken QAsCodeParser::superficiallyParseVarInit() { + sToken t; + getToken(&t); if (t.type == ttAssignment) { - GetToken(&t); + getToken(&t); sToken start = t; // Find the end of the expression @@ -762,50 +952,50 @@ sToken QAsCodeParser::SuperficiallyParseVarInit() { else if (t.type == ttEndStatementBlock) indentBrace--; else if (t.type == ttNonTerminatedStringConstant) { - RewindErrorTo(&t); + rewindErrorTo(&t); break; } else if (t.type == ttEnd) { - RewindErrorTo(&start); + rewindErrorTo(&start); break; } - GetToken(&t); + getToken(&t); } // Rewind so that the next token read is the list separator, end // statement, or end statement block - RewindTo(&t); + rewindTo(&t); } else if (t.type == ttOpenParenthesis) { sToken start = t; // Find the end of the argument list int indent = 1; while (indent) { - GetToken(&t); + getToken(&t); if (t.type == ttOpenParenthesis) indent++; else if (t.type == ttCloseParenthesis) indent--; else if (t.type == ttNonTerminatedStringConstant) { - RewindErrorTo(&t); + rewindErrorTo(&t); break; } else if (t.type == ttEnd) { - RewindErrorTo(&start); + rewindErrorTo(&start); break; } } } else { - RewindErrorTo(&t); + rewindErrorTo(&t); } return t; } -void QAsCodeParser::ParseStatementBlock() { +void QAsCodeParser::parseStatementBlock() { sToken t1; - GetToken(&t1); + getToken(&t1); if (t1.type != ttStartStatementBlock) { - RewindErrorTo(&t1); + rewindErrorTo(&t1); return; } @@ -813,28 +1003,28 @@ void QAsCodeParser::ParseStatementBlock() { for (;;) { while (!isSyntaxError) { - GetToken(&t1); + getToken(&t1); if (t1.type == ttEndStatementBlock) { // Statement block is finished return; } else { - RewindTo(&t1); + rewindTo(&t1); - if (IsVarDecl()) - ParseDeclaration(); + if (isVarDecl()) + parseDeclaration(); else - ParseStatement(); + parseStatement(); } } if (isSyntaxError) { // Search for either ';', '{', '}', or end - GetToken(&t1); + getToken(&t1); while (t1.type != ttEndStatement && t1.type != ttEnd && t1.type != ttStartStatementBlock && t1.type != ttEndStatementBlock) { - GetToken(&t1); + getToken(&t1); } // Skip this statement block @@ -842,7 +1032,7 @@ void QAsCodeParser::ParseStatementBlock() { // Find the end of the block and skip nested blocks int level = 1; while (level > 0) { - GetToken(&t1); + getToken(&t1); if (t1.type == ttStartStatementBlock) level++; if (t1.type == ttEndStatementBlock) @@ -851,9 +1041,9 @@ void QAsCodeParser::ParseStatementBlock() { break; } } else if (t1.type == ttEndStatementBlock) { - RewindTo(&t1); + rewindTo(&t1); } else if (t1.type == ttEnd) { - RewindErrorTo(&start); + rewindErrorTo(&start); return; } @@ -863,11 +1053,11 @@ void QAsCodeParser::ParseStatementBlock() { UNREACHABLE_RETURN; } -void QAsCodeParser::ParseStatement() { +void QAsCodeParser::parseStatement() { sToken t1; - GetToken(&t1); - RewindTo(&t1); + getToken(&t1); + rewindTo(&t1); if (t1.type == ttIf) ParseIf(); @@ -878,7 +1068,7 @@ void QAsCodeParser::ParseStatement() { else if (t1.type == ttReturn) ParseReturn(); else if (t1.type == ttStartStatementBlock) - ParseStatementBlock(); + parseStatementBlock(); else if (t1.type == ttBreak) ParseBreak(); else if (t1.type == ttContinue) @@ -890,8 +1080,8 @@ void QAsCodeParser::ParseStatement() { else if (t1.type == ttTry) ParseTryCatch(); else { - if (IsVarDecl()) { - RewindErrorTo(&t1); + if (isVarDecl()) { + rewindErrorTo(&t1); return; } ParseExpressionStatement(); @@ -900,35 +1090,35 @@ void QAsCodeParser::ParseStatement() { void QAsCodeParser::ParseExpressionStatement() { sToken t; - GetToken(&t); + getToken(&t); if (t.type == ttEndStatement) { return; } - RewindTo(&t); + rewindTo(&t); ParseAssignment(); if (isSyntaxError) return; - GetToken(&t); + getToken(&t); if (t.type != ttEndStatement) { - RewindErrorTo(&t); + rewindErrorTo(&t); return; } } void QAsCodeParser::ParseSwitch() { sToken t; - GetToken(&t); + getToken(&t); if (t.type != ttSwitch) { - RewindErrorTo(&t); + rewindErrorTo(&t); return; } - GetToken(&t); + getToken(&t); if (t.type != ttOpenParenthesis) { - RewindErrorTo(&t); + rewindErrorTo(&t); return; } @@ -936,28 +1126,28 @@ void QAsCodeParser::ParseSwitch() { if (isSyntaxError) return; - GetToken(&t); + getToken(&t); if (t.type != ttCloseParenthesis) { - RewindErrorTo(&t); + rewindErrorTo(&t); return; } - GetToken(&t); + getToken(&t); if (t.type != ttStartStatementBlock) { - RewindErrorTo(&t); + rewindErrorTo(&t); return; } while (!isSyntaxError) { - GetToken(&t); + getToken(&t); if (t.type == ttEndStatementBlock) break; - RewindTo(&t); + rewindTo(&t); if (t.type != ttCase && t.type != ttDefault) { - RewindErrorTo(&t); + rewindErrorTo(&t); return; } @@ -967,16 +1157,16 @@ void QAsCodeParser::ParseSwitch() { } if (t.type != ttEndStatementBlock) { - RewindErrorTo(&t); + rewindErrorTo(&t); return; } } void QAsCodeParser::ParseCase() { sToken t; - GetToken(&t); + getToken(&t); if (t.type != ttCase && t.type != ttDefault) { - RewindErrorTo(&t); + rewindErrorTo(&t); return; } @@ -984,28 +1174,28 @@ void QAsCodeParser::ParseCase() { ParseExpression(); } - GetToken(&t); + getToken(&t); if (t.type != ttColon) { - RewindErrorTo(&t); + rewindErrorTo(&t); return; } // Parse statements until we find either of }, case, default, and break - GetToken(&t); - RewindTo(&t); + getToken(&t); + rewindTo(&t); while (t.type != ttCase && t.type != ttDefault && t.type != ttEndStatementBlock && t.type != ttBreak) { - if (IsVarDecl()) + if (isVarDecl()) // Variable declarations are not allowed, but we parse it anyway to // give a good error message - ParseDeclaration(); + parseDeclaration(); else - ParseStatement(); + parseStatement(); if (isSyntaxError) return; - GetToken(&t); - RewindTo(&t); + getToken(&t); + rewindTo(&t); } // If the case was ended with a break statement, add it to the node @@ -1015,15 +1205,15 @@ void QAsCodeParser::ParseCase() { void QAsCodeParser::ParseIf() { sToken t; - GetToken(&t); + getToken(&t); if (t.type != ttIf) { - RewindErrorTo(&t); + rewindErrorTo(&t); return; } - GetToken(&t); + getToken(&t); if (t.type != ttOpenParenthesis) { - RewindErrorTo(&t); + rewindErrorTo(&t); return; } @@ -1031,43 +1221,43 @@ void QAsCodeParser::ParseIf() { if (isSyntaxError) return; - GetToken(&t); + getToken(&t); if (t.type != ttCloseParenthesis) { - RewindErrorTo(&t); + rewindErrorTo(&t); return; } - ParseStatement(); + parseStatement(); if (isSyntaxError) return; - GetToken(&t); + getToken(&t); if (t.type != ttElse) { // No else statement return already - RewindTo(&t); + rewindTo(&t); return; } - ParseStatement(); + parseStatement(); } void QAsCodeParser::ParseFor() { sToken t; - GetToken(&t); + getToken(&t); if (t.type != ttFor) { - RewindErrorTo(&t); + rewindErrorTo(&t); return; } - GetToken(&t); + getToken(&t); if (t.type != ttOpenParenthesis) { - RewindErrorTo(&t); + rewindErrorTo(&t); return; } - if (IsVarDecl()) - ParseDeclaration(); + if (isVarDecl()) + parseDeclaration(); else ParseExpressionStatement(); if (isSyntaxError) @@ -1077,9 +1267,9 @@ void QAsCodeParser::ParseFor() { if (isSyntaxError) return; - GetToken(&t); + getToken(&t); if (t.type != ttCloseParenthesis) { - RewindTo(&t); + rewindTo(&t); // Parse N increment statements separated by , for (;;) { @@ -1088,32 +1278,32 @@ void QAsCodeParser::ParseFor() { if (isSyntaxError) return; - GetToken(&t); + getToken(&t); if (t.type == ttListSeparator) continue; else if (t.type == ttCloseParenthesis) break; else { - RewindErrorTo(&t); + rewindErrorTo(&t); return; } } } - ParseStatement(); + parseStatement(); } void QAsCodeParser::ParseWhile() { sToken t; - GetToken(&t); + getToken(&t); if (t.type != ttWhile) { - RewindErrorTo(&t); + rewindErrorTo(&t); return; } - GetToken(&t); + getToken(&t); if (t.type != ttOpenParenthesis) { - RewindErrorTo(&t); + rewindErrorTo(&t); return; } @@ -1121,37 +1311,37 @@ void QAsCodeParser::ParseWhile() { if (isSyntaxError) return; - GetToken(&t); + getToken(&t); if (t.type != ttCloseParenthesis) { - RewindErrorTo(&t); + rewindErrorTo(&t); return; } - ParseStatement(); + parseStatement(); } void QAsCodeParser::ParseDoWhile() { sToken t; - GetToken(&t); + getToken(&t); if (t.type != ttDo) { - RewindErrorTo(&t); + rewindErrorTo(&t); return; } - ParseStatement(); + parseStatement(); if (isSyntaxError) return; - GetToken(&t); + getToken(&t); if (t.type != ttWhile) { - RewindErrorTo(&t); + rewindErrorTo(&t); return; } - GetToken(&t); + getToken(&t); if (t.type != ttOpenParenthesis) { - RewindErrorTo(&t); + rewindErrorTo(&t); return; } @@ -1159,57 +1349,57 @@ void QAsCodeParser::ParseDoWhile() { if (isSyntaxError) return; - GetToken(&t); + getToken(&t); if (t.type != ttCloseParenthesis) { - RewindErrorTo(&t); + rewindErrorTo(&t); return; } - GetToken(&t); + getToken(&t); if (t.type != ttEndStatement) { - RewindErrorTo(&t); + rewindErrorTo(&t); return; } } void QAsCodeParser::ParseReturn() { sToken t; - GetToken(&t); + getToken(&t); if (t.type != ttReturn) { - RewindErrorTo(&t); + rewindErrorTo(&t); return; } - GetToken(&t); + getToken(&t); if (t.type == ttEndStatement) { return; } - RewindTo(&t); + rewindTo(&t); ParseAssignment(); if (isSyntaxError) return; - GetToken(&t); + getToken(&t); if (t.type != ttEndStatement) { - RewindErrorTo(&t); + rewindErrorTo(&t); return; } } void QAsCodeParser::ParseBreak() { sToken t; - GetToken(&t); + getToken(&t); if (t.type != ttBreak) { - RewindErrorTo(&t); + rewindErrorTo(&t); return; } - GetToken(&t); + getToken(&t); if (t.type != ttEndStatement) { - RewindErrorTo(&t); + rewindErrorTo(&t); } return; @@ -1217,97 +1407,97 @@ void QAsCodeParser::ParseBreak() { void QAsCodeParser::ParseContinue() { sToken t; - GetToken(&t); + getToken(&t); if (t.type != ttContinue) { - RewindErrorTo(&t); + rewindErrorTo(&t); return; } - GetToken(&t); + getToken(&t); if (t.type != ttEndStatement) { - RewindErrorTo(&t); + rewindErrorTo(&t); } } void QAsCodeParser::ParseTryCatch() { sToken t; - GetToken(&t); + getToken(&t); if (t.type != ttTry) { - RewindErrorTo(&t); + rewindErrorTo(&t); return; } - ParseStatementBlock(); + parseStatementBlock(); if (isSyntaxError) return; - GetToken(&t); + getToken(&t); if (t.type != ttCatch) { - RewindErrorTo(&t); + rewindErrorTo(&t); return; } - ParseStatementBlock(); + parseStatementBlock(); if (isSyntaxError) return; } -QList QAsCodeParser::ParseDeclaration(bool isClassProp, +QList QAsCodeParser::parseDeclaration(bool isClassProp, bool isGlobalVar) { QList ret; Symbol sym; sToken t; - GetToken(&t); - RewindTo(&t); + getToken(&t); + rewindTo(&t); // A class property can be preceeded by private if (t.type == ttPrivate && isClassProp) { - ParseToken(ttPrivate); + parseToken(ttPrivate); sym.vis = Visiblity::Private; } else if (t.type == ttProtected && isClassProp) { - ParseToken(ttProtected); + parseToken(ttProtected); sym.vis = Visiblity::Protected; } // Parse data type - auto dt = ParseType(true, false, !isClassProp); + auto dt = parseType(true, false, !isClassProp); if (isSyntaxError) return ret; - sym.typeStr = getSymbolString(dt); + // sym.typeStr = getSymbolString(dt); for (;;) { // Parse identifier - auto id = ParseIdentifier(); + auto id = parseIdentifier(); if (isSyntaxError) return ret; sym.name = getSymbolString(id); - sym.nameInSrc = id.pos; + // sym.nameInSrc = id.pos; if (isClassProp || isGlobalVar) { // Only superficially parse the initialization RewindErrorTo for the // class property - GetToken(&t); - RewindTo(&t); + getToken(&t); + rewindTo(&t); if (t.type == ttAssignment || t.type == ttOpenParenthesis) { - SuperficiallyParseVarInit(); + superficiallyParseVarInit(); if (isSyntaxError) return ret; } } else { // If next token is assignment, parse expression - GetToken(&t); + getToken(&t); if (t.type == ttOpenParenthesis) { - RewindTo(&t); - ParseArgList(); + rewindTo(&t); + parseArgList(); if (isSyntaxError) return ret; } else if (t.type == ttAssignment) { - GetToken(&t); - RewindTo(&t); + getToken(&t); + rewindTo(&t); if (t.type == ttStartStatementBlock) { ParseInitList(); if (isSyntaxError) @@ -1318,164 +1508,134 @@ QList QAsCodeParser::ParseDeclaration(bool isClassProp, return ret; } } else - RewindTo(&t); + rewindTo(&t); } // continue if list separator, else terminate with end statement - GetToken(&t); + getToken(&t); if (t.type == ttListSeparator) { - sym.type = SymbolType::Variable; + // sym.type = SymbolType::Variable; ret.append(sym); continue; } else if (t.type == ttEndStatement) { - sym.type = SymbolType::Variable; + // sym.type = SymbolType::Variable; ret.append(sym); return ret; } else { - RewindErrorTo(&t); + rewindErrorTo(&t); return ret; } } UNREACHABLE_RETURN; } -QAsCodeParser::Symbol QAsCodeParser::ParseImport() { - sToken t; - GetToken(&t); - if (t.type != ttImport) { - RewindErrorTo(&t); - return {}; - } +QList QAsCodeParser::parseScript(bool inBlock) { + QList segs; - auto fn = ParseFunctionDefinition(); - if (isSyntaxError) - return {}; - - GetToken(&t); - if (t.type != ttIdentifier) { - RewindErrorTo(&t); - return {}; - } - - tempString = getSymbolString(t); - if (tempString != FROM_TOKEN) { - RewindErrorTo(&t); - return {}; - } - - GetToken(&t); - if (t.type != ttStringConstant) { - RewindErrorTo(&t); - return {}; - } - - GetToken(&t); - if (t.type != ttEndStatement) { - RewindErrorTo(&t); - return {}; - } - - fn.type = SymbolType::Import; - return fn; -} - -void QAsCodeParser::ParseScript(bool inBlock) { - // Determine type of node for (;;) { while (!isSyntaxError) { sToken tStart; - GetToken(&tStart); + getToken(&tStart); // Optimize by skipping tokens 'shared', 'external', 'final', // 'abstract' so they don't have to be checked in every condition sToken t1 = tStart; - while (IdentifierIs(t1, SHARED_TOKEN) || - IdentifierIs(t1, EXTERNAL_TOKEN) || - IdentifierIs(t1, FINAL_TOKEN) || - IdentifierIs(t1, ABSTRACT_TOKEN)) - GetToken(&t1); - RewindTo(&tStart); + while (identifierIs(t1, SHARED_TOKEN) || + identifierIs(t1, EXTERNAL_TOKEN) || + identifierIs(t1, FINAL_TOKEN) || + identifierIs(t1, ABSTRACT_TOKEN)) + getToken(&t1); + rewindTo(&tStart); if (t1.type == ttImport) { - auto import = ParseImport(); - _symtable.insert(import.nameInSrc, import); - } else if (t1.type == ttEnum) - ParseEnumeration(); // Handle enumerations - else if (t1.type == ttTypedef) - ParseTypedef(); // Handle primitive typedefs + // import we don't support just skip + skipCodeBlock(); + } else if (t1.type == ttEnum) // Handle enumerations + appendValidSeg(segs, parseEnumeration()); + else if (t1.type == ttTypedef) // Handle primitive typedefs + appendValidSeg(segs, parseTypedef()); else if (t1.type == ttClass) - ParseClass(); + appendValidSeg(segs, parseClass()); else if (t1.type == ttMixin) - ParseMixin(); + appendValidSeg(segs, parseMixin()); else if (t1.type == ttInterface) - ParseInterface(); + appendValidSeg(segs, parseInterface()); else if (t1.type == ttFuncDef) { - auto fndef = ParseFuncDef(); - if (fndef.isValid()) { - _symtable.insert(t1.pos, fndef); - } + appendValidSeg(segs, parseFuncDef()); } else if (t1.type == ttConst || t1.type == ttScope || - t1.type == ttAuto || IsDataType(t1)) { - if (IsVirtualPropertyDecl()) { - auto vpdl = ParseVirtualPropertyDecl(false, false); - if (vpdl.isValid()) { - _symtable.insert(vpdl.nameInSrc, vpdl); - } - } else if (IsVarDecl()) { - auto dl = ParseDeclaration(false, true); - for (auto &item : dl) { - if (item.isValid()) { - _symtable.insert(item.nameInSrc, item); - } - } + t1.type == ttAuto || isDataType(t1)) { + // class properties parsing now are in deep parsing, + // so there is no need to parse there + if (isVarDecl()) { + auto begin = t1.pos; + skipCodeBlock(); + getToken(&t1); + auto end = t1.pos; + + CodeSegment seg; + // seg.name is empty + seg.offset = begin; + seg.scope = currentNs; + seg.type = SymbolType::VarsDecl; + seg.codes = code.sliced(begin, end - begin + 1); + rewindTo(&t1); + + segs.append(seg); } else { - auto fn = ParseFunction(); - if (fn.isValid()) { - m_segs.insert(fn.nameInSrc, fn); - } + appendValidSeg(segs, parseFunction()); } } else if (t1.type == ttEndStatement) { // Ignore a semicolon by itself - GetToken(&t1); + getToken(&t1); } else if (t1.type == ttNamespace) - ParseNamespace(); + parseNamespace(); else if (t1.type == ttEnd) - return; + return segs; else if (inBlock && t1.type == ttEndStatementBlock) - return; + return segs; else { - RewindErrorTo(&t1); + rewindErrorTo(&t1); } } if (isSyntaxError) { - // Search for either ';' or '{' or end - sToken t1; - GetToken(&t1); - while (t1.type != ttEndStatement && t1.type != ttEnd && - t1.type != ttStartStatementBlock) - GetToken(&t1); - - if (t1.type == ttStartStatementBlock) { - // Find the end of the block and skip nested blocks - int level = 1; - while (level > 0) { - GetToken(&t1); - if (t1.type == ttStartStatementBlock) - level++; - if (t1.type == ttEndStatementBlock) - level--; - if (t1.type == ttEnd) - break; - } - } - + skipCodeBlock(); isSyntaxError = false; } } UNREACHABLE_RETURN; } +void QAsCodeParser::appendValidSeg(QList &container, + CodeSegment seg) { + if (seg.isValid()) { + container.append(seg); + } +} + +void QAsCodeParser::skipCodeBlock() { + // Search for either ';' or '{' or end + sToken t1; + getToken(&t1); + while (t1.type != ttEndStatement && t1.type != ttEnd && + t1.type != ttStartStatementBlock) + getToken(&t1); + + if (t1.type == ttStartStatementBlock) { + // Find the end of the block and skip nested blocks + int level = 1; + while (level > 0) { + getToken(&t1); + if (t1.type == ttStartStatementBlock) + level++; + if (t1.type == ttEndStatementBlock) + level--; + if (t1.type == ttEnd) + break; + } + } +} + QByteArray QAsCodeParser::getSymbolString(const sToken &t) { return QByteArray(code.data() + t.pos, t.length); } @@ -1488,78 +1648,219 @@ QByteArrayList QAsCodeParser::getRealNamespace(const QByteArrayList &ns) { // } } -void QAsCodeParser::ParseNamespace() { - sToken t1; +QAsCodeParser::CodeSegment QAsCodeParser::parseMixin() { + sToken t; + getToken(&t); - GetToken(&t1); - if (t1.type != ttNamespace) { - RewindErrorTo(&t1); + if (t.type != ttMixin) { + rewindErrorTo(&t); + return {}; } - ParseIdentifier(); + return parseClass(); +} + +QAsCodeParser::CodeSegment QAsCodeParser::parseClass() { + CodeSegment seg; + sToken t; + getToken(&t); + + // Allow the keywords 'shared', 'abstract', 'final', and 'external' before + // 'class' + while (identifierIs(t, SHARED_TOKEN) || identifierIs(t, ABSTRACT_TOKEN) || + identifierIs(t, FINAL_TOKEN) || identifierIs(t, EXTERNAL_TOKEN)) { + rewindTo(&t); + parseIdentifier(); + getToken(&t); + } + + if (t.type != ttClass) { + rewindErrorTo(&t); + return seg; + } + + if (engine->ep.allowImplicitHandleTypes) { + // Parse 'implicit handle class' construct + getToken(&t); + + if (t.type != ttHandle) + rewindTo(&t); + } + + auto cls = parseIdentifier(); + seg.name = getSymbolString(cls); + seg.offset = cls.pos; + seg.scope = currentNs; + seg.type = SymbolType::Class; + + // External shared declarations are ended with ';' + getToken(&t); + if (t.type == ttEndStatement) { + rewindTo(&t); + parseToken(ttEndStatement); + return seg; + } + + rewindTo(&t); + auto begin = t.pos; + t = superficiallyParseStatementBlock(); + auto end = t.pos; + seg.codes = code.sliced(begin, end - begin + 1); + return seg; +} + +QAsCodeParser::CodeSegment QAsCodeParser::parseTypedef() { + CodeSegment seg; + sToken token; + + getToken(&token); + if (token.type != ttTypedef) { + rewindErrorTo(&token); + return seg; + } + + auto begin = token.pos; + skipCodeBlock(); + getToken(&token); + auto end = token.pos; + + // seg.name is empty + seg.scope = currentNs; + seg.offset = begin; + seg.type = SymbolType::TypeDef; + seg.codes = code.sliced(begin, end - begin + 1); + return seg; +} + +QAsCodeParser::CodeSegment QAsCodeParser::parseEnumeration() { + CodeSegment seg; + sToken token; + + // Optional 'shared' and 'external' token + getToken(&token); + while (identifierIs(token, SHARED_TOKEN) || + identifierIs(token, EXTERNAL_TOKEN)) { + rewindTo(&token); + + parseIdentifier(); + + if (isSyntaxError) + return seg; + + getToken(&token); + } + + // Check for enum + if (token.type != ttEnum) { + rewindErrorTo(&token); + return seg; + } + + // Get the identifier + getToken(&token); + if (ttIdentifier != token.type) { + rewindErrorTo(&token); + return seg; + } + + seg.name = getSymbolString(token); + seg.scope = currentNs; + seg.offset = token.pos; + seg.type = SymbolType::Enum; + + // External shared declarations are ended with ';' + getToken(&token); + if (token.type == ttEndStatement) { + rewindTo(&token); + parseToken(ttEndStatement); + return seg; + } + + auto begin = token.pos; + rewindTo(&token); + token = superficiallyParseStatementBlock(); + auto end = token.pos; + seg.codes = code.sliced(begin, end - begin + 1); + return seg; +} + +void QAsCodeParser::parseNamespace() { + sToken t1; + QByteArrayList ns; + + getToken(&t1); + if (t1.type != ttNamespace) { + rewindErrorTo(&t1); + } + + auto id = parseIdentifier(); if (isSyntaxError) return; - GetToken(&t1); + ns.append(getSymbolString(id)); + + getToken(&t1); while (t1.type == ttScope) { - ParseIdentifier(); + auto id = parseIdentifier(); if (isSyntaxError) return; - GetToken(&t1); + ns.append(getSymbolString(id)); + getToken(&t1); } if (t1.type != ttStartStatementBlock) { - RewindErrorTo(&t1); + rewindErrorTo(&t1); return; } + currentNs = ns; sToken start = t1; - - ParseScript(true); + parseScript(true); + currentNs.clear(); if (!isSyntaxError) { - GetToken(&t1); + getToken(&t1); if (t1.type != ttEndStatementBlock) { - RewindErrorTo(&start); + rewindErrorTo(&start); return; } } } -QAsCodeParser::CodeSegment QAsCodeParser::ParseFunction(bool isMethod) { +QAsCodeParser::CodeSegment QAsCodeParser::parseFunction(bool isMethod) { CodeSegment fn; // TODO: Why isn't ParseFunctionDefinition used? sToken t1; - GetToken(&t1); + getToken(&t1); if (!isMethod) { // A global function can be marked as shared and external while (t1.type == ttIdentifier) { - if (IdentifierIs(t1, SHARED_TOKEN) || - IdentifierIs(t1, EXTERNAL_TOKEN)) { - RewindTo(&t1); - ParseIdentifier(); + if (identifierIs(t1, SHARED_TOKEN) || + identifierIs(t1, EXTERNAL_TOKEN)) { + rewindTo(&t1); + parseIdentifier(); if (isSyntaxError) return fn; } else break; - GetToken(&t1); + getToken(&t1); } } // A class method can start with 'private' or 'protected' if (isMethod && t1.type == ttPrivate) { - RewindTo(&t1); - ParseToken(ttPrivate); - GetToken(&t1); + rewindTo(&t1); + parseToken(ttPrivate); + getToken(&t1); } else if (isMethod && t1.type == ttProtected) { - RewindTo(&t1); - ParseToken(ttProtected); - GetToken(&t1); + rewindTo(&t1); + parseToken(ttProtected); + getToken(&t1); } if (isSyntaxError) return fn; @@ -1567,13 +1868,13 @@ QAsCodeParser::CodeSegment QAsCodeParser::ParseFunction(bool isMethod) { // If it is a global function, or a method, except constructor and // destructor, then the return type is parsed sToken t2; - GetToken(&t2); - RewindTo(&t1); + getToken(&t2); + rewindTo(&t1); if (!isMethod || (t1.type != ttBitNot && t2.type != ttOpenParenthesis)) { - auto id = ParseType(true); + auto id = parseType(true); if (isSyntaxError) return fn; - fn.ret = getSymbolString(id); + // fn.ret = getSymbolString(id); ParseTypeMod(false); if (isSyntaxError) @@ -1583,76 +1884,76 @@ QAsCodeParser::CodeSegment QAsCodeParser::ParseFunction(bool isMethod) { // If this is a class destructor then it starts with ~, and no return type // is declared if (isMethod && t1.type == ttBitNot) { - ParseToken(ttBitNot); + parseToken(ttBitNot); if (isSyntaxError) return fn; } - auto iden = ParseIdentifier(); + auto iden = parseIdentifier(); if (isSyntaxError) return fn; fn.name = getSymbolString(iden); - fn.nameInSrc = iden.pos; + // fn.nameInSrc = iden.pos; - auto params = ParseParameterList(); + auto params = parseParameterListContent(); if (isSyntaxError) return fn; - fn.args = params; + // fn.args = params; if (isMethod) { - GetToken(&t1); - RewindTo(&t1); + getToken(&t1); + rewindTo(&t1); // Is the method a const? if (t1.type == ttConst) - ParseToken(ttConst); + parseToken(ttConst); } // TODO: Should support abstract methods, in which case no statement block // should be provided - ParseMethodAttributes(); + parseMethodAttributes(); if (isSyntaxError) return fn; // External shared functions must be ended with ';' - GetToken(&t1); - RewindTo(&t1); + getToken(&t1); + rewindTo(&t1); if (t1.type == ttEndStatement) { - ParseToken(ttEndStatement); + parseToken(ttEndStatement); // fn.ns = _curns; return fn; } // We should just find the end of the statement block here. The statements // will be parsed on request by the compiler once it starts the compilation. - SuperficiallyParseStatementBlock(); + superficiallyParseStatementBlock(); // fn.ns = _curns; - fn.code = code.mid(t1.pos, sourcePos - t1.pos); - fn.valid = true; + // fn.code = code.mid(t1.pos, sourcePos - t1.pos); + // fn.valid = true; return fn; } -QAsCodeParser::Symbol QAsCodeParser::ParseFuncDef() { +QAsCodeParser::Symbol QAsCodeParser::parseFuncDefContent() { Symbol sym; // Allow keywords 'external' and 'shared' before 'interface' sToken t1; - GetToken(&t1); - while (IdentifierIs(t1, SHARED_TOKEN) || IdentifierIs(t1, EXTERNAL_TOKEN)) { - RewindTo(&t1); + getToken(&t1); + while (identifierIs(t1, SHARED_TOKEN) || identifierIs(t1, EXTERNAL_TOKEN)) { + rewindTo(&t1); if (isSyntaxError) return sym; - GetToken(&t1); + getToken(&t1); } if (t1.type != ttFuncDef) { - RewindErrorTo(&t1); + rewindErrorTo(&t1); return sym; } - ParseType(true); + parseType(true); if (isSyntaxError) return sym; @@ -1660,65 +1961,65 @@ QAsCodeParser::Symbol QAsCodeParser::ParseFuncDef() { if (isSyntaxError) return sym; - auto iden = ParseIdentifier(); + auto iden = parseIdentifier(); if (isSyntaxError) return sym; sym.name = getSymbolString(iden); - sym.nameInSrc = iden.pos; + // sym.nameInSrc = iden.pos; - auto args = ParseParameterList(); + auto args = parseParameterListContent(); if (isSyntaxError) return sym; - sym.content = args; + // sym.content = args; - GetToken(&t1); + getToken(&t1); if (t1.type != ttEndStatement) { - RewindErrorTo(&t1); + rewindErrorTo(&t1); return sym; } - sym.type = SymbolType::FnDecl; + // sym.type = SymbolType::FnDecl; return sym; } -void QAsCodeParser::ParseClass() { +void QAsCodeParser::parseClassContent() { Symbol clssym; sToken t; - GetToken(&t); + getToken(&t); // Allow the keywords 'shared', 'abstract', 'final', and 'external' before // 'class' - while (IdentifierIs(t, SHARED_TOKEN) || IdentifierIs(t, ABSTRACT_TOKEN) || - IdentifierIs(t, FINAL_TOKEN) || IdentifierIs(t, EXTERNAL_TOKEN)) { - RewindTo(&t); - ParseIdentifier(); - GetToken(&t); + while (identifierIs(t, SHARED_TOKEN) || identifierIs(t, ABSTRACT_TOKEN) || + identifierIs(t, FINAL_TOKEN) || identifierIs(t, EXTERNAL_TOKEN)) { + rewindTo(&t); + parseIdentifier(); + getToken(&t); } if (t.type != ttClass) { - RewindErrorTo(&t); + rewindErrorTo(&t); return; } if (engine->ep.allowImplicitHandleTypes) { // Parse 'implicit handle class' construct - GetToken(&t); + getToken(&t); if (t.type != ttHandle) - RewindTo(&t); + rewindTo(&t); } - auto cls = ParseIdentifier(); + auto cls = parseIdentifier(); clssym.name = getSymbolString(cls); - clssym.nameInSrc = cls.pos; - clssym.type = SymbolType::Class; + // clssym.nameInSrc = cls.pos; + // clssym.type = SymbolType::Class; // External shared declarations are ended with ';' - GetToken(&t); + getToken(&t); if (t.type == ttEndStatement) { - RewindTo(&t); - ParseToken(ttEndStatement); + rewindTo(&t); + parseToken(ttEndStatement); return; } @@ -1727,118 +2028,118 @@ void QAsCodeParser::ParseClass() { if (t.type == ttColon) { // TODO: dont support temperily, later ParseOptionalScope(); - ParseIdentifier(); - GetToken(&t); + parseIdentifier(); + getToken(&t); while (t.type == ttListSeparator) { ParseOptionalScope(); - ParseIdentifier(); - GetToken(&t); + parseIdentifier(); + getToken(&t); } } if (t.type != ttStartStatementBlock) { - RewindErrorTo(&t); + rewindErrorTo(&t); return; } // Parse properties - GetToken(&t); - RewindTo(&t); + getToken(&t); + rewindTo(&t); while (t.type != ttEndStatementBlock && t.type != ttEnd) { // Is it a property or a method? if (t.type == ttFuncDef) { - auto fndef = ParseFuncDef(); - if (fndef.isValid()) { - clssym.content.append(fndef); - } - } else if (IsFuncDecl(true)) { - auto fn = ParseFunction(true); - if (fn.isValid()) { - clssym.codesegs.insert(fn.nameInSrc, fn); - } - } else if (IsVirtualPropertyDecl()) { - auto vp = ParseVirtualPropertyDecl(true, false); - if (vp.isValid()) { - clssym.content.append(vp); - } - } else if (IsVarDecl()) { - auto decl = ParseDeclaration(true); - clssym.content.append(decl); + auto fndef = parseFuncDefContent(); + // if (fndef.isValid()) { + // clssym.content.append(fndef); + // } + } else if (isFuncDecl(true)) { + auto fn = parseFunction(true); + // if (fn.isValid()) { + // clssym.codesegs.insert(fn.nameInSrc, fn); + // } + } else if (isVirtualPropertyDecl()) { + auto vp = parseVirtualPropertyDecl(true, false); + // if (vp.isValid()) { + // clssym.content.append(vp); + // } + } else if (isVarDecl()) { + auto decl = parseDeclaration(true); + // clssym.content.append(decl); } else if (t.type == ttEndStatement) // Skip empty declarations - GetToken(&t); + getToken(&t); else { - RewindErrorTo(&t); + rewindErrorTo(&t); return; } if (isSyntaxError) return; - GetToken(&t); - RewindTo(&t); + getToken(&t); + rewindTo(&t); } - GetToken(&t); + getToken(&t); if (t.type != ttEndStatementBlock) { - RewindErrorTo(&t); + rewindErrorTo(&t); return; } - _symtable.insert(cls.pos, clssym); + // _symtable.insert(cls.pos, clssym); } -void QAsCodeParser::ParseMixin() { +void QAsCodeParser::parseMixinContent() { sToken t; - GetToken(&t); + getToken(&t); if (t.type != ttMixin) { - RewindErrorTo(&t); + rewindErrorTo(&t); return; } // A mixin token must be followed by a class declaration - ParseClass(); + parseClassContent(); } void QAsCodeParser::ParseInitList() { sToken t1; - GetToken(&t1); + getToken(&t1); if (t1.type != ttStartStatementBlock) { - RewindErrorTo(&t1); + rewindErrorTo(&t1); return; } - GetToken(&t1); + getToken(&t1); if (t1.type == ttEndStatementBlock) { // Statement block is finished return; } else { - RewindTo(&t1); + rewindTo(&t1); for (;;) { - GetToken(&t1); + getToken(&t1); if (t1.type == ttListSeparator) { // No expression - GetToken(&t1); + getToken(&t1); if (t1.type == ttEndStatementBlock) { // No expression return; } - RewindTo(&t1); + rewindTo(&t1); } else if (t1.type == ttEndStatementBlock) { // No expression // Statement block is finished return; } else if (t1.type == ttStartStatementBlock) { - RewindTo(&t1); + rewindTo(&t1); ParseInitList(); if (isSyntaxError) return; - GetToken(&t1); + getToken(&t1); if (t1.type == ttListSeparator) continue; else if (t1.type == ttEndStatementBlock) { @@ -1846,24 +2147,24 @@ void QAsCodeParser::ParseInitList() { // Statement block is finished return; } else { - RewindErrorTo(&t1); + rewindErrorTo(&t1); return; } } else { - RewindTo(&t1); + rewindTo(&t1); // NOTE ParseAssignment(); if (isSyntaxError) return; - GetToken(&t1); + getToken(&t1); if (t1.type == ttListSeparator) continue; else if (t1.type == ttEndStatementBlock) { // Statement block is finished return; } else { - RewindErrorTo(&t1); + rewindErrorTo(&t1); return; } } @@ -1872,377 +2173,377 @@ void QAsCodeParser::ParseInitList() { UNREACHABLE_RETURN; } -void QAsCodeParser::ParseInterface() { +void QAsCodeParser::parseInterfaceContent() { Symbol sym; sToken t; // Allow keywords 'external' and 'shared' before 'interface' - GetToken(&t); - while (IdentifierIs(t, SHARED_TOKEN) || IdentifierIs(t, EXTERNAL_TOKEN)) { - RewindTo(&t); - ParseIdentifier(); + getToken(&t); + while (identifierIs(t, SHARED_TOKEN) || identifierIs(t, EXTERNAL_TOKEN)) { + rewindTo(&t); + parseIdentifier(); if (isSyntaxError) return; - GetToken(&t); + getToken(&t); } if (t.type != ttInterface) { - RewindErrorTo(&t); + rewindErrorTo(&t); return; } - auto id = ParseIdentifier(); + auto id = parseIdentifier(); sym.name = getSymbolString(id); - sym.nameInSrc = id.pos; + // sym.nameInSrc = id.pos; // External shared declarations are ended with ';' - GetToken(&t); + getToken(&t); if (t.type == ttEndStatement) { - RewindTo(&t); - ParseToken(ttEndStatement); + rewindTo(&t); + parseToken(ttEndStatement); return; } // Can optionally have a list of interfaces that are inherited if (t.type == ttColon) { ParseOptionalScope(); - ParseIdentifier(); - GetToken(&t); + parseIdentifier(); + getToken(&t); while (t.type == ttListSeparator) { ParseOptionalScope(); - ParseIdentifier(); - GetToken(&t); + parseIdentifier(); + getToken(&t); } } if (t.type != ttStartStatementBlock) { - RewindErrorTo(&t); + rewindErrorTo(&t); return; } // Parse interface methods - GetToken(&t); - RewindTo(&t); + getToken(&t); + rewindTo(&t); while (t.type != ttEndStatementBlock && t.type != ttEnd) { - if (IsVirtualPropertyDecl()) { - auto vp = ParseVirtualPropertyDecl(true, true); - if (vp.isValid()) { - sym.content.append(vp); - } + if (isVirtualPropertyDecl()) { + auto vp = parseVirtualPropertyDecl(true, true); + // if (vp.isValid()) { + // sym.content.append(vp); + // } } else if (t.type == ttEndStatement) { // Skip empty declarations - GetToken(&t); + getToken(&t); } else { // Parse the method signature - auto im = ParseInterfaceMethod(); - if (im.isValid()) { - sym.content.append(im); - } + auto im = parseInterfaceMethod(); + // if (im.isValid()) { + // sym.content.append(im); + // } } if (isSyntaxError) return; - GetToken(&t); - RewindTo(&t); + getToken(&t); + rewindTo(&t); } - GetToken(&t); + getToken(&t); if (t.type != ttEndStatementBlock) { - RewindErrorTo(&t); + rewindErrorTo(&t); return; } } -QAsCodeParser::Symbol QAsCodeParser::ParseInterfaceMethod() { +QAsCodeParser::Symbol QAsCodeParser::parseInterfaceMethod() { Symbol sym; - auto ret = ParseType(true); + auto ret = parseType(true); if (isSyntaxError) return sym; - sym.typeStr = getSymbolString(ret); + // sym.typeStr = getSymbolString(ret); ParseTypeMod(false); if (isSyntaxError) return sym; - auto id = ParseIdentifier(); + auto id = parseIdentifier(); if (isSyntaxError) return sym; sym.name = getSymbolString(id); - sym.nameInSrc = id.pos; + // sym.nameInSrc = id.pos; - auto args = ParseParameterList(); + auto args = parseParameterListContent(); if (isSyntaxError) return sym; - sym.content = args; + // sym.content = args; // Parse an optional const after the method definition sToken t1; - GetToken(&t1); - RewindTo(&t1); + getToken(&t1); + rewindTo(&t1); if (t1.type == ttConst) - ParseToken(ttConst); + parseToken(ttConst); - GetToken(&t1); + getToken(&t1); if (t1.type != ttEndStatement) { - RewindErrorTo(&t1); + rewindErrorTo(&t1); return sym; } - sym.type = SymbolType::FnDecl; + // sym.type = SymbolType::FnDecl; return sym; } QAsCodeParser::Symbol -QAsCodeParser::ParseVirtualPropertyDecl(bool isMethod, bool isInterface) { +QAsCodeParser::parseVirtualPropertyDecl(bool isMethod, bool isInterface) { Symbol sym; sToken t1, t2; - GetToken(&t1); - GetToken(&t2); - RewindTo(&t1); + getToken(&t1); + getToken(&t2); + rewindTo(&t1); // A class method can start with 'private' or 'protected' if (isMethod && t1.type == ttPrivate) { - ParseToken(ttPrivate); + parseToken(ttPrivate); sym.vis = Visiblity::Private; } else if (isMethod && t1.type == ttProtected) { - ParseToken(ttProtected); + parseToken(ttProtected); sym.vis = Visiblity::Protected; } if (isSyntaxError) return sym; - auto id = ParseType(true); + auto id = parseType(true); if (isSyntaxError) return sym; - sym.typeStr = getSymbolString(id); + // sym.typeStr = getSymbolString(id); ParseTypeMod(false); if (isSyntaxError) return sym; - auto iden = ParseIdentifier(); + auto iden = parseIdentifier(); if (isSyntaxError) return sym; sym.name = getSymbolString(iden); - sym.nameInSrc = iden.pos; + // sym.nameInSrc = iden.pos; - GetToken(&t1); + getToken(&t1); if (t1.type != ttStartStatementBlock) { - RewindErrorTo(&t1); + rewindErrorTo(&t1); return sym; } for (;;) { - GetToken(&t1); + getToken(&t1); CodeSegment seg; - if (IdentifierIs(t1, GET_TOKEN) || IdentifierIs(t1, SET_TOKEN)) { - RewindTo(&t1); + if (identifierIs(t1, GET_TOKEN) || identifierIs(t1, SET_TOKEN)) { + rewindTo(&t1); - auto id = ParseIdentifier(); + auto id = parseIdentifier(); auto name = getSymbolString(id); seg.name = name; if (isMethod) { - GetToken(&t1); - RewindTo(&t1); + getToken(&t1); + rewindTo(&t1); if (t1.type == ttConst) - ParseToken(ttConst); + parseToken(ttConst); if (!isInterface) { - ParseMethodAttributes(); + parseMethodAttributes(); if (isSyntaxError) return sym; } } if (!isInterface) { - GetToken(&t1); + getToken(&t1); if (t1.type == ttStartStatementBlock) { - RewindTo(&t1); - SuperficiallyParseStatementBlock(); + rewindTo(&t1); + superficiallyParseStatementBlock(); - seg.valid = true; - seg.code = code.mid(t1.pos, sourcePos - t1.pos); - sym.codesegs.insert(t1.pos, seg); + // seg.valid = true; + // seg.code = code.mid(t1.pos, sourcePos - t1.pos); + // sym.codesegs.insert(t1.pos, seg); if (isSyntaxError) return sym; } else if (t1.type == ttEndStatement) { - RewindTo(&t1); - ParseToken(ttEndStatement); + rewindTo(&t1); + parseToken(ttEndStatement); if (isSyntaxError) return sym; } else { - RewindErrorTo(&t1); + rewindErrorTo(&t1); return sym; } } else { - GetToken(&t1); + getToken(&t1); if (t1.type == ttEndStatement) { - RewindTo(&t1); - ParseToken(ttEndStatement); + rewindTo(&t1); + parseToken(ttEndStatement); if (isSyntaxError) return sym; } else { - RewindErrorTo(&t1); + rewindErrorTo(&t1); return sym; } } } else if (t1.type == ttEndStatementBlock) break; else { - RewindErrorTo(&t1); + rewindErrorTo(&t1); return sym; } } - sym.type = SymbolType::Property; + // sym.type = SymbolType::Property; return sym; } -void QAsCodeParser::ParseEnumeration() { +void QAsCodeParser::parseEnumerationContent() { Symbol sym; sToken token; size_t eoff; // Optional 'shared' and 'external' token - GetToken(&token); - while (IdentifierIs(token, SHARED_TOKEN) || - IdentifierIs(token, EXTERNAL_TOKEN)) { - RewindTo(&token); + getToken(&token); + while (identifierIs(token, SHARED_TOKEN) || + identifierIs(token, EXTERNAL_TOKEN)) { + rewindTo(&token); - ParseIdentifier(); + parseIdentifier(); if (isSyntaxError) return; - GetToken(&token); + getToken(&token); } // Check for enum if (token.type != ttEnum) { - RewindErrorTo(&token); + rewindErrorTo(&token); return; } // Get the identifier - GetToken(&token); + getToken(&token); if (ttIdentifier != token.type) { - RewindErrorTo(&token); + rewindErrorTo(&token); return; } // ok, init symbol eoff = token.pos; sym.name = getSymbolString(token); - sym.nameInSrc = token.pos; - sym.type = SymbolType::Enum; + // sym.nameInSrc = token.pos; + // sym.type = SymbolType::Enum; // sym.ns = _curns; // External shared declarations are ended with ';' - GetToken(&token); + getToken(&token); if (token.type == ttEndStatement) { - RewindTo(&token); - ParseToken(ttEndStatement); + rewindTo(&token); + parseToken(ttEndStatement); return; } // check for the start of the declaration block if (token.type != ttStartStatementBlock) { - RewindTo(&token); - RewindErrorTo(&token); + rewindTo(&token); + rewindErrorTo(&token); return; } while (ttEnd != token.type) { - GetToken(&token); + getToken(&token); if (ttEndStatementBlock == token.type) { - RewindTo(&token); + rewindTo(&token); break; } if (ttIdentifier != token.type) { - RewindErrorTo(&token); + rewindErrorTo(&token); return; } // Add the enum element Symbol se; - se.type = SymbolType::Value; + // se.type = SymbolType::Value; se.name = getSymbolString(token); - GetToken(&token); - sym.content.append(se); + getToken(&token); + // sym.content.append(se); if (token.type == ttAssignment) { - RewindTo(&token); + rewindTo(&token); - SuperficiallyParseVarInit(); + superficiallyParseVarInit(); if (isSyntaxError) return; - GetToken(&token); + getToken(&token); } if (ttListSeparator != token.type) { - RewindTo(&token); + rewindTo(&token); break; } } // check for the end of the declaration block - GetToken(&token); + getToken(&token); if (token.type != ttEndStatementBlock) { - RewindTo(&token); - RewindErrorTo(&token); + rewindTo(&token); + rewindErrorTo(&token); return; } - _symtable.insert(eoff, sym); + // _symtable.insert(eoff, sym); } -void QAsCodeParser::ParseTypedef() { +void QAsCodeParser::parseTypedefContent() { Symbol sym; size_t eoff; sToken token; - GetToken(&token); + getToken(&token); if (token.type != ttTypedef) { - RewindErrorTo(&token); + rewindErrorTo(&token); return; } eoff = token.pos; // Parse the base type - GetToken(&token); - RewindTo(&token); + getToken(&token); + rewindTo(&token); // Make sure it is a primitive type (except ttVoid) - if (!IsRealType(token.type) || token.type == ttVoid) { - RewindErrorTo(&token); + if (!isRealType(token.type) || token.type == ttVoid) { + rewindErrorTo(&token); return; } - auto r = ParseRealType(); - auto i = ParseIdentifier(); + auto r = parseRealType(); + auto i = parseIdentifier(); // Check for the end of the typedef - GetToken(&token); + getToken(&token); if (token.type != ttEndStatement) { - RewindTo(&token); - RewindErrorTo(&token); + rewindTo(&token); + rewindErrorTo(&token); } sym.name = getSymbolString(i); @@ -2250,45 +2551,45 @@ void QAsCodeParser::ParseTypedef() { Symbol st; st.name = getSymbolString(r); - sym.content.append(st); + // sym.content.append(st); // sym.ns = _curns; - _symtable.insert(eoff, sym); + // _symtable.insert(eoff, sym); } -bool QAsCodeParser::IsVarDecl() { +bool QAsCodeParser::isVarDecl() { // Set start point so that we can rewind sToken t; - GetToken(&t); - RewindTo(&t); + getToken(&t); + rewindTo(&t); // A class property decl can be preceded by 'private' or 'protected' sToken t1; - GetToken(&t1); + getToken(&t1); if (t1.type != ttPrivate && t1.type != ttProtected) - RewindTo(&t1); + rewindTo(&t1); // A variable decl starts with the type - if (!FindTokenAfterType(t1)) { - RewindTo(&t); + if (!findTokenAfterType(t1)) { + rewindTo(&t); return false; } // Jump to the token after the type - RewindTo(&t1); - GetToken(&t1); + rewindTo(&t1); + getToken(&t1); // The declaration needs to have a name if (t1.type != ttIdentifier) { - RewindTo(&t); + rewindTo(&t); return false; } // It can be followed by an initialization - GetToken(&t1); + getToken(&t1); if (t1.type == ttEndStatement || t1.type == ttAssignment || t1.type == ttListSeparator) { - RewindTo(&t); + rewindTo(&t); return true; } if (t1.type == ttOpenParenthesis) { @@ -2305,131 +2606,131 @@ bool QAsCodeParser::IsVarDecl() { if (nest == 0) break; } - GetToken(&t1); + getToken(&t1); } if (t1.type == ttEnd) { - RewindTo(&t); + rewindTo(&t); return false; } else { - GetToken(&t1); - RewindTo(&t); + getToken(&t1); + rewindTo(&t); if (t1.type == ttStartStatementBlock || t1.type == ttIdentifier || // function decorator t1.type == ttEnd) return false; } - RewindTo(&t); + rewindTo(&t); return true; } - RewindTo(&t); + rewindTo(&t); return false; } -bool QAsCodeParser::IsVirtualPropertyDecl() { // Set start point so that we can - // rewind +bool QAsCodeParser::isVirtualPropertyDecl() { + // Set start point so that we can rewind sToken t; - GetToken(&t); - RewindTo(&t); + getToken(&t); + rewindTo(&t); // A class property decl can be preceded by 'private' or 'protected' sToken t1; - GetToken(&t1); + getToken(&t1); if (t1.type != ttPrivate && t1.type != ttProtected) - RewindTo(&t1); + rewindTo(&t1); // A variable decl starts with the type - if (!FindTokenAfterType(t1)) { - RewindTo(&t); + if (!findTokenAfterType(t1)) { + rewindTo(&t); return false; } // Move to the token after the type - RewindTo(&t1); - GetToken(&t1); + rewindTo(&t1); + getToken(&t1); // The decl must have an identifier if (t1.type != ttIdentifier) { - RewindTo(&t); + rewindTo(&t); return false; } // To be a virtual property it must also have a block for the get/set // functions - GetToken(&t1); + getToken(&t1); if (t1.type == ttStartStatementBlock) { - RewindTo(&t); + rewindTo(&t); return true; } - RewindTo(&t); + rewindTo(&t); return false; } -bool QAsCodeParser::IsFuncDecl( +bool QAsCodeParser::isFuncDecl( bool isMethod) { // Set start point so that we can rewind sToken t; - GetToken(&t); - RewindTo(&t); + getToken(&t); + rewindTo(&t); if (isMethod) { // A class method decl can be preceded by 'private' or 'protected' sToken t1, t2; - GetToken(&t1); + getToken(&t1); if (t1.type != ttPrivate && t1.type != ttProtected) - RewindTo(&t1); + rewindTo(&t1); // A class constructor starts with identifier followed by parenthesis // A class destructor starts with the ~ token - GetToken(&t1); - GetToken(&t2); - RewindTo(&t1); + getToken(&t1); + getToken(&t2); + rewindTo(&t1); if ((t1.type == ttIdentifier && t2.type == ttOpenParenthesis) || t1.type == ttBitNot) { - RewindTo(&t); + rewindTo(&t); return true; } } // A function decl starts with a type sToken t1; - if (!FindTokenAfterType(t1)) { - RewindTo(&t); + if (!findTokenAfterType(t1)) { + rewindTo(&t); return false; } // Move to the token after the type - RewindTo(&t1); - GetToken(&t1); + rewindTo(&t1); + getToken(&t1); // There can be an ampersand if the function returns a reference if (t1.type == ttAmp) { - RewindTo(&t); + rewindTo(&t); return true; } if (t1.type != ttIdentifier) { - RewindTo(&t); + rewindTo(&t); return false; } - GetToken(&t1); + getToken(&t1); if (t1.type == ttOpenParenthesis) { // If the closing parenthesis is not followed by a // statement block then it is not a function. // It's possible that there are nested parenthesis due to default // arguments so this should be checked for. int nest = 0; - GetToken(&t1); + getToken(&t1); while ((nest || t1.type != ttCloseParenthesis) && t1.type != ttEnd) { if (t1.type == ttOpenParenthesis) nest++; if (t1.type == ttCloseParenthesis) nest--; - GetToken(&t1); + getToken(&t1); } if (t1.type == ttEnd) @@ -2438,28 +2739,28 @@ bool QAsCodeParser::IsFuncDecl( if (isMethod) { // A class method can have a 'const' token after the parameter // list - GetToken(&t1); + getToken(&t1); if (t1.type != ttConst) - RewindTo(&t1); + rewindTo(&t1); } // A function may also have any number of additional attributes bool hasAttribs = false; for (;;) { - GetToken(&t1); - if (!IdentifierIs(t1, FINAL_TOKEN) && - !IdentifierIs(t1, OVERRIDE_TOKEN) && - !IdentifierIs(t1, EXPLICIT_TOKEN) && - !IdentifierIs(t1, PROPERTY_TOKEN) && - !IdentifierIs(t1, DELETE_TOKEN)) { - RewindTo(&t1); + getToken(&t1); + if (!identifierIs(t1, FINAL_TOKEN) && + !identifierIs(t1, OVERRIDE_TOKEN) && + !identifierIs(t1, EXPLICIT_TOKEN) && + !identifierIs(t1, PROPERTY_TOKEN) && + !identifierIs(t1, DELETE_TOKEN)) { + rewindTo(&t1); break; } hasAttribs = true; } - GetToken(&t1); - RewindTo(&t); + getToken(&t1); + rewindTo(&t); // If the function has an attribute, e.g. delete, it can be // terminated with a ; if no implementation is expected otherwise it @@ -2469,52 +2770,52 @@ bool QAsCodeParser::IsFuncDecl( return true; } - RewindTo(&t); + rewindTo(&t); return false; } - RewindTo(&t); + rewindTo(&t); return false; } -bool QAsCodeParser::IsLambda() { +bool QAsCodeParser::isLambda() { bool isLambda = false; sToken t; - GetToken(&t); - if (t.type == ttIdentifier && IdentifierIs(t, FUNCTION_TOKEN)) { + getToken(&t); + if (t.type == ttIdentifier && identifierIs(t, FUNCTION_TOKEN)) { sToken t2; - GetToken(&t2); + getToken(&t2); if (t2.type == ttOpenParenthesis) { // Skip until ) while (t2.type != ttCloseParenthesis && t2.type != ttEnd) - GetToken(&t2); + getToken(&t2); // The next token must be a { - GetToken(&t2); + getToken(&t2); if (t2.type == ttStartStatementBlock) isLambda = true; } } - RewindTo(&t); + rewindTo(&t); return isLambda; } -bool QAsCodeParser::IsFunctionCall() { +bool QAsCodeParser::isFunctionCall() { sToken s; sToken t1, t2; - GetToken(&s); + getToken(&s); t1 = s; // A function call may be prefixed with scope resolution if (t1.type == ttScope) - GetToken(&t1); - GetToken(&t2); + getToken(&t1); + getToken(&t2); while (t1.type == ttIdentifier && t2.type == ttScope) { - GetToken(&t1); - GetToken(&t2); + getToken(&t1); + getToken(&t2); } // A function call starts with an identifier followed by an argument list @@ -2523,16 +2824,16 @@ bool QAsCodeParser::IsFunctionCall() { // the parser will identify the expression as a function call rather than a // construct call. The compiler will sort this out later if (t1.type != ttIdentifier) { - RewindTo(&s); + rewindTo(&s); return false; } if (t2.type == ttOpenParenthesis) { - RewindTo(&s); + rewindTo(&s); return true; } - RewindTo(&s); + rewindTo(&s); return false; } @@ -2542,10 +2843,10 @@ void QAsCodeParser::ParseAssignment() { return; sToken t; - GetToken(&t); - RewindTo(&t); + getToken(&t); + rewindTo(&t); - if (IsAssignOperator(t.type)) { + if (isAssignOperator(t.type)) { ParseAssignOperator(); if (isSyntaxError) return; @@ -2558,9 +2859,9 @@ void QAsCodeParser::ParseAssignment() { void QAsCodeParser::ParseAssignOperator() { sToken t; - GetToken(&t); - if (!IsAssignOperator(t.type)) { - RewindErrorTo(&t); + getToken(&t); + if (!isAssignOperator(t.type)) { + rewindErrorTo(&t); return; } } @@ -2572,15 +2873,15 @@ void QAsCodeParser::ParseCondition() { return; sToken t; - GetToken(&t); + getToken(&t); if (t.type == ttQuestion) { ParseAssignment(); if (isSyntaxError) return; - GetToken(&t); + getToken(&t); if (t.type != ttColon) { - RewindErrorTo(&t); + rewindErrorTo(&t); return; } @@ -2588,7 +2889,7 @@ void QAsCodeParser::ParseCondition() { if (isSyntaxError) return; } else - RewindTo(&t); + rewindTo(&t); } void QAsCodeParser::ParseExpression() { @@ -2598,10 +2899,10 @@ void QAsCodeParser::ParseExpression() { for (;;) { sToken t; - GetToken(&t); - RewindTo(&t); + getToken(&t); + rewindTo(&t); - if (!IsOperator(t.type)) + if (!isOperator(t.type)) return; ParseExprOperator(); @@ -2619,39 +2920,39 @@ void QAsCodeParser::ParseExprTerm() { // Check if the expression term is an initialization of a temp object with // init list, i.e. type = {...} sToken t; - GetToken(&t); + getToken(&t); sToken t2 = t, t3; - RewindTo(&t); - if (IsDataType(t2) && CheckTemplateType(t2) && FindTokenAfterType(t2)) { + rewindTo(&t); + if (isDataType(t2) && checkTemplateType(t2) && findTokenAfterType(t2)) { // Move to token after the type - RewindTo(&t2); + rewindTo(&t2); // The next token must be a = followed by a { - GetToken(&t2); - GetToken(&t3); + getToken(&t2); + getToken(&t3); if (t2.type == ttAssignment && t3.type == ttStartStatementBlock) { // It is an initialization, now parse it for real - RewindTo(&t); - ParseType(false); - GetToken(&t2); + rewindTo(&t); + parseType(false); + getToken(&t2); ParseInitList(); return; } } // Or an anonymous init list, i.e. {...} else if (t.type == ttStartStatementBlock) { - RewindTo(&t); + rewindTo(&t); ParseInitList(); return; } // It wasn't an initialization, so it must be an ordinary expression term - RewindTo(&t); + rewindTo(&t); for (;;) { - GetToken(&t); - RewindTo(&t); - if (!IsPreOperator(t.type)) + getToken(&t); + rewindTo(&t); + if (!isPreOperator(t.type)) break; ParseExprPreOp(); @@ -2664,9 +2965,9 @@ void QAsCodeParser::ParseExprTerm() { return; for (;;) { - GetToken(&t); - RewindTo(&t); - if (!IsPostOperator(t.type)) + getToken(&t); + rewindTo(&t); + if (!isPostOperator(t.type)) return; ParseExprPostOp(); @@ -2678,81 +2979,81 @@ void QAsCodeParser::ParseExprTerm() { void QAsCodeParser::ParseExprOperator() { sToken t; - GetToken(&t); - if (!IsOperator(t.type)) { - RewindErrorTo(&t); + getToken(&t); + if (!isOperator(t.type)) { + rewindErrorTo(&t); return; } } void QAsCodeParser::ParseExprPreOp() { sToken t; - GetToken(&t); - if (!IsPreOperator(t.type)) { - RewindErrorTo(&t); + getToken(&t); + if (!isPreOperator(t.type)) { + rewindErrorTo(&t); return; } } void QAsCodeParser::ParseExprPostOp() { sToken t; - GetToken(&t); - if (!IsPostOperator(t.type)) { - RewindErrorTo(&t); + getToken(&t); + if (!isPostOperator(t.type)) { + rewindErrorTo(&t); return; } if (t.type == ttDot) { sToken t1, t2; - GetToken(&t1); - GetToken(&t2); - RewindTo(&t1); + getToken(&t1); + getToken(&t2); + rewindTo(&t1); if (t2.type == ttOpenParenthesis) ParseFunctionCall(); else - ParseIdentifier(); + parseIdentifier(); } else if (t.type == ttOpenBracket) { - ParseArgList(false); + parseArgList(false); - GetToken(&t); + getToken(&t); if (t.type != ttCloseBracket) { - RewindErrorTo(&t); + rewindErrorTo(&t); return; } } else if (t.type == ttOpenParenthesis) { - RewindTo(&t); - ParseArgList(); + rewindTo(&t); + parseArgList(); } } void QAsCodeParser::ParseExprValue() { sToken t1, t2; - GetToken(&t1); - GetToken(&t2); - RewindTo(&t1); + getToken(&t1); + getToken(&t2); + rewindTo(&t1); // 'void' is a special expression that doesn't do anything (normally used // for skipping output arguments) if (t1.type == ttVoid) - ParseToken(ttVoid); - else if (IsRealType(t1.type)) + parseToken(ttVoid); + else if (isRealType(t1.type)) ParseConstructCall(); else if (t1.type == ttIdentifier || t1.type == ttScope) { // Check if the expression is an anonymous function - if (IsLambda()) { + if (isLambda()) { ParseLambda(); } else { // Determine the last identifier in order to check if it is a type - FindIdentifierAfterScope(t2); - RewindTo(&t2); + findIdentifierAfterScope(t2); + rewindTo(&t2); // Get The token after the identifier to determine if it is an [ sToken t; - GetToken(&t); - GetToken(&t); + getToken(&t); + getToken(&t); - bool isDataType = IsDataType(t2); + bool isDataType = this->isDataType(t2); bool isTemplateType = false; if (isDataType) { // Is this a template type? @@ -2761,11 +3062,11 @@ void QAsCodeParser::ParseExprValue() { isTemplateType = true; } - GetToken(&t2); + getToken(&t2); // Rewind so the real parsing can be done, after deciding what to // parse - RewindTo(&t1); + rewindTo(&t1); // Check if this is a construct call // Just 'type()' isn't considered a construct call, because type may @@ -2777,62 +3078,62 @@ void QAsCodeParser::ParseExprValue() { ParseConstructCall(); else if (isTemplateType && t.type == ttLessThan) // type() ParseConstructCall(); - else if (IsFunctionCall()) + else if (isFunctionCall()) ParseFunctionCall(); else ParseVariableAccess(); } } else if (t1.type == ttCast) ParseCast(); - else if (IsConstant(t1.type)) + else if (isConstant(t1.type)) ParseConstant(); else if (t1.type == ttOpenParenthesis) { - GetToken(&t1); + getToken(&t1); ParseAssignment(); if (isSyntaxError) return; - GetToken(&t1); + getToken(&t1); if (t1.type != ttCloseParenthesis) { - RewindErrorTo(&t1); + rewindErrorTo(&t1); } } else { - RewindErrorTo(&t1); + rewindErrorTo(&t1); } } -void QAsCodeParser::ParseArgList(bool withParenthesis) { +void QAsCodeParser::parseArgList(bool withParenthesis) { sToken t1; if (withParenthesis) { - GetToken(&t1); + getToken(&t1); if (t1.type != ttOpenParenthesis) { - RewindErrorTo(&t1); + rewindErrorTo(&t1); return; } } - GetToken(&t1); + getToken(&t1); if (t1.type == ttCloseParenthesis || t1.type == ttCloseBracket) { if (withParenthesis) { if (t1.type != ttCloseParenthesis) { - RewindErrorTo(&t1); + rewindErrorTo(&t1); } } else - RewindTo(&t1); + rewindTo(&t1); // Argument list has ended return; } else { - RewindTo(&t1); + rewindTo(&t1); for (;;) { // Determine if this is a named argument sToken tl, t2; - GetToken(&tl); - GetToken(&t2); - RewindTo(&tl); + getToken(&tl); + getToken(&t2); + rewindTo(&tl); // Named arguments uses the syntax: arg : expr // This avoids confusion when the argument has the same name as a @@ -2847,8 +3148,8 @@ void QAsCodeParser::ParseArgList(bool withParenthesis) { // NOTE add symbol - ParseIdentifier(); - GetToken(&t2); + parseIdentifier(); + getToken(&t2); ParseAssignment(); } else @@ -2858,16 +3159,16 @@ void QAsCodeParser::ParseArgList(bool withParenthesis) { return; // Check if list continues - GetToken(&t1); + getToken(&t1); if (t1.type == ttListSeparator) continue; else { if (withParenthesis) { if (t1.type != ttCloseParenthesis) { - RewindErrorTo(&t1); + rewindErrorTo(&t1); } } else - RewindTo(&t1); + rewindTo(&t1); return; } @@ -2880,11 +3181,11 @@ void QAsCodeParser::ParseFunctionCall() { ParseOptionalScope(); // Parse the function name followed by the argument list - ParseIdentifier(); + parseIdentifier(); if (isSyntaxError) return; - ParseArgList(); + parseArgList(); } void QAsCodeParser::ParseVariableAccess() { @@ -2892,47 +3193,47 @@ void QAsCodeParser::ParseVariableAccess() { ParseOptionalScope(); // Parse the variable name - ParseIdentifier(); + parseIdentifier(); } void QAsCodeParser::ParseConstructCall() { // NOTE - ParseType(false); + parseType(false); if (isSyntaxError) return; - ParseArgList(); + parseArgList(); } void QAsCodeParser::ParseCast() { sToken t1; - GetToken(&t1); + getToken(&t1); if (t1.type != ttCast) { - RewindErrorTo(&t1); + rewindErrorTo(&t1); return; } - GetToken(&t1); + getToken(&t1); if (t1.type != ttLessThan) { - RewindErrorTo(&t1); + rewindErrorTo(&t1); return; } // Parse the data type - ParseType(true); + parseType(true); if (isSyntaxError) return; - GetToken(&t1); + getToken(&t1); if (t1.type != ttGreaterThan) { - RewindErrorTo(&t1); + rewindErrorTo(&t1); return; } - GetToken(&t1); + getToken(&t1); if (t1.type != ttOpenParenthesis) { - RewindErrorTo(&t1); + rewindErrorTo(&t1); return; } @@ -2940,64 +3241,64 @@ void QAsCodeParser::ParseCast() { if (isSyntaxError) return; - GetToken(&t1); + getToken(&t1); if (t1.type != ttCloseParenthesis) { - RewindErrorTo(&t1); + rewindErrorTo(&t1); return; } } void QAsCodeParser::ParseConstant() { sToken t; - GetToken(&t); - if (!IsConstant(t.type)) { - RewindErrorTo(&t); + getToken(&t); + if (!isConstant(t.type)) { + rewindErrorTo(&t); return; } // We want to gather a list of string constants to concatenate as children if (t.type == ttStringConstant || t.type == ttMultilineStringConstant || t.type == ttHeredocStringConstant) - RewindTo(&t); + rewindTo(&t); while (t.type == ttStringConstant || t.type == ttMultilineStringConstant || t.type == ttHeredocStringConstant) { // NOTE ParseStringConstant(); - GetToken(&t); - RewindTo(&t); + getToken(&t); + rewindTo(&t); } } void QAsCodeParser::ParseStringConstant() { sToken t; - GetToken(&t); + getToken(&t); if (t.type != ttStringConstant && t.type != ttMultilineStringConstant && t.type != ttHeredocStringConstant) { - RewindErrorTo(&t); + rewindErrorTo(&t); return; } } void QAsCodeParser::ParseLambda() { sToken t; - GetToken(&t); + getToken(&t); - if (t.type != ttIdentifier || !IdentifierIs(t, FUNCTION_TOKEN)) { - RewindErrorTo(&t); + if (t.type != ttIdentifier || !identifierIs(t, FUNCTION_TOKEN)) { + rewindErrorTo(&t); return; } - GetToken(&t); + getToken(&t); if (t.type != ttOpenParenthesis) { - RewindErrorTo(&t); + rewindErrorTo(&t); return; } - GetToken(&t); + getToken(&t); while (t.type != ttCloseParenthesis && t.type != ttEnd) { - RewindTo(&t); + rewindTo(&t); // Create node to represent the parameter, the datatype and identifier // must be children of the node. If no datatype or identifier is given @@ -3009,15 +3310,15 @@ void QAsCodeParser::ParseLambda() { // Skip 'const' for the next check sToken t1, t2 = t; if (t.type == ttConst) - GetToken(&t1); + getToken(&t1); // Determine the last identifier after scope in order to check if it is // a type - FindIdentifierAfterScope(t2); - RewindTo(&t); + findIdentifierAfterScope(t2); + rewindTo(&t); // Parse optional type before parameter name - if (IsDataType(t2) && CheckTemplateType(t2) && FindTokenAfterType(t) && + if (isDataType(t2) && checkTemplateType(t2) && findTokenAfterType(t) && (t.type == ttIdentifier || t.type == ttListSeparator || t.type == ttCloseParenthesis)) { // NOTE @@ -3037,57 +3338,57 @@ void QAsCodeParser::ParseLambda() { return; } - GetToken(&t); + getToken(&t); if (t.type == ttListSeparator) - GetToken(&t); + getToken(&t); else if (t.type != ttCloseParenthesis) { - RewindErrorTo(&t); + rewindErrorTo(&t); return; } } if (t.type != ttCloseParenthesis) { - RewindErrorTo(&t); + rewindErrorTo(&t); return; } // We should just find the end of the statement block here. The statements // will be parsed on request by the compiler once it starts the compilation. - SuperficiallyParseStatementBlock(); + superficiallyParseStatementBlock(); } -bool QAsCodeParser::FindTokenAfterType( +bool QAsCodeParser::findTokenAfterType( sToken &nextToken) { // Set a rewind point sToken t, t1; - GetToken(&t); + getToken(&t); // A type can start with a const t1 = t; if (t1.type == ttConst) - GetToken(&t1); + getToken(&t1); sToken t2; if (t1.type != ttAuto) { // The type may be initiated with the scope operator if (t1.type == ttScope) - GetToken(&t1); + getToken(&t1); // The type may be preceded with a multilevel scope - GetToken(&t2); + getToken(&t2); while (t1.type == ttIdentifier) { if (t2.type == ttScope) { - GetToken(&t1); - GetToken(&t2); + getToken(&t1); + getToken(&t2); continue; } else if (t2.type == ttLessThan) { // Template types can also be used as scope identifiers - RewindTo(&t2); - if (CheckTemplateType(t1)) { + rewindTo(&t2); + if (checkTemplateType(t1)) { sToken t3; - GetToken(&t3); + getToken(&t3); if (t3.type == ttScope) { - GetToken(&t1); - GetToken(&t2); + getToken(&t1); + getToken(&t2); continue; } } @@ -3095,69 +3396,69 @@ bool QAsCodeParser::FindTokenAfterType( break; } - RewindTo(&t2); + rewindTo(&t2); } // We don't validate if the identifier is an actual declared type at this // moment as it may wrongly identify the statement as a non-declaration if // the user typed the name incorrectly. The real type is validated in // ParseDeclaration where a proper error message can be given. - if (!IsRealType(t1.type) && t1.type != ttIdentifier && t1.type != ttAuto) { - RewindTo(&t); + if (!isRealType(t1.type) && t1.type != ttIdentifier && t1.type != ttAuto) { + rewindTo(&t); return false; } - if (!CheckTemplateType(t1)) { - RewindTo(&t); + if (!checkTemplateType(t1)) { + rewindTo(&t); return false; } // Object handles can be interleaved with the array brackets // Even though declaring variables with & is invalid we'll accept // it here to give an appropriate error message later - GetToken(&t2); + getToken(&t2); while (t2.type == ttHandle || t2.type == ttAmp || t2.type == ttOpenBracket) { if (t2.type == ttHandle) { // A handle can optionally be read-only sToken t3; - GetToken(&t3); + getToken(&t3); if (t3.type != ttConst) - RewindTo(&t3); + rewindTo(&t3); } else if (t2.type == ttOpenBracket) { - GetToken(&t2); + getToken(&t2); if (t2.type != ttCloseBracket) { - RewindTo(&t); + rewindTo(&t); return false; } } else if (t2.type == ttAmp) { // & can be followed by in, out, or inout sToken t3; - GetToken(&t3); + getToken(&t3); if (t3.type != ttIn && t3.type != ttOut && t3.type != ttInOut) - RewindTo(&t3); + rewindTo(&t3); } - GetToken(&t2); + getToken(&t2); } // Return the next token so the caller can jump directly to it if desired nextToken = t2; // Rewind to start point - RewindTo(&t); + rewindTo(&t); return true; } -bool QAsCodeParser::FindIdentifierAfterScope(sToken &nextToken) { +bool QAsCodeParser::findIdentifierAfterScope(sToken &nextToken) { sToken t1, t2, t3; // Determine the last identifier after scope in order to check if it is a // type - GetToken(&t1); - GetToken(&t2); - RewindTo(&t1); + getToken(&t1); + getToken(&t2); + rewindTo(&t1); if (t1.type != ttScope && t2.type != ttScope) { if (t1.type == ttIdentifier) { @@ -3171,23 +3472,23 @@ bool QAsCodeParser::FindIdentifierAfterScope(sToken &nextToken) { t3 = t2; else t3 = t1; - RewindTo(&t3); - GetToken(&t2); + rewindTo(&t3); + getToken(&t2); while (t3.type == ttIdentifier) { t2 = t3; - GetToken(&t3); + getToken(&t3); if (t3.type == ttScope) - GetToken(&t3); + getToken(&t3); else break; } - RewindTo(&t1); + rewindTo(&t1); nextToken = t2; return true; } -bool QAsCodeParser::IsConstant(int tokenType) { +bool QAsCodeParser::isConstant(int tokenType) { if (tokenType == ttIntConstant || tokenType == ttFloatConstant || tokenType == ttDoubleConstant || tokenType == ttStringConstant || tokenType == ttMultilineStringConstant || @@ -3199,7 +3500,7 @@ bool QAsCodeParser::IsConstant(int tokenType) { return false; } -bool QAsCodeParser::IsOperator(int tokenType) { +bool QAsCodeParser::isOperator(int tokenType) { if (tokenType == ttPlus || tokenType == ttMinus || tokenType == ttStar || tokenType == ttSlash || tokenType == ttPercent || tokenType == ttStarStar || tokenType == ttAnd || tokenType == ttOr || @@ -3215,7 +3516,7 @@ bool QAsCodeParser::IsOperator(int tokenType) { return false; } -bool QAsCodeParser::IsPreOperator(int tokenType) { +bool QAsCodeParser::isPreOperator(int tokenType) { if (tokenType == ttMinus || tokenType == ttPlus || tokenType == ttNot || tokenType == ttInc || tokenType == ttDec || tokenType == ttBitNot || tokenType == ttHandle) @@ -3223,7 +3524,7 @@ bool QAsCodeParser::IsPreOperator(int tokenType) { return false; } -bool QAsCodeParser::IsPostOperator(int tokenType) { +bool QAsCodeParser::isPostOperator(int tokenType) { if (tokenType == ttInc || // post increment tokenType == ttDec || // post decrement tokenType == ttDot || // member access @@ -3234,7 +3535,7 @@ bool QAsCodeParser::IsPostOperator(int tokenType) { return false; } -bool QAsCodeParser::IsAssignOperator(int tokenType) { +bool QAsCodeParser::isAssignOperator(int tokenType) { if (tokenType == ttAssignment || tokenType == ttAddAssign || tokenType == ttSubAssign || tokenType == ttMulAssign || tokenType == ttDivAssign || tokenType == ttModAssign || @@ -3247,67 +3548,67 @@ bool QAsCodeParser::IsAssignOperator(int tokenType) { return false; } -bool QAsCodeParser::DoesTypeExist(const QString &t) { +bool QAsCodeParser::typeExist(const QString &t) { Q_UNUSED(t); // TODO: don't check return true; } -bool QAsCodeParser::CheckTemplateType(const sToken &t) { +bool QAsCodeParser::checkTemplateType(const sToken &t) { // Is this a template type? tempString = getSymbolString(t); auto tstr = tempString; if (engine->IsTemplateType(tstr.data())) { // If the next token is a < then parse the sub-type too sToken t1; - GetToken(&t1); + getToken(&t1); if (t1.type != ttLessThan) { - RewindTo(&t1); + rewindTo(&t1); return true; } for (;;) { // There might optionally be a 'const' - GetToken(&t1); + getToken(&t1); if (t1.type == ttConst) - GetToken(&t1); + getToken(&t1); // The type may be initiated with the scope operator if (t1.type == ttScope) - GetToken(&t1); + getToken(&t1); // There may be multiple levels of scope operators sToken t2; - GetToken(&t2); + getToken(&t2); while (t1.type == ttIdentifier && t2.type == ttScope) { - GetToken(&t1); - GetToken(&t2); + getToken(&t1); + getToken(&t2); } - RewindTo(&t2); + rewindTo(&t2); // Now there must be a data type - if (!IsDataType(t1)) + if (!isDataType(t1)) return false; - if (!CheckTemplateType(t1)) + if (!checkTemplateType(t1)) return false; - GetToken(&t1); + getToken(&t1); // Is it a handle or array? while (t1.type == ttHandle || t1.type == ttOpenBracket) { if (t1.type == ttOpenBracket) { - GetToken(&t1); + getToken(&t1); if (t1.type != ttCloseBracket) return false; } else if (t1.type == ttHandle) { // after @ there can be a const - GetToken(&t1); + getToken(&t1); if (t1.type != ttConst) - RewindTo(&t1); + rewindTo(&t1); } - GetToken(&t1); + getToken(&t1); } // Was this the last template subtype? @@ -3329,28 +3630,28 @@ bool QAsCodeParser::CheckTemplateType(const sToken &t) { return true; } -sToken QAsCodeParser::ParseToken(int token) { +sToken QAsCodeParser::parseToken(int token) { sToken t1; - GetToken(&t1); + getToken(&t1); if (t1.type != token) { - RewindErrorTo(&t1); + rewindErrorTo(&t1); } return t1; } -sToken QAsCodeParser::ParseOneOf(int *tokens, int count) { +sToken QAsCodeParser::parseOneOf(int *tokens, int count) { sToken t1; - GetToken(&t1); + getToken(&t1); int n; for (n = 0; n < count; n++) { if (tokens[n] == t1.type) break; } if (n == count) { - RewindErrorTo(&t1); + rewindErrorTo(&t1); return t1; } diff --git a/src/class/qascodeparser.h b/src/class/qascodeparser.h index 11f590b..1c985fc 100644 --- a/src/class/qascodeparser.h +++ b/src/class/qascodeparser.h @@ -27,8 +27,7 @@ // This class is the modification of as_parser. // You can modified it to support more features. /** It's a complex thing to fully support AngelScript code intellisense. - ** I just support basic code completion like local or global - * variables/functions. + ** I just support basic code completion. ** If you are interested in implement a well-featured intellisense like * Qt creator or Visual Studio, PRs are welcomed !!! */ @@ -42,101 +41,115 @@ public: public: enum class SymbolType { Invalid, - FnDecl, - Import, - Value, // a common value - Variable, // a variable + Variable, // variable or property in class Enum, // an enum Class, // a class type Function, // a function TypeDef, // a typedef FnDef, // a funcdef - Property, // a property + VarsDecl, // global variable decalration }; enum class Visiblity { Public, Private, Protected }; - struct Symbol; - + /** + * @brief The CodeSegment class + */ struct CodeSegment { - bool valid = false; - // QByteArrayList ns; - QByteArray ret; - QByteArray name; - qsizetype nameInSrc = -1; - QList args; - QByteArray code; + QByteArrayList scope; + QString name; + SymbolType type = QAsCodeParser::SymbolType::Invalid; + int offset = -1; + QString codes; - bool isValid() const { return valid; } + QByteArrayList additonalInfos; // for other additonal infos + + public: + bool isValid() const { return type != SymbolType::Invalid; } + bool hasCodes() const { return !codes.isEmpty(); } }; struct Symbol { - SymbolType type = SymbolType::Invalid; + SymbolType symtype = QAsCodeParser::SymbolType::Invalid; + QByteArrayList scope; QString name; - qsizetype nameInSrc = -1; - QString typeStr; - Visiblity vis = Visiblity::Public; - QList content; + QByteArray type; + int offset = -1; + Visiblity vis = QAsCodeParser::Visiblity::Public; + QByteArray additonalInfo; // for other additonal info - // QByteArrayList ns; // namespaces - QMap codesegs; // used in class - - // size_t scope = 0; // 0 for all - - bool isValid() const { return type != SymbolType::Invalid; } + QList children; }; - using SymbolTable = QMap; - -private: - // QMap< offset , CodeSegment> - QMap m_segs; // global functions - public: - SymbolTable parse(const QByteArray &codes); + // First, we should parse and split the code into segments + QList parse(const QByteArray &codes); - SymbolTable parseIntell(qsizetype offset, const QByteArray &codes); + // Then, we can deep parsing for code completion + QList parseIntell(qsizetype offset, + const QList &segs); + + // so, a helper function? + QList parseAndIntell(qsizetype offset, const QByteArray &codes); private: - void ParseScript(bool inBlock); + QList parseScript(bool inBlock); + void appendValidSeg(QList &container, + QAsCodeParser::CodeSegment seg); + + void skipCodeBlock(); QByteArray getSymbolString(const sToken &t); - QByteArrayList getRealNamespace(const QByteArrayList &ns); + // Statements + sToken superficiallyParseVarInit(); + sToken superficiallyParseStatementBlock(); + void parseMethodAttributes(); + +private: + CodeSegment parseEnumeration(); + CodeSegment parseTypedef(); + CodeSegment parseClass(); + CodeSegment parseMixin(); + CodeSegment parseInterface(); + CodeSegment parseFuncDef(); + CodeSegment parseFunction(); + +private: // parse tokens - sToken ParseIdentifier(); - sToken ParseToken(int token); - sToken ParseRealType(); - sToken ParseDataType(bool allowVariableType = false, + sToken parseIdentifier(); + sToken parseToken(int token); + sToken parseRealType(); + sToken parseDataType(bool allowVariableType = false, bool allowAuto = false); - sToken ParseOneOf(int *tokens, int count); - sToken ParseType(bool allowConst, bool allowVariableType = false, + sToken parseOneOf(int *tokens, int count); + sToken parseType(bool allowConst, bool allowVariableType = false, bool allowAuto = false); - // Statements - sToken SuperficiallyParseVarInit(); + void parseNamespace(); - // parse and get symbols - Symbol ParseImport(); - void ParseEnumeration(); - void ParseTypedef(); - void ParseClass(); - void ParseMixin(); - void ParseInterface(); - Symbol ParseFuncDef(); - void ParseNamespace(); +private: + // deep parsing + void parseStatementBlock(); + void parseStatement(); + +private: + void parseEnumerationContent(); + void parseTypedefContent(); + void parseClassContent(); + void parseMixinContent(); + void parseInterfaceContent(); + Symbol parseFuncDefContent(); void ParseReturn(); void ParseBreak(); void ParseContinue(); void ParseTryCatch(); void ParseIf(); void ParseLambda(); - void ParseStatement(); - CodeSegment ParseFunction(bool isMethod = false); + CodeSegment parseFunction(bool isMethod); void ParseExpressionStatement(); void ParseListPattern(); - void ParseStatementBlock(); void ParseAssignment(); void ParseAssignOperator(); @@ -155,13 +168,12 @@ private: QByteArrayList ParseOptionalScope(); - Symbol ParseVirtualPropertyDecl(bool isMethod, bool isInterface); - QList ParseParameterList(); + Symbol parseVirtualPropertyDecl(bool isMethod, bool isInterface); + QList parseParameterListContent(); // parse but not get symbols void ParseTypeMod(bool isParam); void ParseFunctionCall(); - void SuperficiallyParseStatementBlock(); void ParseInitList(); void ParseCast(); void ParseVariableAccess(); @@ -169,49 +181,48 @@ private: void ParseConstant(); private: - void Reset(); + void reset(); - bool IsVarDecl(); - bool IsVirtualPropertyDecl(); - bool IsFuncDecl(bool isMethod); - bool IsLambda(); - bool IsFunctionCall(); + bool isVarDecl(); + bool isVirtualPropertyDecl(); + bool isFuncDecl(bool isMethod); + bool isLambda(); + bool isFunctionCall(); - void GetToken(sToken *token); - void RewindTo(const sToken *token); - void RewindErrorTo(sToken *token); + void getToken(sToken *token); + void rewindTo(const sToken *token); + void rewindErrorTo(sToken *token); void SetPos(size_t pos); - bool IsRealType(int tokenType); - bool IdentifierIs(const sToken &t, const char *str); - bool IsDataType(const sToken &token); + bool isRealType(int tokenType); + bool identifierIs(const sToken &t, const char *str); + bool isDataType(const sToken &token); private: - bool CheckTemplateType(const sToken &t); - bool ParseTemplTypeList(bool required = true); - void ParseMethodAttributes(); + bool checkTemplateType(const sToken &t); + bool parseTemplTypeList(bool required = true); - void ParseArgList(bool withParenthesis = true); + void parseArgList(bool withParenthesis = true); - void SuperficiallyParseExpression(); + void superficiallyParseExpression(); private: - bool FindTokenAfterType(sToken &nextToken); - bool FindIdentifierAfterScope(sToken &nextToken); - bool IsConstant(int tokenType); - bool IsOperator(int tokenType); - bool IsPreOperator(int tokenType); - bool IsPostOperator(int tokenType); - bool IsAssignOperator(int tokenType); + bool findTokenAfterType(sToken &nextToken); + bool findIdentifierAfterScope(sToken &nextToken); + bool isConstant(int tokenType); + bool isOperator(int tokenType); + bool isPreOperator(int tokenType); + bool isPostOperator(int tokenType); + bool isAssignOperator(int tokenType); - bool DoesTypeExist(const QString &t); + bool typeExist(const QString &t); - Symbol ParseFunctionDefinition(); + Symbol parseFunctionDefinition(); - QList ParseDeclaration(bool isClassProp = false, + QList parseDeclaration(bool isClassProp = false, bool isGlobalVar = false); - Symbol ParseInterfaceMethod(); + Symbol parseInterfaceMethod(); void ParseStringConstant(); @@ -224,13 +235,14 @@ private: asCScriptEngine *engine; // size_t _curscope = 0; - SymbolTable _symtable; QByteArray code; QByteArray tempString; // Used for reduzing amount of dynamic allocations sToken lastToken; size_t sourcePos; + + QByteArrayList currentNs; }; #endif // QASCODEPARSER_H diff --git a/src/class/scriptmachine.cpp b/src/class/scriptmachine.cpp index 21f8f5c..665cf8f 100644 --- a/src/class/scriptmachine.cpp +++ b/src/class/scriptmachine.cpp @@ -265,12 +265,12 @@ bool ScriptMachine::executeScript(const QString &script, bool isInDebug) { asBuilder builder(_engine); for (auto &m : PluginSystem::instance().scriptMarcos()) { - builder.DefineWord(m); + builder.defineWord(m); } // Set the pragma callback so we can detect - builder.SetPragmaCallback(&ScriptMachine::pragmaCallback, this); - builder.SetIncludeCallback(&ScriptMachine::includeCallback, this); + builder.setPragmaCallback(&ScriptMachine::pragmaCallback, this); + builder.setIncludeCallback(&ScriptMachine::includeCallback, this); // Compile the script auto r = builder.StartNewModule("script"); @@ -278,7 +278,7 @@ bool ScriptMachine::executeScript(const QString &script, bool isInDebug) { return false; } - r = builder.AddSectionFromFile(script.toUtf8()); + r = builder.loadSectionFromFile(script.toUtf8()); if (r < 0) { return false; } @@ -522,7 +522,7 @@ int ScriptMachine::pragmaCallback(const QByteArray &pragmaText, const QString §ionname, void *userParam) { Q_UNUSED(userParam); - asIScriptEngine *engine = builder->GetEngine(); + asIScriptEngine *engine = builder->getEngine(); // Filter the pragmaText so only what is of interest remains // With this the user can add comments and use different whitespaces @@ -589,7 +589,7 @@ int ScriptMachine::includeCallback(const QString &include, bool quotedInclude, inc += QStringLiteral(".as"); } - return builder->AddSectionFromFile(inc); + return builder->loadSectionFromFile(inc); } QString ScriptMachine::processTranslation(const char *content, diff --git a/src/dialog/mainwindow.cpp b/src/dialog/mainwindow.cpp index 2f49276..a4dc62b 100644 --- a/src/dialog/mainwindow.cpp +++ b/src/dialog/mainwindow.cpp @@ -724,25 +724,40 @@ MainWindow::buildUpNumberShowDock(ads::CDockManager *dock, actionGroup->setExclusive(true); auto le = Utilities::checkIsLittleEndian(); - m_littleEndian = new QAction(actionGroup); - m_littleEndian->setText(tr("LittleEndian")); - m_littleEndian->setCheckable(true); - m_littleEndian->setChecked(le); - connect(m_littleEndian, &QAction::triggered, this, [=] { + auto aLittleEndian = new QAction(actionGroup); + aLittleEndian->setText(tr("LittleEndian")); + aLittleEndian->setCheckable(true); + aLittleEndian->setChecked(le); + connect(aLittleEndian, &QAction::triggered, this, [=] { m_islittle = true; this->on_locChanged(); }); - m_numshowtable->addAction(m_littleEndian); + m_numshowtable->addAction(aLittleEndian); - m_bigEndian = new QAction(actionGroup); - m_bigEndian->setText(tr("BigEndian")); - m_bigEndian->setCheckable(true); - m_bigEndian->setChecked(!le); - connect(m_bigEndian, &QAction::triggered, this, [=] { + auto aBigEndian = new QAction(actionGroup); + aBigEndian->setText(tr("BigEndian")); + aBigEndian->setCheckable(true); + aBigEndian->setChecked(!le); + connect(aBigEndian, &QAction::triggered, this, [=] { m_islittle = false; this->on_locChanged(); }); - m_numshowtable->addAction(m_bigEndian); + m_numshowtable->addAction(aBigEndian); + + a = new QAction(this); + a->setSeparator(true); + m_numshowtable->addAction(a); + + auto aUnsignedHex = new QAction(this); + aUnsignedHex->setText(tr("UnsignedHex")); + aUnsignedHex->setCheckable(true); + aUnsignedHex->setChecked(false); + connect(aUnsignedHex, &QAction::toggled, this, [=](bool b) { + m_unsignedHex = b; + this->on_locChanged(); + }); + m_numshowtable->addAction(aUnsignedHex); + m_numshowtable->setContextMenuPolicy( Qt::ContextMenuPolicy::ActionsContextMenu); @@ -2834,7 +2849,9 @@ void MainWindow::on_locChanged() { auto s = processEndian(n); _numsitem->setNumData( NumShowModel::NumTableIndex::Uint64, - QStringLiteral("0x%1").arg(QString::number(s, 16).toUpper())); + m_unsignedHex + ? QStringLiteral("0x%1").arg(QString::number(s, 16).toUpper()) + : QString::number(s)); auto s1 = processEndian(qsizetype(n)); _numsitem->setNumData(NumShowModel::NumTableIndex::Int64, QString::number(s1)); @@ -2853,7 +2870,9 @@ void MainWindow::on_locChanged() { auto s = processEndian(quint32(n)); _numsitem->setNumData( NumShowModel::NumTableIndex::Uint32, - QStringLiteral("0x%1").arg(QString::number(s, 16).toUpper())); + m_unsignedHex + ? QStringLiteral("0x%1").arg(QString::number(s, 16).toUpper()) + : QString::number(s)); auto s1 = processEndian(qint32(n)); _numsitem->setNumData(NumShowModel::NumTableIndex::Int32, QString::number(s1)); @@ -2872,7 +2891,9 @@ void MainWindow::on_locChanged() { auto s = processEndian(quint16(n)); _numsitem->setNumData( NumShowModel::NumTableIndex::Ushort, - QStringLiteral("0x%1").arg(QString::number(s, 16).toUpper())); + m_unsignedHex + ? QStringLiteral("0x%1").arg(QString::number(s, 16).toUpper()) + : QString::number(s)); auto s1 = processEndian(qint16(n)); _numsitem->setNumData(NumShowModel::NumTableIndex::Short, QString::number(s1)); @@ -2885,7 +2906,9 @@ void MainWindow::on_locChanged() { auto s = uchar(s1); _numsitem->setNumData( NumShowModel::NumTableIndex::Byte, - QStringLiteral("0x%1").arg(QString::number(s, 16).toUpper())); + m_unsignedHex + ? QStringLiteral("0x%1").arg(QString::number(s, 16).toUpper()) + : QString::number(s)); _numsitem->setNumData(NumShowModel::NumTableIndex::Char, QString::number(s1)); } else { diff --git a/src/dialog/mainwindow.h b/src/dialog/mainwindow.h index aa09643..50a4317 100644 --- a/src/dialog/mainwindow.h +++ b/src/dialog/mainwindow.h @@ -555,9 +555,6 @@ private: QLabel *m_lblsellen = nullptr; QStatusBar *m_status = nullptr; - QAction *m_littleEndian = nullptr; - QAction *m_bigEndian = nullptr; - QAction *m_aShowMetafg = nullptr; QAction *m_aShowMetabg = nullptr; QAction *m_aShowMetaComment = nullptr; @@ -603,9 +600,6 @@ private: QString m_lastusedpath; bool m_islittle = true; - bool m_enablePlugin = true; - - // Guard against recursion - bool _isHandlingEvent = false; + bool m_unsignedHex = false; }; #endif // MAINWINDOW_H