Skip to content

Commit

Permalink
Start of test macros and use + panic in images fix + for i := num {
Browse files Browse the repository at this point in the history
… fix (#229)

* Start of test macros and use

* Add comments

* fix error handling for images (panic)

* Fix that := wouldn't work in simple for loop

* Add mandelbrot example (will be good to profile that one as it's slow)

* optimize/avoid allocs, better colors
  • Loading branch information
ldemailly authored Sep 15, 2024
1 parent 880b703 commit 3398017
Show file tree
Hide file tree
Showing 9 changed files with 133 additions and 42 deletions.
15 changes: 11 additions & 4 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -76,13 +76,20 @@ wasm/wasm_exec.js: Makefile
wasm/wasm_exec.html:
cp "$(shell $(WASM_GO) env GOROOT)/misc/wasm/wasm_exec.html" ./wasm/

test: grol
test: grol unit-tests examples grol-tests

unit-tests:
CGO_ENABLED=0 go test -tags $(GO_BUILD_TAGS) ./...
GOMEMLIMIT=1GiB ./grol examples/*.gr
GOMEMLIMIT=1GiB ./grol -shared-state grol_tests/*.gr

examples: grol
GOMEMLIMIT=1GiB ./grol -panic examples/*.gr

grol-tests: grol
GOMEMLIMIT=1GiB ./grol -panic -shared-state grol_tests/*.gr

check: grol
./check_samples_double_format.sh examples/*.gr
./check_tests_double_format.sh

generate: $(GEN)

Expand All @@ -107,4 +114,4 @@ lint: .golangci.yml
.golangci.yml: Makefile
curl -fsS -o .golangci.yml https://raw.githubusercontent.com/fortio/workflows/main/golangci.yml

.PHONY: all lint generate test clean run build wasm tinygo wasm-release tiny_test tinygo-tests check install
.PHONY: all lint generate test clean run build wasm tinygo wasm-release tiny_test tinygo-tests check install unit-tests examples grol-tests
17 changes: 17 additions & 0 deletions check_tests_double_format.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#! /bin/bash
set -e
export GOMEMLIMIT=1GiB
BIN="./grol -panic -shared-state"
echo "---testing double format for grol_tests ---"
$BIN -format grol_tests/*.gr > /tmp/format1
$BIN -format /tmp/format1 > /tmp/format2
diff -u /tmp/format1 /tmp/format2
$BIN -eval=false grol_tests/*.gr > /tmp/output1
$BIN /tmp/format2 > /tmp/output2
diff -u /tmp/output1 /tmp/output2
$BIN -format -compact grol_tests/*.gr > /tmp/format3
$BIN -format -compact /tmp/format3 > /tmp/format4
diff -u /tmp/format3 /tmp/format4
$BIN /tmp/format4 > /tmp/output3
diff -u /tmp/output1 /tmp/output3
echo "---done---"
2 changes: 1 addition & 1 deletion eval/eval.go
Original file line number Diff line number Diff line change
Expand Up @@ -803,7 +803,7 @@ func (s *State) evalForSpecialForms(fe *ast.ForExpression) (object.Object, bool)
if !ok {
return object.NULL, false
}
if ie.Token.Type() != token.ASSIGN {
if ie.Token.Type() != token.ASSIGN && ie.Token.Type() != token.DEFINE {
return object.NULL, false
}
if ie.Left.Value().Type() != token.IDENT {
Expand Down
20 changes: 14 additions & 6 deletions eval/macro_expension.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,15 @@ func isMacroCall(s *object.Environment, exp *ast.CallExpression) (*object.Macro,
return macro, true
}

func (s *State) MacroErrorf(fmtmsg string, args ...any) ast.Node {
res := ast.Builtin{}
res.Token = token.ByType(token.ERROR)
msgNode := ast.StringLiteral{}
msgNode.Token = token.Intern(token.STRING, fmt.Sprintf(fmtmsg, args...))
res.Parameters = []ast.Node{&msgNode}
return &res
}

func (s *State) ExpandMacros(program ast.Node) ast.Node {
return ast.Modify(program, func(node ast.Node) ast.Node {
callExpression, ok := node.(*ast.CallExpression)
Expand All @@ -86,6 +95,10 @@ func (s *State) ExpandMacros(program ast.Node) ast.Node {
}

args := quoteArgs(callExpression)
if len(args) != len(macro.Parameters) {
return s.MacroErrorf("wrong number of macro arguments, want=%d, got=%d", len(macro.Parameters), len(args))
}

evalEnv := extendMacroEnv(macro, args)

evaluated := evalEnv.Eval(macro.Body)
Expand All @@ -94,12 +107,7 @@ func (s *State) ExpandMacros(program ast.Node) ast.Node {
if !ok {
estr := fmt.Sprintf("macro should return Quote. got=%T (%+v)", evaluated, evaluated)
log.Critf("%s", estr)
res := ast.Builtin{}
res.Token = token.ByType(token.ERROR)
msg := ast.StringLiteral{}
msg.Token = token.Intern(token.STRING, estr)
res.Parameters = []ast.Node{&msg}
return &res
return s.MacroErrorf("%s", estr)
}
return quote.Node
})
Expand Down
40 changes: 40 additions & 0 deletions examples/mandelbrot.gr
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@

maxIter = 32

func mandelbrot(x, y) {
m := maxIter // bind to global, prevents caching, save allocs/cache writes.
zx := 0.0
zy := 0.0
for n := m {
zx2 := zx * zx
zy2 := zy * zy
if zx2 + zy2 > 4.0 {
return n
}
zy = 2 * zx * zy + y
zx = zx2 - zy2 + x
}
m
}

size:=256
img:="img"
image.new(img, size, size)

now := time.now()
for px := size {
for py := size {
x := (2.*px)/size - 1.5
y := (2.*py)/size - 1.
m := mandelbrot(x, y)
color := [0,0,0]
if m != maxIter {
norm := ln(m)/ln(maxIter)
color = [ 0.5+cos(PI/3+norm*PI/4)/2., .9, .5]
}
image.set_hsl(img,px,py,color)
}
}
elapsed := time.now() - now
log("Elapsed time:", elapsed)
image.save(img)
2 changes: 1 addition & 1 deletion extensions/images.go
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,7 @@ func createImageFunctions() { //nolint:funlen // this is a group of related func
return object.Errorf("unknown image.set function %q", name)
}
if oerr != nil {
return oerr
return *oerr
}
img.Image.SetNRGBA(x, y, color)
return args[0]
Expand Down
36 changes: 36 additions & 0 deletions grol_tests/_lib.gr
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/*
Library of macros for testing
*/

// Convert any grol object to a string.
func str(x) {
sprintf("%v", x)
}

// Test for absence of error and that the expression's result matches a regexp.
NoErr = macro(msg, expr, expectedRegexp) {
quote(if (r = catch(unquote(expr))).err {
error("FAIL unexpected error:", r.value, "for", unquote(msg))
} else {
if (regexp(unquote(expectedRegexp), str(r.value))) {
println("OK", unquote(msg), "is:", r.value)
} else {
error("FAIL", unquote(msg), "didn't match expected:", r.value)
}
})
}

// Test for expected error and that the message matches a regexp.
IsErr = macro(msg, expr, expectedRegexp) {
quote(if (r = catch(unquote(expr))).err {
if (regexp(unquote(expectedRegexp), str(r.value))) {
println("OK", unquote(msg), "get expected error:", r.value)
} else {
error("FAIL", unquote(msg), "didn't match expected:", r.value)
}
} else {
error("FAIL", unquote(msg),"didn't get expected error:",r.value)
})
}
33 changes: 3 additions & 30 deletions grol_tests/constants.gr
Original file line number Diff line number Diff line change
@@ -1,31 +1,4 @@
// - Test constants

/*
NoErr = macro(expr,a,b) {
quote(
r = catch(unquote(expr))
if r.err {
error("unexpected error:", r.value)
unquote(a)
} else {
unquote(b)
}
)
}
*/

if (r=catch(PI)).err {
error("unexpected error:", r.value)
} else {
println("PI is:", r.value)
}


if !(r=catch(PI++)).err {
error("expected error, got ok", r)
} else {
if regexp("attempt to change constant PI", r.value) {
println("Got expected error:", r.value)
} else {
error("unexpected error:", r.value)
}
}
NoErr("PI should exist", PI, "3.141592")
IsErr("Can't change a constant", PI++, "attempt to change constant PI")
10 changes: 10 additions & 0 deletions grol_tests/for.gr
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@

s :=0
// check that := works too in for loop.
for n := 4 {
s = s+ n
}
// 0 + 1 + 2 + 3 = 6
if s != 6 {
error("Expected 6, got", s) // was 16 before the fix.
}

0 comments on commit 3398017

Please sign in to comment.