Skip to content

Commit 09ad6be

Browse files
committed
Parity: Changes for NetLogo 7
- Change how language tests are retrieved - Handle X/Y autoplotting split
1 parent 34a7487 commit 09ad6be

19 files changed

+222
-106
lines changed

build.sbt

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,9 @@ import sbtcrossproject.CrossPlugin.autoImport.CrossType
22
import sbtcrossproject.CrossProject
33
import org.scalajs.sbtplugin.ScalaJSCrossVersion
44

5-
// For anyone who happens to stumble onto this commit for any reason, note that the below NetLogo headless/parser version/commit
6-
// is not mainline. It was done as a small side-branch to allow the nested multi-assign changes to go in here in Tortoise
7-
// cleanly as part of NL7 updates, then those changes were rebased to mainline NetLogo. The commit should be on an archived
8-
// branch in the NetLogo repo (`multi-assign-cleanup`). -Jeremy B April 2025
5+
val nlDependencyVersion = "7.0.0-internal1-a87d725"
96

10-
val nlDependencyVersion = "7.0.0-3d3af69"
11-
12-
val parserJsDependencyVersion = "0.4.0-3d3af69"
7+
val parserJsDependencyVersion = "0.4.0-a87d725"
138

149
val scalazVersion = "7.2.35"
1510

compiler/js/src/main/scala/BrowserRequests.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ case class ExportRequest(
2929
code = code,
3030
widgets = widgets.toList,
3131
info = info getOrElse "",
32-
turtleShapes = turtleShapes.map(_.toList) getOrElse Model.defaultShapes,
32+
turtleShapes = turtleShapes.map(_.toList) getOrElse Model.defaultTurtleShapes,
3333
linkShapes = linkShapes.map(_.toList) getOrElse Model.defaultLinkShapes,
3434
version = version getOrElse ExportRequest.NlogoFileVersion)
3535
}
@@ -72,7 +72,7 @@ case class CompilationRequest(
7272
code = code,
7373
widgets = widgets.toList,
7474
info = info getOrElse "",
75-
turtleShapes = turtleShapes.map(_.toList) getOrElse Model.defaultShapes,
75+
turtleShapes = turtleShapes.map(_.toList) getOrElse Model.defaultTurtleShapes,
7676
linkShapes = linkShapes.map(_.toList) getOrElse Model.defaultLinkShapes)
7777
}
7878

compiler/js/src/test/scala/TestUtilities.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ object TestUtilities {
9292
info = "some model info here",
9393
version = NlogoFileVersion,
9494
linkShapes = CModel.defaultLinkShapes :+ linkShape,
95-
turtleShapes = CModel.defaultShapes :+ vectorShape)
95+
turtleShapes = CModel.defaultTurtleShapes :+ vectorShape)
9696
}
9797

9898
val widgetyModel: CModel =

compiler/shared/src/main/scala/PlotCompiler.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ object PlotCompiler {
7878

7979
val args =
8080
Seq("name", "pens", "plotOps", jsString(sanitizeNil(xAxis.getOrElse(""))),
81-
jsString(sanitizeNil(yAxis.getOrElse(""))), legendOn, autoPlotOn, xmin,
81+
jsString(sanitizeNil(yAxis.getOrElse(""))), legendOn, autoPlotX, autoPlotY, xmin,
8282
xmax, ymin, ymax, "setup", "update").mkString(", ")
8383

8484
val plotConstructor =

compiler/shared/src/main/scala/SimplePrims.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -209,7 +209,7 @@ object SimplePrims {
209209
case _: prim._patchat => "SelfManager.self().patchAt"
210210

211211
// Plotting
212-
case _: prim.etc._autoplot => "plotManager.isAutoplotting"
212+
case _: prim.etc._autoplot => "plotManager.isAutoPlotting()"
213213
case _: prim.etc._plotname => "plotManager.getPlotName"
214214
case _: prim.etc._plotpenexists => "plotManager.hasPenWithName"
215215
case _: prim.etc._plotxmax => "plotManager.getPlotXMax"

compiler/shared/src/main/scala/json/WidgetRead.scala

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,20 @@ object WidgetRead {
9393
case other => other.toString.failureNel
9494
}
9595
}
96+
implicit object tortoiseJs2OptionInt extends JsonReader[TortoiseJson, Option[Int]] {
97+
override def read(key: String, json: Option[TortoiseJson]): ValidationNel[String, Option[Int]] =
98+
json.map(j =>
99+
apply(j).leftMap(value => NonEmptyList(s"$value is an invalid value for $key")))
100+
.getOrElse(None.successNel)
101+
102+
def apply(t: TortoiseJson): ValidationNel[String, Option[Int]] =
103+
t match {
104+
case JsNull => None.successNel
105+
case JsString("NIL") => None.successNel
106+
case JsString(s) => Some(s.toInt).successNel
107+
case other => other.toString.failureNel
108+
}
109+
}
96110

97111
implicit object tortoiseJs2Direction extends JsonReader[TortoiseJson, Direction] {
98112
def apply(t: TortoiseJson): ValidationNel[String, Direction] = t match {

compiler/shared/src/main/scala/json/WidgetWrite.scala

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,11 @@ object WidgetWrite {
7070
def apply(s: Option[String]): TortoiseJson = JsString(s.get)
7171
}
7272

73+
implicit object intOption2Json extends OptionWriter[Int] {
74+
// in general, get is not safe, but we're checking it in write
75+
def apply(i: Option[Int]): TortoiseJson = JsString(i.get.toString)
76+
}
77+
7378
implicit object chooseable2Json extends JsonWriter[Chooseable] {
7479
def apply(c: Chooseable): TortoiseJson =
7580
c match {

compiler/shared/src/test/scala/json/WidgetSamples.scala

Lines changed: 45 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,9 @@ import
1515

1616
object WidgetSamples {
1717

18-
val slider = Slider(Option("foobar"), 1, 2, 3, 4, Option("abc"), "5", "25", 10.0, "1", Some("bazzes"), Horizontal)
19-
val reporterSlider = Slider(Option("foobar"), 1, 2, 3, 4, Option("abc"), "0", "count turtles", 10.0, "count turtles / 100", Some("bazzes"), Horizontal)
20-
val switch = Switch(Option("foobar"), 1, 2, 3, 4, Option("abc"), true)
18+
val slider = Slider(Option("foobar"), 1, 2, 3, 4, false, Option("abc"), "5", "25", 10.0, "1", Some("bazzes"), Horizontal)
19+
val reporterSlider = Slider(Option("foobar"), 1, 2, 3, 4, false, Option("abc"), "0", "count turtles", 10.0, "count turtles / 100", Some("bazzes"), Horizontal)
20+
val switch = Switch(Option("foobar"), 1, 2, 3, 4, false, Option("abc"), true)
2121
val buttonNoName = Button(Option("foobar"), 1, 2, 3, 4, None, false, Turtle, Option('A'))
2222
val buttonWithName = Button(Option("foobar"), 1, 2, 3, 4, Some("press this"), false)
2323
val chooser = {
@@ -26,22 +26,22 @@ object WidgetSamples {
2626
Chooseable("def"),
2727
Chooseable(LogoList("xyz")),
2828
Chooseable(Boolean.box(false)))
29-
Chooser(Option("foobar"), 1, 2, 3, 4, Option("abc"), choices, 0)
29+
Chooser(Option("foobar"), 1, 2, 3, 4, false, Option("abc"), choices, 0)
3030
}
31-
val inputBoxNumber = InputBox(Option("foobar"), 1, 2, 3, 4, NumericInput(25.0, NumberLabel))
32-
val inputBoxColor = InputBox(Option("foobar"), 1, 2, 3, 4, NumericInput(15, ColorLabel))
33-
val inputBoxString = InputBox(Option("foobar"), 1, 2, 3, 4, StringInput("baz", StringLabel, false))
34-
val monitor = Monitor(Some("reporter"), 1, 2, 3, 4, Option("abc"), 3, 10)
35-
val monitorNil = Monitor(Some("reporter"), 1, 2, 3, 4, None, 3, 10)
31+
val inputBoxNumber = InputBox(Option("foobar"), 1, 2, 3, 4, false, NumericInput(25.0, NumberLabel))
32+
val inputBoxColor = InputBox(Option("foobar"), 1, 2, 3, 4, false, NumericInput(15, ColorLabel))
33+
val inputBoxString = InputBox(Option("foobar"), 1, 2, 3, 4, false, StringInput("baz", StringLabel, false))
34+
val monitor = Monitor(Some("reporter"), 1, 2, 3, 4, false, Option("abc"), 3, 10)
35+
val monitorNil = Monitor(Some("reporter"), 1, 2, 3, 4, false, None, 3, 10)
3636
val plot = {
3737
val pen = Pen("abc", 2, 0, 15, true, "setup", "update")
38-
Plot(Option("abc"), 1, 2, 3, 4,
38+
Plot(Option("abc"), 1, 2, 3, 4, false,
3939
Option("time"), Option("height"), 0, 100, 50, 200,
40-
autoPlotOn = true, legendOn = false,
40+
autoPlotX = true, autoPlotY = true, legendOn = false,
4141
setupCode = "setup", updateCode = "update", pens = List(pen))
4242
}
4343
val ouput = Output(1, 2, 3, 4, 10)
44-
val textBox = TextBox(Option("abc"), 1, 2, 3, 4, 10, 25.0, false)
44+
val textBox = TextBox(Option("abc"), 1, 2, 3, 4, 10, false)
4545
val view = View(1, 2, 3, 4, WorldDimensions(10, 9, 8, 7, 25.0, true, false), 8, UpdateMode.Continuous, false, Option("tocks"), 50.0)
4646

4747
val penJson = JsObject(fields(
@@ -64,6 +64,7 @@ object WidgetSamples {
6464
def widgetJsons: Map[String, JsObject] = Map(
6565

6666
"slider" -> locatableJsObject(
67+
"oldSize" -> JsBool(false),
6768
"type" -> JsString("slider"),
6869
"display" -> JsString("abc"),
6970
"variable" -> JsString("foobar"),
@@ -75,6 +76,7 @@ object WidgetSamples {
7576
"step" -> JsString("1")),
7677

7778
"switch" -> locatableJsObject(
79+
"oldSize" -> JsBool(false),
7880
"type" -> JsString("switch"),
7981
"display" -> JsString("abc"),
8082
"variable" -> JsString("foobar"),
@@ -97,6 +99,7 @@ object WidgetSamples {
9799
"buttonKind" -> JsString("Observer")),
98100

99101
"chooser" -> locatableJsObject(
102+
"oldSize" -> JsBool(false),
100103
"type" -> JsString("chooser"),
101104
"display" -> JsString("abc"),
102105
"variable" -> JsString("foobar"),
@@ -109,15 +112,17 @@ object WidgetSamples {
109112
))),
110113

111114
"inputBox[number]" -> locatableJsObject(
112-
"type" -> JsString("inputBox"),
113-
"variable" -> JsString("foobar"),
114-
"boxedValue" -> JsObject(fields(
115-
"value" -> JsDouble(25.0),
116-
"type" -> JsString(NumberLabel.display)
117-
))
115+
"oldSize" -> JsBool(false),
116+
"type" -> JsString("inputBox"),
117+
"variable" -> JsString("foobar"),
118+
"boxedValue" -> JsObject(fields(
119+
"value" -> JsDouble(25.0),
120+
"type" -> JsString(NumberLabel.display)
121+
))
118122
),
119123

120124
"inputBox[color]" -> locatableJsObject(
125+
"oldSize" -> JsBool(false),
121126
"type" -> JsString("inputBox"),
122127
"variable" -> JsString("foobar"),
123128
"boxedValue" -> JsObject(fields(
@@ -127,6 +132,7 @@ object WidgetSamples {
127132
),
128133

129134
"inputBox[string]" -> locatableJsObject(
135+
"oldSize" -> JsBool(false),
130136
"type" -> JsString("inputBox"),
131137
"variable" -> JsString("foobar"),
132138
"boxedValue" -> JsObject(fields(
@@ -137,43 +143,46 @@ object WidgetSamples {
137143
),
138144

139145
"monitor" -> locatableJsObject(
146+
"oldSize" -> JsBool(false),
140147
"type" -> JsString("monitor"),
141148
"display" -> JsString("abc"),
142149
"source" -> JsString("reporter"),
143150
"precision" -> JsInt(3),
144151
"fontSize" -> JsInt(10)),
145152

146153
"monitorNil" -> locatableJsObject(
154+
"oldSize" -> JsBool(false),
147155
"type" -> JsString("monitor"),
148156
"source" -> JsString("reporter"),
149157
"precision" -> JsInt(3),
150158
"fontSize" -> JsInt(10)),
151159

152160
"plot" -> locatableJsObject(
153-
"type" -> JsString("plot"),
154-
"display" -> JsString("abc"),
155-
"xAxis" -> JsString("time"),
156-
"yAxis" -> JsString("height"),
157-
"xmin" -> JsDouble(0),
158-
"xmax" -> JsDouble(100),
159-
"ymin" -> JsDouble(50),
160-
"ymax" -> JsDouble(200),
161-
"autoPlotOn" -> JsBool(true),
162-
"legendOn" -> JsBool(false),
163-
"setupCode" -> JsString("setup"),
164-
"updateCode" -> JsString("update"),
165-
"pens" -> JsArray(Seq(penJson))),
161+
"oldSize" -> JsBool(false),
162+
"type" -> JsString("plot"),
163+
"display" -> JsString("abc"),
164+
"xAxis" -> JsString("time"),
165+
"yAxis" -> JsString("height"),
166+
"xmin" -> JsDouble(0),
167+
"xmax" -> JsDouble(100),
168+
"ymin" -> JsDouble(50),
169+
"ymax" -> JsDouble(200),
170+
"autoPlotX" -> JsBool(true),
171+
"autoPlotY" -> JsBool(true),
172+
"legendOn" -> JsBool(false),
173+
"setupCode" -> JsString("setup"),
174+
"updateCode" -> JsString("update"),
175+
"pens" -> JsArray(Seq(penJson))),
166176

167177
"output" -> locatableJsObject(
168178
"type" -> JsString("output"),
169179
"fontSize" -> JsInt(10)),
170180

171181
"textBox" -> locatableJsObject(
172-
"type" -> JsString("textBox"),
173-
"display" -> JsString("abc"),
174-
"fontSize" -> JsInt(10),
175-
"color" -> JsDouble(25.0),
176-
"transparent" -> JsBool(false)),
182+
"type" -> JsString("textBox"),
183+
"display" -> JsString("abc"),
184+
"fontSize" -> JsInt(10),
185+
"markdown" -> JsBool(false)),
177186

178187
"view" -> locatableJsObject(
179188
"type" -> JsString("view"),

engine/src/main/coffee/engine/core/world/export.coffee

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,8 @@ exportPlot = (plot) ->
167167
new ExportedPen(color, interval, isPenDown, mode, name, points, x)
168168

169169
currentPenNameOrNull = fold(-> null)((cp) -> cp.name)(plot.getCurrentPenMaybe())
170-
isAutoplotting = plot.isAutoplotting
170+
isAutoPlotX = plot.isAutoPlotX
171+
isAutoPlotY = plot.isAutoPlotY
171172
isLegendOpen = plot.isLegendEnabled
172173
name = plot.name
173174
pens = plot.getPens().map(exportPen)
@@ -176,7 +177,7 @@ exportPlot = (plot) ->
176177
yMax = plot.yMax
177178
yMin = plot.yMin
178179

179-
new ExportedPlot(currentPenNameOrNull, isAutoplotting, isLegendOpen, name, pens, xMax, xMin, yMax, yMin)
180+
new ExportedPlot(currentPenNameOrNull, isAutoPlotX, isAutoPlotY, isLegendOpen, name, pens, xMax, xMin, yMax, yMin)
180181

181182
# (String) => ExportedPlot
182183
exportRawPlot = (plotName) ->

engine/src/main/coffee/engine/plot/plot.coffee

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,11 @@ module.exports = class Plot
1919

2020
name: undefined # String
2121

22-
# (String, Array[Pen], PlotOps, String, String, Boolean, Number, Number, Number, Number, () => (Unit | StopInterrupt), () => (Unit | StopInterrupt)) => Plot
23-
constructor: (@name, pens = [], @_ops, @xLabel, @yLabel, @isLegendEnabled = true, @isAutoplotting = true, @xMin = 0, @xMax = 10, @yMin = 0, @yMax = 10, @_setupThis = (->), @_updateThis = (->)) ->
22+
# (String, Array[Pen], PlotOps, String, String, Boolean, Boolean, Boolean,
23+
# Number, Number, Number, Number, () => (Unit | StopInterrupt), () => (Unit | StopInterrupt)) => Plot
24+
constructor: (@name, pens = [], @_ops, @xLabel, @yLabel, @isLegendEnabled = true, @isAutoPlotX = true, @isAutoPlotY = true,
25+
@xMin = 0, @xMax = 10, @yMin = 0, @yMax = 10, @_setupThis = (->), @_updateThis = (->)) ->
26+
2427
toName = (p) -> p.name.toUpperCase()
2528
@_currentPenMaybe = maybe(pens[0])
2629
@_originalBounds = [@xMin, @xMax, @yMin, @yMax]
@@ -59,7 +62,8 @@ module.exports = class Plot
5962

6063
# () => Unit
6164
disableAutoplotting: ->
62-
@isAutoplotting = false
65+
@isAutoPlotX = false
66+
@isAutoPlotY = false
6367
return
6468

6569
# (Array[Number]) => Unit
@@ -76,9 +80,13 @@ module.exports = class Plot
7680

7781
# () => Unit
7882
enableAutoplotting: ->
79-
@isAutoplotting = true
83+
@isAutoPlotX = true
84+
@isAutoPlotY = true
8085
return
8186

87+
isAutoPlotting: ->
88+
@isAutoPlotX and @isAutoPlotY
89+
8290
# () => Maybe[Pen]
8391
getCurrentPenMaybe: ->
8492
@_currentPenMaybe
@@ -92,7 +100,7 @@ module.exports = class Plot
92100
pipeline(@_getPenMaybeByName, isSomething)(name)
93101

94102
# (ExportedPlot) => Unit
95-
importState: ({ currentPenNameOrNull, @isAutoplotting, isLegendOpen: @isLegendEnabled, pens
103+
importState: ({ currentPenNameOrNull, @isAutoPlotX, @isAutoPlotY, isLegendOpen: @isLegendEnabled, pens
96104
, @xMax, @xMin, @yMax, @yMin }) ->
97105
pens.forEach((pen) => @_createAndReturnTemporaryPen(pen.name).importState(pen))
98106
@_currentPenMaybe = @_getPenMaybeByName(currentPenNameOrNull)
@@ -229,9 +237,10 @@ module.exports = class Plot
229237
# (Pen) => Unit
230238
_verifyHistogramSize: (pen) ->
231239
isWithinBounds = ({ x }) => x >= @xMin and x <= @xMax
232-
penYMax = pipeline(filter(isWithinBounds), map((p) -> p.y), maxBy(id), fold(-> 0)(id))(pen.getPoints())
233-
if penYMax > @yMax and @isAutoplotting
234-
@yMax = penYMax
240+
if @isAutoPlotY
241+
penYMax = pipeline(filter(isWithinBounds), map((p) -> p.y), maxBy(id), fold(-> 0)(id))(pen.getPoints())
242+
if penYMax > @yMax
243+
@yMax = penYMax
235244
@_resize()
236245
return
237246

@@ -264,9 +273,10 @@ module.exports = class Plot
264273
# If bounds extended, we must resize, regardless of whether or not autoplotting is enabled, because some
265274
# libraries force autoscaling, but we only _expand_ the boundaries when autoplotting. --JAB (10/10/14)
266275
if newXMin isnt @xMin or newXMax isnt @xMax or newYMin isnt @yMin or newYMax isnt @yMax
267-
if @isAutoplotting
276+
if @isAutoPlotX
268277
@xMin = newXMin
269278
@xMax = newXMax
279+
if @isAutoPlotY
270280
@yMin = newYMin
271281
@yMax = newYMax
272282
@_resize()

engine/src/main/coffee/engine/plot/plotmanager.coffee

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -101,8 +101,8 @@ module.exports = class PlotManager
101101
return
102102

103103
# () => Boolean
104-
isAutoplotting: ->
105-
@_withPlot((plot) -> plot.isAutoplotting)
104+
isAutoPlotting: ->
105+
@_withPlot((plot) -> plot.isAutoPlotting)
106106

107107
# () => Unit
108108
lowerPen: ->

engine/src/main/coffee/serialize/exportcsv.coffee

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -301,17 +301,19 @@ formatAgents = (agents, schemafy, builtinsNames, ownsNames, formatAnyValue) ->
301301
"#{keysRow}#{onNextLineIfNotEmpty(valuesRows)}"
302302

303303
# (ExportedPlot) => String
304-
formatPlotData = ({ currentPenNameOrNull, isAutoplotting, isLegendOpen, name, pens, xMax, xMin, yMax, yMin }) ->
304+
formatPlotData = ({ currentPenNameOrNull, isAutoPlotX, isAutoPlotY, isLegendOpen, name, pens, xMax, xMin, yMax, yMin }) ->
305305

306306
currentPenStr = currentPenNameOrNull ? ''
307307

308+
isAutoplot = isAutoPlotX and isAutoPlotY
309+
308310
convertedPlot =
309311
{
310312
'x min': [xMin , formatNumber ]
311313
'x max': [xMax , formatNumber ]
312314
'y min': [yMin , formatNumber ]
313315
'y max': [yMax , formatNumber ]
314-
'autoplot?': [isAutoplotting, formatBoolean]
316+
'autoplot?': [isAutoplot , formatBoolean]
315317
'current pen': [currentPenStr , formatString ]
316318
'legend open?': [isLegendOpen , formatBoolean]
317319
'number of pens': [pens.length , formatNumber ]

engine/src/main/coffee/serialize/exportstructures.coffee

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,9 +69,9 @@ module.exports.ExportedPen =
6969

7070
module.exports.ExportedPlot =
7171
class
72-
# ( String, Boolean, Boolean, String, Array[ExportedPen]
72+
# ( String, Boolean, Boolean, Boolean, String, Array[ExportedPen]
7373
# , Number, Number, Number, Number)
74-
constructor: ( @currentPenNameOrNull, @isAutoplotting, @isLegendOpen, @name, @pens
74+
constructor: ( @currentPenNameOrNull, @isAutoPlotX, @isAutoPlotY, @isLegendOpen, @name, @pens
7575
, @xMax, @xMin, @yMax, @yMin) ->
7676

7777
module.exports.ExportedPlotManager =

0 commit comments

Comments
 (0)