Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] Editor #93

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions lib/builder.dart
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,7 @@ class BuiltinStub {
'SchemeSymbol': 'symbol',
'Procedure': 'procedure',
'Pair': 'pair',
'SchemeList': 'list',
'SchemeEventListener': 'event listener',
'JsValue': 'js object',
'JsProcedure': 'js function',
Expand Down
12 changes: 12 additions & 0 deletions lib/src/core/interpreter.dart
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,18 @@ class Interpreter {
StandardLibrary().importAll(globalEnv);
}

/// Creates a clone of this interpreter, with a copy of this interpreter's
/// current global environment and settings, but a reset logger, exit
/// listener, and frame counter.
Interpreter clone() {
var cloned = Interpreter(impl);
cloned.language = language;
cloned.tailCallOptimized = tailCallOptimized;
cloned.globalEnv.bindings.addAll(globalEnv.bindings);
cloned.globalEnv.hidden.addAll(globalEnv.hidden);
return cloned;
}

@deprecated
ProjectInterface get implementation => impl;

Expand Down
4 changes: 2 additions & 2 deletions lib/src/core/standard_library.dart
Original file line number Diff line number Diff line change
Expand Up @@ -244,13 +244,13 @@ class StandardLibrary extends SchemeLibrary with _$StandardLibraryMixin {
bool isZero(Number x) => x == Number.zero;

/// Forces [promise], evaluating it if necessary.
Expression force(Promise promise) => promise.force();
Value force(Promise promise) => promise.force();

/// Finds the rest of [stream].
///
/// Equivalent to (force (cdr [stream]))
@SchemeSymbol("cdr-stream")
Expression cdrStream(Pair stream) => force(cdr(stream));
Value cdrStream(Pair stream) => force(cdr(stream));

/// Mutates the car of [pair] to be [val].
@SchemeSymbol("set-car!")
Expand Down
21 changes: 12 additions & 9 deletions lib/src/core/standard_library.g.dart
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,8 @@ abstract class _$StandardLibraryMixin {
bool isEven(Number x);
bool isOdd(Number x);
bool isZero(Number x);
Expression force(Promise promise);
Expression cdrStream(Pair stream);
Value force(Promise promise);
Value cdrStream(Pair stream);
void setCar(Pair pair, Value val);
void setCdr(Pair pair, Value val, Frame env);
String getRuntimeType(Expression expression);
Expand All @@ -65,7 +65,7 @@ abstract class _$StandardLibraryMixin {
return this.apply(__exprs[0], SchemeList(__exprs[1]), __env);
}, 2,
docs: Docs("apply", "Applies [procedure] to the given [args]\n",
[Param("procedure", "procedure"), Param(null, "args")],
[Param("procedure", "procedure"), Param("list", "args")],
returnType: "value"));
addBuiltin(__env, const SchemeSymbol("display"), (__exprs, __env) {
this.display(__exprs[0], __env);
Expand Down Expand Up @@ -220,7 +220,8 @@ abstract class _$StandardLibraryMixin {
}, 0,
maxArgs: -1,
docs: Docs.variable(
"list", "Constructs a list from zero or more arguments.\n"));
"list", "Constructs a list from zero or more arguments.\n",
returnType: "list"));
addBuiltin(__env, const SchemeSymbol("map"), (__exprs, __env) {
if (__exprs[0] is! Procedure || __exprs[1] is! PairOrEmpty)
throw SchemeException('Argument of invalid type passed to map.');
Expand All @@ -229,7 +230,8 @@ abstract class _$StandardLibraryMixin {
docs: Docs(
"map",
"Constructs a new list from calling [fn] on each item in [lst].\n",
[Param("procedure", "fn"), Param(null, "lst")]));
[Param("procedure", "fn"), Param("list", "lst")],
returnType: "list"));
addBuiltin(__env, const SchemeSymbol("filter"), (__exprs, __env) {
if (__exprs[0] is! Procedure || __exprs[1] is! PairOrEmpty)
throw SchemeException('Argument of invalid type passed to filter.');
Expand All @@ -238,7 +240,8 @@ abstract class _$StandardLibraryMixin {
docs: Docs(
"filter",
"Constructs a new list of all items in [lst] that return true when passed\nto [pred].\n",
[Param("procedure", "pred"), Param(null, "lst")]));
[Param("procedure", "pred"), Param("list", "lst")],
returnType: "list"));
addBuiltin(__env, const SchemeSymbol("reduce"), (__exprs, __env) {
if (__exprs[0] is! Procedure || __exprs[1] is! PairOrEmpty)
throw SchemeException('Argument of invalid type passed to reduce.');
Expand All @@ -247,7 +250,7 @@ abstract class _$StandardLibraryMixin {
docs: Docs(
"reduce",
"Reduces [lst] into a single expression by combining items with [combiner].\n",
[Param("procedure", "combiner"), Param(null, "lst")],
[Param("procedure", "combiner"), Param("list", "lst")],
returnType: "value"));
addVariableBuiltin(__env, const SchemeSymbol("+"), (__exprs, __env) {
if (__exprs.any((x) => x is! Number))
Expand Down Expand Up @@ -421,7 +424,7 @@ abstract class _$StandardLibraryMixin {
}, 1,
docs: Docs("force", "Forces [promise], evaluating it if necessary.\n",
[Param(null, "promise")],
returnType: "expression"));
returnType: "value"));
addBuiltin(__env, const SchemeSymbol("cdr-stream"), (__exprs, __env) {
if (__exprs[0] is! Pair)
throw SchemeException('Argument of invalid type passed to cdr-stream.');
Expand All @@ -431,7 +434,7 @@ abstract class _$StandardLibraryMixin {
"cdr-stream",
"Finds the rest of [stream].\n\nEquivalent to (force (cdr [stream]))\n",
[Param("pair", "stream")],
returnType: "expression"));
returnType: "value"));
addBuiltin(__env, const SchemeSymbol("set-car!"), (__exprs, __env) {
if (__exprs[0] is! Pair)
throw SchemeException('Argument of invalid type passed to set-car!.');
Expand Down
6 changes: 3 additions & 3 deletions lib/src/core/values.dart
Original file line number Diff line number Diff line change
Expand Up @@ -99,19 +99,19 @@ class Thunk extends Value {
/// whose cdr is a promise that evaluates to another stream or the empty list.
///
/// It is semantically different from a JS Promise, which is equivalent to a
/// Dart [Future]. The Scheme equivalent of [Future] is [AsyncExpression].
/// Dart [Future]. The Scheme equivalent of [Future] is [AsyncValue].
///
/// A Scheme stream is semantically different from a Dart Stream, which is an
/// asynchronous sequence. A Scheme stream is analogous to a lazily-computed
/// iterable built on a linked list.
class Promise extends Value {
Expression expr;
Value expr;
final Frame env;
bool _evaluated = false;
Promise(this.expr, this.env);

/// Evaluates the promise, or returns the result if already evaluated.
Expression force() {
Value force() {
if (!_evaluated) {
expr = schemeEval(expr, env);
env.interpreter.language.validateCdr(expr,
Expand Down
7 changes: 3 additions & 4 deletions lib/src/extra/extra_library.g.dart
Original file line number Diff line number Diff line change
Expand Up @@ -61,10 +61,9 @@ abstract class _$ExtraLibraryMixin {
addBuiltin(__env, const SchemeSymbol("bindings"), (__exprs, __env) {
return (this.bindings(__env)).list;
}, 0,
docs: Docs(
"bindings",
"Returns a list of all bindings in the current environment.\n",
[]));
docs: Docs("bindings",
"Returns a list of all bindings in the current environment.\n", [],
returnType: "list"));
addVariableBuiltin(__env, const SchemeSymbol('trigger-event'),
(__exprs, __env) {
this.triggerEvent(__exprs, __env);
Expand Down
15 changes: 6 additions & 9 deletions lib/src/extra/visualization.dart
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,6 @@ class Button extends Widget {
void Function() click;
Widget inside;
Button(this.inside, this.click);
Button.forEvent(
this.inside, SchemeSymbol id, List<Expression> data, Frame env) {
click = () {
env.interpreter.triggerEvent(id, data, env);
};
}
}

class Visualization extends Widget {
Expand All @@ -29,6 +23,8 @@ class Visualization extends Widget {
List<Widget> buttonRow;
Value result;

Function(int index, [bool keepAnimating]) goto;

Visualization(this.code, this.env) {
Interpreter inter = env.interpreter;

Expand Down Expand Up @@ -61,7 +57,7 @@ class Visualization extends Widget {

_init() {
bool animating = false;
goto(int index, [bool keepAnimating = false]) {
goto = (index, [keepAnimating = false]) {
if (!keepAnimating) animating = false;
if (index < 0) index = diagrams.length - 1;
if (index >= diagrams.length - 1) {
Expand All @@ -71,7 +67,7 @@ class Visualization extends Widget {
current = index;
buttonRow[2] = TextWidget("${current + 1}/${diagrams.length}");
update();
}
};

Button first = Button(TextWidget("<<"), () => goto(0));
Button prev = Button(TextWidget("<"), () => goto(current - 1));
Expand All @@ -83,6 +79,7 @@ class Visualization extends Widget {
animating = false;
return;
}
if (current == diagrams.length - 1) goto(0);
animating = true;
await Future.delayed(Duration(seconds: 1));
while (animating && current < diagrams.length - 1) {
Expand All @@ -93,7 +90,7 @@ class Visualization extends Widget {
buttonRow = [first, prev, status, next, last, animate];
}

void _addFrames(Frame myEnv, [Expression returnValue]) {
void _addFrames(Frame myEnv, [Value returnValue]) {
if (myEnv.tag == '#imported') return;
if (frameReturnValues.containsKey(myEnv)) {
frameReturnValues[myEnv] = returnValue;
Expand Down
11 changes: 5 additions & 6 deletions lib/src/web/turtle_library.dart
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ class TurtleLibrary extends SchemeLibrary with _$TurtleLibraryMixin {
@turtlestart
@MinArgs(1)
@MaxArgs(2)
void circle(List<Expression> exprs) {
void circle(List<Value> exprs) {
if (exprs[0] is! Number) {
throw SchemeException('${exprs[0]} is not a number');
}
Expand Down Expand Up @@ -96,7 +96,7 @@ class TurtleLibrary extends SchemeLibrary with _$TurtleLibraryMixin {

/// Sets the pen color of the turtle.
@turtlestart
void color(Expression color) {
void color(Value color) {
turtle.penColor = Color.fromAnything(color);
}

Expand All @@ -123,13 +123,13 @@ class TurtleLibrary extends SchemeLibrary with _$TurtleLibraryMixin {

/// Sets the background color of the turtle canvas.
@turtlestart
void bgcolor(Expression color) {
void bgcolor(Value color) {
turtle.backgroundColor = Color.fromAnything(color);
}

/// Sets the [size] of the turtle's pen.
@turtlestart
void pensize(num size) {
void pensize(int size) {
turtle.penSize = size;
}

Expand Down Expand Up @@ -169,7 +169,7 @@ class TurtleLibrary extends SchemeLibrary with _$TurtleLibraryMixin {

/// Draws a box with [color] in the turtle's current pixel size at ([x], [y])
@turtlestart
void pixel(num x, num y, Expression color) {
void pixel(num x, num y, Value color) {
turtle.drawPixel(x, y, Color.fromAnything(color));
}

Expand All @@ -188,7 +188,6 @@ class TurtleLibrary extends SchemeLibrary with _$TurtleLibraryMixin {
@SchemeSymbol('screen-height')
num screenHeight() => turtle.gridHeight / turtle.pixelSize;

/// This turtle procedure is not supported in the web interpreter.
@SchemeSymbol('unsupported')
@SchemeSymbol('speed')
@SchemeSymbol('showturtle')
Expand Down
43 changes: 14 additions & 29 deletions lib/src/web/turtle_library.g.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,23 +9,23 @@ abstract class _$TurtleLibraryMixin {
void backward(num distance);
void left(num angle);
void right(num angle);
void circle(List<Expression> exprs);
void circle(List<Value> exprs);
void setPosition(num x, num y);
void setHeading(num heading);
void penUp();
void penDown();
void turtleClear();
void color(Expression color);
void color(Value color);
void beginFill();
void endFill();
void exitonclick(Frame env);
void exit();
void bgcolor(Expression color);
void pensize(num size);
void bgcolor(Value color);
void pensize(int size);
void turtleHelp(Frame env);
void setGridSize(int width, int height);
void setCanvasSize(int width, int height);
void pixel(num x, num y, Expression color);
void pixel(num x, num y, Value color);
void pixelsize(int size);
num screenWidth();
num screenHeight();
Expand Down Expand Up @@ -90,10 +90,8 @@ abstract class _$TurtleLibraryMixin {
__env.bindings[const SchemeSymbol('right')];
__env.hidden[const SchemeSymbol('rt')] = true;
addVariableBuiltin(__env, const SchemeSymbol("circle"), (__exprs, __env) {
if (__exprs.any((x) => x is! Expression))
throw SchemeException('Argument of invalid type passed to circle.');
turtle.show();
this.circle(__exprs.cast<Expression>());
this.circle(__exprs);
return undefined;
}, 1,
maxArgs: 2,
Expand Down Expand Up @@ -153,14 +151,12 @@ abstract class _$TurtleLibraryMixin {
return undefined;
}, 0, docs: Docs('turtle-clear', "Clears the current turtle state.\n", []));
addBuiltin(__env, const SchemeSymbol("color"), (__exprs, __env) {
if (__exprs[0] is! Expression)
throw SchemeException('Argument of invalid type passed to color.');
turtle.show();
this.color(__exprs[0]);
return undefined;
}, 1,
docs: Docs("color", "Sets the pen color of the turtle.\n",
[Param("expression", "color")]));
[Param("value", "color")]));
addBuiltin(__env, const SchemeSymbol('begin_fill'), (__exprs, __env) {
turtle.show();
this.beginFill();
Expand Down Expand Up @@ -194,25 +190,23 @@ abstract class _$TurtleLibraryMixin {
docs: Docs('turtle-exit',
"Closes the turtle canvas, reseting its state.\n", []));
addBuiltin(__env, const SchemeSymbol("bgcolor"), (__exprs, __env) {
if (__exprs[0] is! Expression)
throw SchemeException('Argument of invalid type passed to bgcolor.');
turtle.show();
this.bgcolor(__exprs[0]);
return undefined;
}, 1,
docs: Docs(
"bgcolor",
"Sets the background color of the turtle canvas.\n",
[Param("expression", "color")]));
[Param("value", "color")]));
addBuiltin(__env, const SchemeSymbol("pensize"), (__exprs, __env) {
if (__exprs[0] is! Number)
if (__exprs[0] is! Integer)
throw SchemeException('Argument of invalid type passed to pensize.');
turtle.show();
this.pensize(__exprs[0].toJS());
this.pensize(__exprs[0].toJS().toInt());
return undefined;
}, 1,
docs: Docs("pensize", "Sets the [size] of the turtle's pen.\n",
[Param("num", "size")]));
[Param("int", "size")]));
addBuiltin(__env, const SchemeSymbol('turtle-help'), (__exprs, __env) {
this.turtleHelp(__env);
return undefined;
Expand Down Expand Up @@ -244,9 +238,7 @@ abstract class _$TurtleLibraryMixin {
"Sets the exterior dimensions of the turtle's canvas.\n\nThis does not effect the current state of the turtle.\n",
[Param("int", "width"), Param("int", "height")]));
addBuiltin(__env, const SchemeSymbol("pixel"), (__exprs, __env) {
if (__exprs[0] is! Number ||
__exprs[1] is! Number ||
__exprs[2] is! Expression)
if (__exprs[0] is! Number || __exprs[1] is! Number)
throw SchemeException('Argument of invalid type passed to pixel.');
turtle.show();
this.pixel(__exprs[0].toJS(), __exprs[1].toJS(), __exprs[2]);
Expand All @@ -255,11 +247,7 @@ abstract class _$TurtleLibraryMixin {
docs: Docs(
"pixel",
"Draws a box with [color] in the turtle's current pixel size at ([x], [y])\n",
[
Param("num", "x"),
Param("num", "y"),
Param("expression", "color")
]));
[Param("num", "x"), Param("num", "y"), Param("value", "color")]));
addBuiltin(__env, const SchemeSymbol("pixelsize"), (__exprs, __env) {
if (__exprs[0] is! Integer)
throw SchemeException('Argument of invalid type passed to pixelsize.');
Expand Down Expand Up @@ -297,10 +285,7 @@ abstract class _$TurtleLibraryMixin {
'Argument of invalid type passed to unsupported.');
this.unsupported(__exprs.cast<Expression>(), __env);
return undefined;
}, 0,
maxArgs: -1,
docs: Docs.variable('unsupported',
"This turtle procedure is not supported in the web interpreter.\n"));
}, 0, maxArgs: -1);
__env.bindings[const SchemeSymbol('speed')] =
__env.bindings[const SchemeSymbol('unsupported')];
__env.hidden[const SchemeSymbol('speed')] = true;
Expand Down
Loading