Skip to content

Commit b5f2e4a

Browse files
committed
wip
1 parent 17ada08 commit b5f2e4a

File tree

10 files changed

+147
-13
lines changed

10 files changed

+147
-13
lines changed

frontend/courses/courses.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,8 @@
2727
{ "id": "ellipse", "title": "Ellipse" },
2828
{ "id": "fill", "title": "Stroke and Fill" },
2929
{ "id": "linestyle", "title": "Line Styles" },
30-
{ "id": "text", "title": "Text" }
30+
{ "id": "text", "title": "Text" },
31+
{ "id": "curve", "title": "Curve" }
3132
]
3233
},
3334
{
@@ -36,6 +37,7 @@
3637
"emoji": "🤹‍♀️",
3738
"units": [
3839
{ "id": "movingdot", "title": "Moving Red Dot" },
40+
{ "id": "bounce", "title": "Bounce" },
3941
{ "id": "juggle", "title": "Juggle" },
4042
{ "id": "splashtrig", "title": "Splash of Trig" },
4143
{ "id": "draw", "title": "Draw" }
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
background := "hsl(0deg 0% 0% / 10%)"
2+
x := 10
3+
y := 50
4+
s := 1
5+
width 1
6+
fill background
7+
stroke "red"
8+
9+
on animate
10+
clear background
11+
move x y
12+
circle 10
13+
x = x + s
14+
if x < 10 or x > 90
15+
s = -s
16+
end
17+
end
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
print "todo"

frontend/index.js

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ function newEvyGo() {
5858
// advanced canvas
5959
poly,
6060
ellipse,
61+
curve,
6162
stroke,
6263
fill,
6364
dash,
@@ -99,6 +100,7 @@ function needsCanvas(f) {
99100
f.clear ||
100101
f.poly ||
101102
f.ellipse ||
103+
f.curve ||
102104
f.stroke ||
103105
f.fill ||
104106
f.dash ||
@@ -562,6 +564,71 @@ function ellipse(x, y, radiusX, radiusY, rotation, startAngle, endAngle) {
562564
stroke && ctx.stroke()
563565
}
564566

567+
// curve is exported to evy go/wasm.
568+
// curve draws connected curve segments encoded as string
569+
// representing 2 dimensional array, e.g.:
570+
// "1 2 3 4,5 6" => [[1,2,3,4], [5,6]]
571+
// the curve segments here are 1 2 3 4 and 5 6
572+
//
573+
// curve segments are interpreted differently depending on their
574+
// **length**:
575+
// 2: endX, endY - Line from current position end position x, y
576+
// 4: controlX, controlY, endX, endY: quadratic bezier curve, see
577+
// https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/quadraticCurveTo
578+
// 5: control1X, control1Y, control2X, control2Y, radius: arcTo, see
579+
// https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/arcTo
580+
// 6: control1X, control1Y, control2X, control2Y, endX, endY: bezierCurveTo, see
581+
// https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/bezierCurveTo
582+
//
583+
// This notation is very dense and is intended as escape hatch for advanced graphics.
584+
function curve(ptr, len) {
585+
const s = memToString(ptr, len)
586+
// parse "1 2 3 4,5 6" into [[1,2,3,4], [5,6]]:
587+
const curves = s.split(",").map((s) => s.split(" ").map(Number))
588+
589+
const { x, y, ctx, fill, stroke } = canvas
590+
591+
ctx.beginPath()
592+
ctx.moveTo(x, y)
593+
594+
for (const curve of courves) {
595+
switch (curve.length) {
596+
case 2:
597+
ctx.lineTo(transformX(curve[0]), transformY(curve[1]))
598+
break
599+
case 4:
600+
ctx.quadraticCurveTo(
601+
transformX(curve[0]), // controlPoint.x
602+
transformY(curve[1]), // controlPoint.y
603+
transformX(curve[2]), // endPoint.x
604+
transformY(curve[3]) // endPoint.y
605+
)
606+
break
607+
case 5:
608+
ctx.arcTo(
609+
transformX(curve[0]), // controlPoint1.x
610+
transformY(curve[1]), // controlPoint1.y
611+
transformX(curve[2]), // controlPoint2.x
612+
transformY(curve[3]), // controlPoint1.y
613+
transformX(curve[4]) // radius
614+
)
615+
break
616+
case 6:
617+
ctx.bezierCurveTo(
618+
transformX(curve[0]), // controlPoint1.x
619+
transformY(curve[1]), // controlPoint1.y
620+
transformX(curve[2]), // controlPoint2.x
621+
transformY(curve[3]), // controlPoint1.y
622+
transformX(curve[4]), // endPoint.x
623+
transformY(curve[5]) // endPoint.y
624+
)
625+
break
626+
}
627+
}
628+
fill && ctx.fill()
629+
stroke && ctx.stroke()
630+
}
631+
565632
// stroke is exported to evy go/wasm.
566633
function stroke(ptr, len) {
567634
const s = memToString(ptr, len)

frontend/module/yace-editor.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -476,6 +476,7 @@ const builtins = new Set([
476476
"clear",
477477
"poly",
478478
"ellipse",
479+
"curve",
479480
"stroke",
480481
"fill",
481482
"dash",

main.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,7 @@ func format(r io.Reader, w io.StringWriter, checkOnly bool) error {
146146
parserBuiltins := evaluator.DefaultBuiltins(newCLIRuntime()).ParserBuiltins()
147147
prog, err := parser.Parse(in, parserBuiltins)
148148
if err != nil {
149+
fmt.Println("parser error")
149150
return fmt.Errorf("%w: %w", errParse, parser.TruncateError(err, 8))
150151
}
151152
out := prog.Format()

pkg/evaluator/builtin.go

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,13 +86,15 @@ func DefaultBuiltins(rt Runtime) Builtins {
8686
"line": xyBuiltin("line", rt.Line),
8787
"rect": xyBuiltin("rect", rt.Rect),
8888
"circle": numBuiltin("circle", rt.Circle),
89+
8990
"width": numBuiltin("width", rt.Width),
9091
"color": stringBuiltin("color", rt.Color),
9192
"colour": stringBuiltin("colour", rt.Color),
9293
"clear": {Func: clearFunc(rt.Clear), Decl: clearDecl},
9394

9495
"poly": {Func: polyFunc(rt.Poly), Decl: polyDecl},
9596
"ellipse": {Func: ellipseFunc(rt.Ellipse), Decl: ellipseDecl},
97+
"curve": {Func: curveFunc(rt.Curve), Decl: curveDecl},
9698

9799
"stroke": stringBuiltin("stroke", rt.Stroke),
98100
"fill": stringBuiltin("fill", rt.Fill),
@@ -154,6 +156,7 @@ type GraphicsRuntime interface {
154156
// advanced graphics functions
155157
Poly(vertices [][]float64)
156158
Ellipse(x, y, radiusX, radiusY, rotation, startAngle, endAngle float64)
159+
Curve(sements [][]float64)
157160
Stroke(s string)
158161
Fill(s string)
159162
Dash(segments []float64)
@@ -191,6 +194,7 @@ func (rt *UnimplementedRuntime) Width(w float64) { rt.Unimplemented("w
191194
func (rt *UnimplementedRuntime) Color(s string) { rt.Unimplemented("color") }
192195
func (rt *UnimplementedRuntime) Clear(color string) { rt.Unimplemented("clear") }
193196
func (rt *UnimplementedRuntime) Poly(vertices [][]float64) { rt.Unimplemented("poly") }
197+
func (rt *UnimplementedRuntime) Curve(sements [][]float64) { rt.Unimplemented("curve") }
194198
func (rt *UnimplementedRuntime) Stroke(s string) { rt.Unimplemented("stroke") }
195199
func (rt *UnimplementedRuntime) Fill(s string) { rt.Unimplemented("fill") }
196200
func (rt *UnimplementedRuntime) Dash(segments []float64) { rt.Unimplemented("dash") }
@@ -646,6 +650,31 @@ func ellipseFunc(ellipseFn func(x, y, radiusX, radiusY, rotation, startAngle, en
646650
}
647651
}
648652

653+
var curveDecl = &parser.FuncDeclStmt{
654+
Name: "curve",
655+
VariadicParam: &parser.Var{Name: "n", T: numArrayType},
656+
ReturnType: parser.NONE_TYPE,
657+
}
658+
659+
func curveFunc(curveFn func([][]float64)) BuiltinFunc {
660+
return func(_ *scope, args []Value) (Value, error) {
661+
segments := make([][]float64, len(args))
662+
for i, arg := range args {
663+
vertex := arg.(*Array)
664+
elements := *vertex.Elements
665+
if len(elements) < 2 || len(elements) == 3 || len(elements) > 6 {
666+
return nil, fmt.Errorf("%w: 'curve' argument %d has %d elements, expected 2, 4, 5 or 6", ErrBadArguments, i+1, len(elements))
667+
}
668+
segments[i] = make([]float64, len(elements))
669+
for j, val := range elements {
670+
segments[i][j] = val.(*Num).Val
671+
}
672+
}
673+
curveFn(segments)
674+
return nil, nil
675+
}
676+
}
677+
649678
var dashDecl = &parser.FuncDeclStmt{
650679
Name: "dash",
651680
VariadicParam: &parser.Var{Name: "segments", T: parser.NUM_TYPE},

pkg/parser/ast.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -544,7 +544,10 @@ func (i *IfStmt) AlwaysTerminates() bool {
544544
}
545545

546546
func (e *EventHandlerStmt) String() string {
547-
body := e.Body.String()
547+
body := ""
548+
if e.Body != nil {
549+
body = e.Body.String()
550+
}
548551
return "on " + e.Name + " {\n" + body + "}\n"
549552
}
550553

pkg/parser/parser.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,6 @@ func (p *parser) parseFunc(scope *scope) Node {
185185
p.advance() // advance past FUNC
186186
tok := p.cur // function name
187187
funcName := p.cur.Literal
188-
189188
p.advancePastNL() // advance past signature, already parsed into p.funcs earlier
190189
fd := p.funcs[funcName]
191190
scope = newScopeWithReturnType(scope, fd, fd.ReturnType)
@@ -202,6 +201,7 @@ func (p *parser) parseFunc(scope *scope) Node {
202201
if fd.ReturnType != NONE_TYPE && !block.AlwaysTerminates() {
203202
p.appendError("missing return")
204203
}
204+
205205
p.assertEnd()
206206
p.advance()
207207
p.recordComment(block)

pkg/wasm/imports.go

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,14 @@ func (rt *jsRuntime) Ellipse(x, y, rX, rY, rotation, startAngle, endAngle float6
5757
ellipse(x, y, rX, rY, rotation, startAngle, endAngle)
5858
}
5959

60+
func (rt *jsRuntime) Curve(segments [][]float64) {
61+
sStrings := make([]string, len(segments))
62+
for i, segment := range segments {
63+
sStrings[i] = floatsToString(segment)
64+
}
65+
curve(strings.Join(sStrings, ","))
66+
}
67+
6068
func floatsToString(floats []float64) string {
6169
if len(floats) == 0 {
6270
return ""
@@ -180,16 +188,6 @@ func rect(dx, dy float64)
180188
//export circle
181189
func circle(r float64)
182190

183-
// width is imported from JS, setting the lineWidth
184-
//
185-
//export width
186-
func width(w float64)
187-
188-
// color is imported from JS
189-
//
190-
//export color
191-
func color(s string)
192-
193191
// clear is imported from JS
194192
//
195193
//export clear
@@ -205,6 +203,21 @@ func poly(s string)
205203
//export ellipse
206204
func ellipse(x, y, rX, rY, rotation, startAngle, endAngle float64)
207205

206+
// curve is imported from JS
207+
//
208+
//export curve
209+
func curve(s string)
210+
211+
// width is imported from JS, setting the lineWidth
212+
//
213+
//export width
214+
func width(w float64)
215+
216+
// color is imported from JS
217+
//
218+
//export color
219+
func color(s string)
220+
208221
// stroke is imported from JS
209222
//
210223
//export stroke

0 commit comments

Comments
 (0)