diff --git a/PluginCommon/Interfaces.cs b/PluginCommon/Interfaces.cs
index ff2b347..05dde90 100644
--- a/PluginCommon/Interfaces.cs
+++ b/PluginCommon/Interfaces.cs
@@ -29,7 +29,7 @@ namespace PluginCommon {
string Identifier { get; }
///
- /// Prepares the plugin for action. Called at the start of the code analysis pass.
+ /// Prepares the plugin for action. Called at the start of every code analysis pass.
///
/// In the current implementation, the file data will be the same every time,
/// because it doesn't change after the project is opened. However, this could
@@ -38,11 +38,44 @@ namespace PluginCommon {
/// Reference to application interface.
/// 65xx code and data.
/// Mapping between offsets and addresses.
- /// Symbols available to plugins, in no particular order. All
- /// platform, project, and user labels are included; auto-generated symbols and
- /// local variables are not.
- void Prepare(IApplication appRef, byte[] fileData, AddressTranslate addrTrans,
- List plSyms);
+ void Prepare(IApplication appRef, byte[] fileData, AddressTranslate addrTrans);
+ }
+
+ ///
+ /// Extension scripts that want to receive the list of symbols must implement this interface.
+ ///
+ public interface IPlugin_SymbolList {
+ ///
+ /// Receives a list of the currently defined platform, project, and user symbols.
+ /// The list does not include auto-generated labels or local variables.
+ ///
+ /// This is called immediately after Prepare(), before any other interfaces are
+ /// invoked, at the start of every code analysis pass.
+ ///
+ /// Symbols available to plugins, in no particular order.
+ void UpdateSymbolList(List plSyms);
+
+ ///
+ /// Handles a notification that a user symbol has been added, edited, or removed. If the
+ /// label is of interest to the plugin, e.g. it changes how the plugin formats code or
+ /// data, the app needs to know.
+ ///
+ ///
+ /// The application does a full re-analysis when project properties change, but not
+ /// when labels are edited. The CheckJsr/Jsl/Brk methods are only called during code
+ /// analysis, so if their behavior changes based on the presence or absence of a user
+ /// label then we need to tell the application that a full re-analysis is needed.
+ ///
+ /// Plugins that don't care about user symbols, e.g. that just use tagged platform
+ /// symbols, can simply return false. (Changes to user labels that overlap with
+ /// project/platform symbols are detected by the app.)
+ ///
+ /// The label before the change, or empty if this is a
+ /// newly-added label.
+ /// The label after the change, or empty if the label was
+ /// removed.
+ /// True if the label change could affect the plugin's actions.
+ bool IsLabelSignificant(string beforeLabel, string afterLabel);
}
///
@@ -128,6 +161,9 @@ namespace PluginCommon {
///
/// Data format type.
///
+ ///
+ /// Essentially a clone of FormatDescriptor.Type.
+ ///
public enum DataType {
Unknown = 0,
NumericLE,
@@ -145,6 +181,9 @@ namespace PluginCommon {
///
/// Data format sub-type.
///
+ ///
+ /// Essentially a clone of FormatDescriptor.SubType.
+ ///
public enum DataSubType {
// No sub-type specified.
None = 0,
diff --git a/PluginCommon/PluginManager.cs b/PluginCommon/PluginManager.cs
index bbee8df..dba75db 100644
--- a/PluginCommon/PluginManager.cs
+++ b/PluginCommon/PluginManager.cs
@@ -154,15 +154,37 @@ namespace PluginCommon {
/// Invokes the Prepare() method on all active plugins.
///
/// Reference to host object providing app services.
+ /// Serialized AddressMap entries.
+ /// SymbolTable contents, converted to PlSymbol.
public void PreparePlugins(IApplication appRef,
List addrEntries, List plSyms) {
AddressMap addrMap = new AddressMap(addrEntries);
AddressTranslate addrTrans = new AddressTranslate(addrMap);
foreach (KeyValuePair kvp in mActivePlugins) {
- kvp.Value.Prepare(appRef, mFileData, addrTrans, plSyms);
+ IPlugin ipl = kvp.Value;
+ ipl.Prepare(appRef, mFileData, addrTrans);
+ if (ipl is IPlugin_SymbolList) {
+ ((IPlugin_SymbolList)ipl).UpdateSymbolList(plSyms);
+ }
}
}
+ ///
+ /// Returns true if any of the plugins report that the before or after label is
+ /// significant.
+ ///
+ public bool IsLabelSignificant(string labelBefore, string labelAfter) {
+ foreach (KeyValuePair kvp in mActivePlugins) {
+ IPlugin ipl = kvp.Value;
+ if (ipl is IPlugin_SymbolList &&
+ ((IPlugin_SymbolList)ipl).IsLabelSignificant(labelBefore,
+ labelAfter)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
#if false
///
/// DEBUG ONLY: establish a fast lease timeout. Normally the lease
diff --git a/SourceGen/DisasmProject.cs b/SourceGen/DisasmProject.cs
index 7b5b639..eda1c95 100644
--- a/SourceGen/DisasmProject.cs
+++ b/SourceGen/DisasmProject.cs
@@ -1970,6 +1970,16 @@ namespace SourceGen {
// to do the refactor here, though we can skip Anattribs work.
Debug.Assert(oldValue == null || newValue == null);
}
+
+ // For add/edit/remove, we need to see if what we do will impact
+ // the behavior of a plugin. We don't need to do this on
+ // project/platform symbol changes because project property changes
+ // always update code and data.
+ if (mScriptManager.IsLabelSignificant((Symbol)oldValue,
+ (Symbol)newValue)) {
+ Debug.WriteLine("Plugin claims symbol is significant");
+ needReanalysis |= UndoableChange.ReanalysisScope.CodeAndData;
+ }
}
break;
case UndoableChange.ChangeType.SetOperandFormat: {
diff --git a/SourceGen/Examples/Scripts/InlineL1String.cs b/SourceGen/Examples/Scripts/InlineL1String.cs
new file mode 100644
index 0000000..5ff0212
--- /dev/null
+++ b/SourceGen/Examples/Scripts/InlineL1String.cs
@@ -0,0 +1,74 @@
+// Copyright 2019 faddenSoft. All Rights Reserved.
+// See the LICENSE.txt file for distribution terms (Apache 2.0).
+
+using System;
+using System.Collections.Generic;
+
+using PluginCommon;
+
+namespace ExtensionScriptSample {
+ ///
+ /// Sample class for handling a JSR followed by a string prefixed with a 1-byte length.
+ ///
+ public class InlineL1String: MarshalByRefObject, IPlugin, IPlugin_SymbolList,
+ IPlugin_InlineJsr {
+ private IApplication mAppRef;
+ private byte[] mFileData;
+
+ // Only one call.
+ private const string CALL_LABEL = "PrintInlineL1String";
+ private int mInlineL1StringAddr; // jsr
+
+ public string Identifier {
+ get {
+ return "Inline L1 ASCII string handler";
+ }
+ }
+
+ public void Prepare(IApplication appRef, byte[] fileData, AddressTranslate addrTrans) {
+ mAppRef = appRef;
+ mFileData = fileData;
+
+ mAppRef.DebugLog("InlineL1String(id=" +
+ AppDomain.CurrentDomain.Id + "): prepare()");
+ }
+
+ public void UpdateSymbolList(List plSyms) {
+ // reset this every time, in case they remove the symbol
+ mInlineL1StringAddr = -1;
+
+ foreach (PlSymbol sym in plSyms) {
+ if (sym.Label == CALL_LABEL) {
+ mInlineL1StringAddr = sym.Value;
+ break;
+ }
+ }
+ mAppRef.DebugLog(CALL_LABEL + " @ $" + mInlineL1StringAddr.ToString("x6"));
+ }
+ public bool IsLabelSignificant(string beforeLabel, string afterLabel) {
+ return beforeLabel == CALL_LABEL || afterLabel == CALL_LABEL;
+ }
+
+ public void CheckJsr(int offset, out bool noContinue) {
+ noContinue = false;
+ int target = Util.GetWord(mFileData, offset + 1, 2, false);
+ if (target != mInlineL1StringAddr) {
+ return;
+ }
+ if (offset + 3 >= mFileData.Length) {
+ return; // length byte is off end
+ }
+ int len = mFileData[3]; // first byte past JSR
+ if (offset + 4 + len > mFileData.Length) {
+ mAppRef.DebugLog("L1 string ran off end of file at +" +
+ (offset + 4).ToString("x6"));
+ return;
+ }
+
+ // Assuming ASCII. This can be hard-coded, use auto-detection, or look
+ // up a value in a project constant.
+ mAppRef.SetInlineDataFormat(offset + 3, len + 1,
+ DataType.StringL8, DataSubType.Ascii, null);
+ }
+ }
+}
diff --git a/SourceGen/Examples/Scripts/InlineNullTerm.cs b/SourceGen/Examples/Scripts/InlineNullTerm.cs
deleted file mode 100644
index 30431ba..0000000
--- a/SourceGen/Examples/Scripts/InlineNullTerm.cs
+++ /dev/null
@@ -1,69 +0,0 @@
-// Copyright 2019 faddenSoft. All Rights Reserved.
-// See the LICENSE.txt file for distribution terms (Apache 2.0).
-
-using System;
-using System.Collections.Generic;
-
-using PluginCommon;
-
-namespace ExtensionScriptSample {
- ///
- /// Sample class for handling a JSR followed by an inline null-terminated string.
- ///
- public class InlineNullStringHandler : MarshalByRefObject, IPlugin, IPlugin_InlineJsr {
- private IApplication mAppRef;
- private byte[] mFileData;
-
- private int mInlineNullStringAddr; // jsr
-
- public string Identifier {
- get {
- return "Inline null-terminated ASCII string handler";
- }
- }
-
- public void Prepare(IApplication appRef, byte[] fileData, AddressTranslate addrTrans,
- List plSyms) {
- mAppRef = appRef;
- mFileData = fileData;
-
- mAppRef.DebugLog("InlineNullStringHandler(id=" +
- AppDomain.CurrentDomain.Id + "): prepare()");
-
- // reset this every time, in case they remove the label
- mInlineNullStringAddr = -1;
- foreach (PlSymbol sym in plSyms) {
- if (sym.Label == "PrintInlineZString") {
- mInlineNullStringAddr = sym.Value;
- break;
- }
- }
- mAppRef.DebugLog("PrintInlineZString @ $" + mInlineNullStringAddr.ToString("x6"));
- }
-
- public void CheckJsr(int offset, out bool noContinue) {
- noContinue = false;
- int target = Util.GetWord(mFileData, offset + 1, 2, false);
- if (target == mInlineNullStringAddr) {
- // search for the terminating null byte
- int nullOff = offset + 3;
- while (nullOff < mFileData.Length) {
- if (mFileData[nullOff] == 0) {
- break;
- }
- nullOff++;
- }
- if (nullOff == mFileData.Length) {
- mAppRef.DebugLog("Unable to find end of null-terminated string at +" +
- (offset+3).ToString("x6"));
- return;
- }
-
- // Assuming ASCII. This can be hard-coded, use auto-detection, or look
- // up a value in a project constant.
- mAppRef.SetInlineDataFormat(offset + 3, nullOff - (offset + 3) + 1,
- DataType.StringNullTerm, DataSubType.Ascii, null);
- }
- }
- }
-}
diff --git a/SourceGen/Examples/Scripts/InlineNullTermString.cs b/SourceGen/Examples/Scripts/InlineNullTermString.cs
new file mode 100644
index 0000000..e5453ee
--- /dev/null
+++ b/SourceGen/Examples/Scripts/InlineNullTermString.cs
@@ -0,0 +1,77 @@
+// Copyright 2019 faddenSoft. All Rights Reserved.
+// See the LICENSE.txt file for distribution terms (Apache 2.0).
+
+using System;
+using System.Collections.Generic;
+
+using PluginCommon;
+
+namespace ExtensionScriptSample {
+ ///
+ /// Sample class for handling a JSR followed by an inline null-terminated string. Any
+ /// label that starts with "PrintLineNullString" is matched.
+ ///
+ public class InlineNullTermString : MarshalByRefObject, IPlugin, IPlugin_SymbolList,
+ IPlugin_InlineJsr {
+ private IApplication mAppRef;
+ private byte[] mFileData;
+
+ private const string LABEL_PREFIX = "PrintInlineNullString";
+ private Dictionary mNullStringAddrs = new Dictionary();
+
+ public string Identifier {
+ get {
+ return "Inline null-terminated ASCII string handler";
+ }
+ }
+
+ public void Prepare(IApplication appRef, byte[] fileData, AddressTranslate addrTrans) {
+ mAppRef = appRef;
+ mFileData = fileData;
+
+ mAppRef.DebugLog("InlineNullStringHandler(id=" +
+ AppDomain.CurrentDomain.Id + "): prepare()");
+ }
+
+ public void UpdateSymbolList(List plSyms) {
+ mNullStringAddrs.Clear();
+
+ foreach (PlSymbol sym in plSyms) {
+ if (sym.Label.StartsWith(LABEL_PREFIX)) {
+ mNullStringAddrs.Add(sym.Value, sym);
+ }
+ }
+ mAppRef.DebugLog(LABEL_PREFIX + " matched " + mNullStringAddrs.Count + " labels");
+ }
+ public bool IsLabelSignificant(string beforeLabel, string afterLabel) {
+ return beforeLabel.StartsWith(LABEL_PREFIX) || afterLabel.StartsWith(LABEL_PREFIX);
+ }
+
+ public void CheckJsr(int offset, out bool noContinue) {
+ noContinue = false;
+ int target = Util.GetWord(mFileData, offset + 1, 2, false);
+ if (!mNullStringAddrs.ContainsKey(target)) {
+ return;
+ }
+
+ // search for the terminating null byte
+ int nullOff = offset + 3;
+ while (nullOff < mFileData.Length) {
+ if (mFileData[nullOff] == 0) {
+ break;
+ }
+ nullOff++;
+ }
+ if (nullOff == mFileData.Length) {
+ mAppRef.DebugLog("Unable to find end of null-terminated string at +" +
+ (offset+3).ToString("x6"));
+ return;
+ }
+
+ // Assuming ASCII. This can be hard-coded, use auto-detection, or look
+ // up a value in a project constant.
+ mAppRef.SetInlineDataFormat(offset + 3, nullOff - (offset + 3) + 1,
+ DataType.StringNullTerm, DataSubType.Ascii, null);
+ }
+ }
+}
diff --git a/SourceGen/Examples/Scripts/Sample b/SourceGen/Examples/Scripts/Sample
index 4f43070..c8968a9 100644
Binary files a/SourceGen/Examples/Scripts/Sample and b/SourceGen/Examples/Scripts/Sample differ
diff --git a/SourceGen/Examples/Scripts/Sample.S b/SourceGen/Examples/Scripts/Sample.S
index 9ddddb2..8c2f85a 100644
--- a/SourceGen/Examples/Scripts/Sample.S
+++ b/SourceGen/Examples/Scripts/Sample.S
@@ -1,8 +1,18 @@
org $1000
- jsr PrintInlineZString
- asc 'Testing',00
+ jsr PrintInlineL1String
+ str 'How long?'
+
+ jsr PrintInlineZString1
+ asc 'Test one',00
+
+ jsr PrintInlineZString2
+ asc 'Test two',00
rts
-PrintInlineZString
+PrintInlineL1String
+ rts
+PrintInlineZString1
+ rts
+PrintInlineZString2
rts
diff --git a/SourceGen/Examples/Scripts/Sample.dis65 b/SourceGen/Examples/Scripts/Sample.dis65
index e63fc3e..0f7e6d2 100644
--- a/SourceGen/Examples/Scripts/Sample.dis65
+++ b/SourceGen/Examples/Scripts/Sample.dis65
@@ -1,9 +1,9 @@
### 6502bench SourceGen dis65 v1.0 ###
{
-"_ContentVersion":2,"FileDataLength":13,"FileDataCrc32":205674068,"ProjectProps":{
-"CpuName":"65816","IncludeUndocumentedInstr":false,"EntryFlags":32702671,"AutoLabelStyle":"Simple","AnalysisParams":{
+"_ContentVersion":2,"FileDataLength":41,"FileDataCrc32":-1863359703,"ProjectProps":{
+"CpuName":"6502","IncludeUndocumentedInstr":false,"TwoByteBrk":false,"EntryFlags":32702671,"AutoLabelStyle":"Simple","AnalysisParams":{
"AnalyzeUncategorizedData":true,"DefaultTextScanMode":"LowHighAscii","MinCharsForString":4,"SeekNearbyTargets":true,"SmartPlpHandling":true},
-"PlatformSymbolFileIdentifiers":[],"ExtensionScriptFileIdentifiers":["PROJ:InlineNullTerm.cs"],"ProjectSyms":{
+"PlatformSymbolFileIdentifiers":[],"ExtensionScriptFileIdentifiers":["PROJ:InlineL1String.cs","PROJ:InlineNullTermString.cs"],"ProjectSyms":{
}},
"AddressMap":[{
"Offset":0,"Addr":4096}],"TypeHints":[{
@@ -16,8 +16,12 @@
"Notes":{
},
"UserLabels":{
-"12":{
-"Label":"PrintInlineZString","Value":4108,"Source":"User","Type":"LocalOrGlobalAddr"}},
+"38":{
+"Label":"PrintInlineL1String","Value":4134,"Source":"User","Type":"LocalOrGlobalAddr"},
+"39":{
+"Label":"PrintInlineNullString1","Value":4135,"Source":"User","Type":"LocalOrGlobalAddr"},
+"40":{
+"Label":"PrintInlineNullString2","Value":4136,"Source":"User","Type":"LocalOrGlobalAddr"}},
"OperandFormats":{
},
"LvTables":{
diff --git a/SourceGen/RuntimeData/Apple/GSOS.cs b/SourceGen/RuntimeData/Apple/GSOS.cs
index 57ffa15..ce3a96d 100644
--- a/SourceGen/RuntimeData/Apple/GSOS.cs
+++ b/SourceGen/RuntimeData/Apple/GSOS.cs
@@ -34,7 +34,7 @@ using PluginCommon;
*/
namespace RuntimeData.Apple {
- public class GSOS : MarshalByRefObject, IPlugin, IPlugin_InlineJsl {
+ public class GSOS : MarshalByRefObject, IPlugin, IPlugin_SymbolList, IPlugin_InlineJsl {
private const string GSOS_FUNC_TAG = "AppleIIgs-GSOS-Functions"; // tag used in .sym65 file
private bool VERBOSE = false;
@@ -48,15 +48,21 @@ namespace RuntimeData.Apple {
}
}
- public void Prepare(IApplication appRef, byte[] fileData, AddressTranslate addrTrans,
- List plSyms) {
+ public void Prepare(IApplication appRef, byte[] fileData, AddressTranslate addrTrans) {
mAppRef = appRef;
mFileData = fileData;
mAppRef.DebugLog("GSOS(id=" + AppDomain.CurrentDomain.Id + "): prepare()");
//System.Diagnostics.Debugger.Break();
- mFunctionList = PlSymbol.GeneratePlatformValueList(plSyms, GSOS_FUNC_TAG, appRef);
+ }
+
+ public void UpdateSymbolList(List plSyms) {
+ // Extract the list of function name constants from the platform symbol file.
+ mFunctionList = PlSymbol.GeneratePlatformValueList(plSyms, GSOS_FUNC_TAG, mAppRef);
+ }
+ public bool IsLabelSignificant(string beforeLabel, string afterLabel) {
+ return false;
}
public void CheckJsl(int offset, out bool noContinue) {
diff --git a/SourceGen/RuntimeData/Apple/IIgs-Toolbox.cs b/SourceGen/RuntimeData/Apple/IIgs-Toolbox.cs
index 4556ca9..744b04c 100644
--- a/SourceGen/RuntimeData/Apple/IIgs-Toolbox.cs
+++ b/SourceGen/RuntimeData/Apple/IIgs-Toolbox.cs
@@ -27,8 +27,8 @@ using PluginCommon;
*/
namespace RuntimeData.Apple {
- public class IIgsToolbox : MarshalByRefObject, IPlugin, IPlugin_InlineJsl {
- private const string TOOLBOX_FUNC_TAG = "AppleIIgs-Toolbox-Functions"; // tag used in .sym65 file
+ public class IIgsToolbox : MarshalByRefObject, IPlugin, IPlugin_SymbolList, IPlugin_InlineJsl {
+ private const string TOOLBOX_FUNC_TAG = "AppleIIgs-Toolbox-Functions"; // tag used in .sym65 file
private bool VERBOSE = false;
private IApplication mAppRef;
@@ -41,14 +41,19 @@ namespace RuntimeData.Apple {
}
}
- public void Prepare(IApplication appRef, byte[] fileData, AddressTranslate addrTrans,
- List plSyms) {
+ public void Prepare(IApplication appRef, byte[] fileData, AddressTranslate addrTrans) {
mAppRef = appRef;
mFileData = fileData;
mAppRef.DebugLog("IIgsToolbox(id=" + AppDomain.CurrentDomain.Id + "): prepare()");
+ }
- mFunctionList = PlSymbol.GeneratePlatformValueList(plSyms, TOOLBOX_FUNC_TAG, appRef);
+ public void UpdateSymbolList(List plSyms) {
+ // Extract the list of function name constants from the platform symbol file.
+ mFunctionList = PlSymbol.GeneratePlatformValueList(plSyms, TOOLBOX_FUNC_TAG, mAppRef);
+ }
+ public bool IsLabelSignificant(string beforeLabel, string afterLabel) {
+ return false;
}
public void CheckJsl(int offset, out bool noContinue) {
diff --git a/SourceGen/RuntimeData/Apple/ProDOS8.cs b/SourceGen/RuntimeData/Apple/ProDOS8.cs
index 806f0e0..696dac5 100644
--- a/SourceGen/RuntimeData/Apple/ProDOS8.cs
+++ b/SourceGen/RuntimeData/Apple/ProDOS8.cs
@@ -29,7 +29,7 @@ parm_block
*/
namespace RuntimeData.Apple {
- public class ProDOS8 : MarshalByRefObject, IPlugin, IPlugin_InlineJsr {
+ public class ProDOS8 : MarshalByRefObject, IPlugin, IPlugin_SymbolList, IPlugin_InlineJsr {
private const string P8_MLI_TAG = "ProDOS8-MLI-Functions"; // tag used in .sym65 file
private bool VERBOSE = false;
@@ -161,8 +161,7 @@ namespace RuntimeData.Apple {
}
}
- public void Prepare(IApplication appRef, byte[] fileData, AddressTranslate addrTrans,
- List plSyms) {
+ public void Prepare(IApplication appRef, byte[] fileData, AddressTranslate addrTrans) {
mAppRef = appRef;
mFileData = fileData;
mAddrTrans = addrTrans;
@@ -170,8 +169,13 @@ namespace RuntimeData.Apple {
mAppRef.DebugLog("ProDOS(id=" + AppDomain.CurrentDomain.Id + "): prepare()");
//System.Diagnostics.Debugger.Break();
+ }
+ public void UpdateSymbolList(List plSyms) {
// Extract the list of function name constants from the platform symbol file.
- mFunctionList = PlSymbol.GeneratePlatformValueList(plSyms, P8_MLI_TAG, appRef);
+ mFunctionList = PlSymbol.GeneratePlatformValueList(plSyms, P8_MLI_TAG, mAppRef);
+ }
+ public bool IsLabelSignificant(string beforeLabel, string afterLabel) {
+ return false;
}
public void CheckJsr(int offset, out bool noContinue) {
diff --git a/SourceGen/RuntimeData/Apple/SOS.cs b/SourceGen/RuntimeData/Apple/SOS.cs
index 187892a..93eb325 100644
--- a/SourceGen/RuntimeData/Apple/SOS.cs
+++ b/SourceGen/RuntimeData/Apple/SOS.cs
@@ -29,7 +29,7 @@ parm_block
*/
namespace RuntimeData.Apple {
- public class SOS : MarshalByRefObject, IPlugin, IPlugin_InlineBrk {
+ public class SOS : MarshalByRefObject, IPlugin, IPlugin_SymbolList, IPlugin_InlineBrk {
private const string SOS_MLI_TAG = "SOS-MLI-Functions"; // tag used in .sym65 file
private bool VERBOSE = true;
@@ -43,15 +43,20 @@ namespace RuntimeData.Apple {
}
}
- public void Prepare(IApplication appRef, byte[] fileData, AddressTranslate addrTrans,
- List plSyms) {
+ public void Prepare(IApplication appRef, byte[] fileData, AddressTranslate addrTrans) {
mAppRef = appRef;
mFileData = fileData;
mAppRef.DebugLog("SOS(id=" + AppDomain.CurrentDomain.Id + "): prepare()");
//System.Diagnostics.Debugger.Break();
+ }
- mFunctionList = PlSymbol.GeneratePlatformValueList(plSyms, SOS_MLI_TAG, appRef);
+ public void UpdateSymbolList(List plSyms) {
+ // Extract the list of function name constants from the platform symbol file.
+ mFunctionList = PlSymbol.GeneratePlatformValueList(plSyms, SOS_MLI_TAG, mAppRef);
+ }
+ public bool IsLabelSignificant(string beforeLabel, string afterLabel) {
+ return false;
}
public void CheckBrk(int offset, bool twoByteBrk, out bool noContinue) {
diff --git a/SourceGen/RuntimeData/Help/advanced.html b/SourceGen/RuntimeData/Help/advanced.html
index 6315e47..e1f9c3a 100644
--- a/SourceGen/RuntimeData/Help/advanced.html
+++ b/SourceGen/RuntimeData/Help/advanced.html
@@ -115,13 +115,6 @@ invoked is not defined.
Known Issues and Limitations
-Sometimes a manual refresh (F5) is required. Plugins are executed during
-the code analysis pass, but SourceGen doesn't perform code analysis on
-every change. If you add or change a label that a plugin is looking
-for, you won't see the effects until you do something that causes the
-code analysis pass to be run. Hitting F5 does this. (There's no easy
-way around this -- either we have to re-run code analysis on every label
-change, or we need a way to know which labels a plugin is interested in.)
When a project is opened, any errors encountered by the script compiler
are reported to the user. If the project is already open, and a script
is added to the project through the Project Properties editor, compiler
diff --git a/SourceGen/SGTestData/2011-hinting.cs b/SourceGen/SGTestData/2011-hinting.cs
index 34837c8..8889c05 100644
--- a/SourceGen/SGTestData/2011-hinting.cs
+++ b/SourceGen/SGTestData/2011-hinting.cs
@@ -17,8 +17,7 @@ namespace RuntimeData.Test2011 {
}
}
- public void Prepare(IApplication appRef, byte[] fileData, AddressTranslate addrTrans,
- List plSyms) {
+ public void Prepare(IApplication appRef, byte[] fileData, AddressTranslate addrTrans) {
mAppRef = appRef;
mFileData = fileData;
diff --git a/SourceGen/SGTestData/2022-extension-scripts-a.cs b/SourceGen/SGTestData/2022-extension-scripts-a.cs
index 9ab8639..fbeefc5 100644
--- a/SourceGen/SGTestData/2022-extension-scripts-a.cs
+++ b/SourceGen/SGTestData/2022-extension-scripts-a.cs
@@ -7,7 +7,8 @@ using System.Collections.Generic;
using PluginCommon;
namespace RuntimeData.Test2022 {
- public class Test2022A : MarshalByRefObject, IPlugin, IPlugin_InlineJsr, IPlugin_InlineJsl {
+ public class Test2022A : MarshalByRefObject, IPlugin, IPlugin_SymbolList,
+ IPlugin_InlineJsr, IPlugin_InlineJsl {
private IApplication mAppRef;
private byte[] mFileData;
@@ -24,13 +25,13 @@ namespace RuntimeData.Test2022 {
}
}
- public void Prepare(IApplication appRef, byte[] fileData, AddressTranslate addrTrans,
- List plSyms) {
+ public void Prepare(IApplication appRef, byte[] fileData, AddressTranslate addrTrans) {
mAppRef = appRef;
mFileData = fileData;
mAppRef.DebugLog("Test2022-A(id=" + AppDomain.CurrentDomain.Id + "): prepare()");
-
+ }
+ public void UpdateSymbolList(List plSyms) {
foreach (PlSymbol sym in plSyms) {
switch (sym.Label) {
case "PrintInline8String":
@@ -55,6 +56,11 @@ namespace RuntimeData.Test2022 {
}
}
+ public bool IsLabelSignificant(string beforeLabel, string afterLabel) {
+ const string PREFIX = "PrintInline"; // all interesting labels start with this
+ return (beforeLabel.StartsWith(PREFIX) || afterLabel.StartsWith(PREFIX));
+ }
+
public void CheckJsr(int offset, out bool noContinue) {
noContinue = false;
int target = Util.GetWord(mFileData, offset + 1, 2, false);
@@ -99,6 +105,9 @@ namespace RuntimeData.Test2022 {
if (target == mInlineL1StringAddr) {
// 0 1 2 3 4 5
// 22 00 10 01 01 66
+ if (offset + 4 >= mFileData.Length) {
+ return; // length byte is off end
+ }
int len = mFileData[offset + 4]; // 1-byte len in first byte past 4-byte JSL
if (offset + 5 + len > mFileData.Length) {
// ran off the end
@@ -109,6 +118,9 @@ namespace RuntimeData.Test2022 {
mAppRef.SetInlineDataFormat(offset + 4, len + 1,
DataType.StringL8, DataSubType.Ascii, null);
} else if (target == mInlineL2StringAddr) {
+ if (offset + 5 >= mFileData.Length) {
+ return; // length word is off end
+ }
int len = Util.GetWord(mFileData, offset + 4, 2, false);
if (offset + 6 + len > mFileData.Length) {
// ran off the end
@@ -118,7 +130,7 @@ namespace RuntimeData.Test2022 {
}
mAppRef.SetInlineDataFormat(offset + 4, len + 2,
DataType.StringL16, DataSubType.Ascii, null);
- } else {
+ } else if (target == mInlineDciStringAddr) {
// look for the first byte whose high bit doesn't match the first byte's bit
// 0 1 2 3 4 5
// 22 00 30 01 66 c1
diff --git a/SourceGen/SGTestData/2022-extension-scripts-b.cs b/SourceGen/SGTestData/2022-extension-scripts-b.cs
index 1bef8d8..deabeab 100644
--- a/SourceGen/SGTestData/2022-extension-scripts-b.cs
+++ b/SourceGen/SGTestData/2022-extension-scripts-b.cs
@@ -18,8 +18,7 @@ namespace RuntimeData.Test2022 {
}
}
- public void Prepare(IApplication appRef, byte[] fileData, AddressTranslate addrTrans,
- List plSyms) {
+ public void Prepare(IApplication appRef, byte[] fileData, AddressTranslate addrTrans) {
mAppRef = appRef;
mFileData = fileData;
mAddrTrans = addrTrans;
diff --git a/SourceGen/Sandbox/ScriptManager.cs b/SourceGen/Sandbox/ScriptManager.cs
index a3819a4..cc4b848 100644
--- a/SourceGen/Sandbox/ScriptManager.cs
+++ b/SourceGen/Sandbox/ScriptManager.cs
@@ -161,7 +161,11 @@ namespace SourceGen.Sandbox {
if (DomainMgr == null) {
AddressTranslate addrTrans = new AddressTranslate(mProject.AddrMap);
foreach (KeyValuePair kvp in mActivePlugins) {
- kvp.Value.Prepare(appRef, mProject.FileData, addrTrans, plSyms);
+ IPlugin ipl = kvp.Value;
+ ipl.Prepare(appRef, mProject.FileData, addrTrans);
+ if (ipl is IPlugin_SymbolList) {
+ ((IPlugin_SymbolList)ipl).UpdateSymbolList(plSyms);
+ }
}
} else {
List addrEnts = mProject.AddrMap.GetEntryList();
@@ -169,6 +173,28 @@ namespace SourceGen.Sandbox {
}
}
+ ///
+ /// Returns true if any of the plugins report that the before or after label is
+ /// significant.
+ ///
+ public bool IsLabelSignificant(Symbol before, Symbol after) {
+ string labelBefore = (before == null) ? string.Empty : before.Label;
+ string labelAfter = (after == null) ? string.Empty : after.Label;
+ if (DomainMgr == null) {
+ foreach (KeyValuePair kvp in mActivePlugins) {
+ IPlugin ipl = kvp.Value;
+ if (ipl is IPlugin_SymbolList &&
+ ((IPlugin_SymbolList)ipl).IsLabelSignificant(labelBefore,
+ labelAfter)) {
+ return true;
+ }
+ }
+ return false;
+ } else {
+ return DomainMgr.PluginMgr.IsLabelSignificant(labelBefore, labelAfter);
+ }
+ }
+
///
/// Gathers a list of platform symbols from the project's symbol table.
///
@@ -261,6 +287,9 @@ namespace SourceGen.Sandbox {
// The plugin is actually a MarshalByRefObject, so we can't use reflection
// to gather the list of interfaces.
// TODO(maybe): add a call that does the query on the remote site
+ if (plugin is PluginCommon.IPlugin_SymbolList) {
+ sb.Append(" SymbolList");
+ }
if (plugin is PluginCommon.IPlugin_InlineJsr) {
sb.Append(" InlineJsr");
}