Skip to content

Commit

Permalink
Updated example & intro with sprite animation
Browse files Browse the repository at this point in the history
Show errors from scripts
  • Loading branch information
Jonas Minnberg committed Jun 6, 2020
1 parent b114875 commit caa2c28
Show file tree
Hide file tree
Showing 9 changed files with 137 additions and 41 deletions.
39 changes: 39 additions & 0 deletions INTRO.md
Original file line number Diff line number Diff line change
Expand Up @@ -313,4 +313,43 @@ sine:
!rept 256 { !byte (sin(i*Math.Pi*2/256)+1) * 100 + 24 }
```
So this is all pretty good - but can we take advantage of the fact that we can
generate circles of different sizes? How about a small animation.
First, lets generate 8 sprites with different radiuses:
```cpp
spriteData:
!rept 8 {
!block circle(zeroes(3*21), 3, 12, 10, i + 3)
!byte 0
}
```

And we need to copy all frames to sprite memory

```cpp
!rept 8 {
ldx #3*21
$ lda spriteData-1+i*64,x
sta spriteMem-1+i*64,x
dex
bne -
}
```

Then lets add another sine table with an amplitude that matches the number of
frames, and add some code to set the sprite pointer every frame

```cpp
lda sine2,x
adc #(spriteMem-0x4000)/64

sta spritePtrs+2
rts

sine2:
!rept 256 { !byte (sin(i*Math.Pi*2/96)+1) * 3.5 }
```
The full example can be found in [asm/example.asm](asm/example.asm)
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@ all : debug

build/cmake_install.cmake :
rm -rf builds/debug
cmake -Bbuild -H. -DCMAKE_BUILD_TYPE=ReleaseDebug
cmake -Bbuild -H. -DCMAKE_BUILD_TYPE=Debug

compile_commands.json : build/compile_commands.json
rm -f compile_commands.json
ln -s builds/debug/compile_commands.json .
ln -s build/compile_commands.json .

debug : build/cmake_install.cmake compile_commands.json
cmake --build build -- -j8
Expand Down
52 changes: 36 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,22 +81,6 @@ Results are saved in tests.<name>
The assembled changes are then rolled back.


### Meta commands

```
!section <name>, <address>
!byte <value> [, <value> ]*
!if <value> { <statements> }
!test <name> { <statements> }
!assert <expression> [, <message> ]
...
```

### Basic Operation in Detail

The source is parsed top to bottom. Included files are inserted
Expand Down Expand Up @@ -135,3 +119,39 @@ Macros affect the symbol table, so you can set symbols from macros.
If you don't want to pollute the symbol table, used "."-symbols, they
will be local to the macro.

The symbol table supports the following types:
* Number (double)
* String (`std::string_view`)
* Byte Array (`std::vector<uint8_t>`)
* Symbols (SymbolTable, based on `std::unordered_map<std::string, std::any>`

Only numbers and strings can be assigned directly.

Arrays are returned from functions, such as `bytes(elems...)` which is the basic
way of creating an array.

A `Symbols` can be created using the `!enum` meta command.

```cpp
!enum myObj {
name = "hey"
x = 1
y = 3
}
```

### Limitations of the parser

Currently the parser evaluates everything while parsing. This means
that it is not possible to _parse_ an expression without _evaluating_ it.

To support delayed (macros) or skipped (if) evaulation, the parser
recognizes blocks ( `'{' anything '}'` ) and saves the contents without
evalutating it.

If we rewrite the parser to create an AST for delayed evaluation, more
advanced constructs would be possible.




40 changes: 23 additions & 17 deletions asm/example.asm
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ $ lda #100
jsr update_sprite
jmp loop

spriteMem = 0x5f80
spriteMem = 0x7000

init_sprite
; Enable sprite 2
Expand All @@ -90,11 +90,13 @@ init_sprite
sta spritePtrs+2

; Copy sprite data
!rept 10 {
ldx #3*21
$ lda spriteData-1,x
sta spriteMem-1,x
$ lda spriteData-1+i*64,x
sta spriteMem-1+i*64,x
dex
bne -
}
rts

update_sprite
Expand All @@ -110,6 +112,11 @@ update_sprite

stx xy
sty xy+1

lda sine2,x
adc #(spriteMem-0x4000)/64

sta spritePtrs+2
rts

xy: !byte 0,0
Expand All @@ -118,6 +125,9 @@ xy: !byte 0,0
sine:
!rept 256 { !byte (sin(i*Math.Pi*2/256)+1) * 100 + 24 }

sine2:
!rept 256 { !byte (sin(i*Math.Pi*2/96)+1) * 3.5 }

%{

function setPixel(target, width, x, y)
Expand All @@ -127,7 +137,8 @@ function setPixel(target, width, x, y)
end
end

function circle(target, width, xp, yp, r)
function circle(target, width, xp, yp, radius)
r = math.floor(radius + 0.5)
for y=-r,r, 1 do
for x=-r,r, 1 do
if x*x+y*y <= r*r then
Expand All @@ -138,23 +149,18 @@ function circle(target, width, xp, yp, r)
return target
end



}%

circle_sprite = circle(zeroes(3*21), 3, 12, 10, 10)

spriteData
;!rept 3*21 { !byte 0xff>>((i%3)+i/8) }

!ifdef BALL {
!block circle_sprite
} else {
; Balloon
!byte 0,127,0,1,255,192,3,255,224,3,231,224
!byte 7,217,240,7,223,240,2,217,240,3,231,224
!byte 3,255,224,3,255,224,2,255,160,1,127,64
!byte 1,62,64,0,156,128,0,156,128,0,73,0,0,73,0,0
!byte 62,0,0,62,0,0,62,0,0,28,0
}
spriteData:
!rept 8 {
!block circle(zeroes(3*21), 3, 12, 10, i + 3)
!byte 0xff
}

; Koala Image

koala = load("../data/oys.koa")
Expand Down
2 changes: 1 addition & 1 deletion src/grammar.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ BlockContents <- SkipProgram
SkipProgram <- (SkipLine EOL)* SkipLine?
SkipLine <- SkipLabel? _? (SkipMeta / SkipInstruction)? _? LineComment?
SkipLabel <- (_? DotSymbol ':') / (DotSymbol (_ / &EOL))
SkipInstruction <- (!(EOL / '}') .)*
SkipInstruction <- (!(LineComment / EOL / '}') .)*
SkipMeta <- MetaName _ (!(EOL / '}' / '{') .)* Block? (_ Symbol _ Block)*
String <- _ ["] StringContents ["] _
Expand Down
9 changes: 8 additions & 1 deletion src/meta.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -220,9 +220,16 @@ void initMeta(Assembler& a)
if (blocks.empty()) {
throw parse_error("No block for !rept");
}
auto count = any_cast<Number>(a.evaluateExpression(text));

std::any data = a.evaluateExpression(text);
auto* vec = any_cast<std::vector<uint8_t>>(&data);
size_t count = vec ? vec->size() : number<size_t>(data);

for (Number i = 0; i < count; i++) {
a.getSymbols()["i"] = i;
if(vec) {
a.getSymbols()["v"] = (*vec)[i];
}
a.evaluateBlock(blocks[0]);
}
});
Expand Down
13 changes: 9 additions & 4 deletions src/script.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ Scripting::Scripting()
{
lua.open_libraries(sol::lib::base, sol::lib::package, sol::lib::string,
sol::lib::math, sol::lib::table, sol::lib::debug);

}

void Scripting::load(utils::path const& p)
Expand Down Expand Up @@ -49,10 +48,16 @@ std::any Scripting::call(std::string_view const& name,
}
objs.push_back(o);
}
sol::object res = test.call(sol::as_args(objs));
if(res.is<double>()) {
sol::protected_function_result fres = test.call(sol::as_args(objs));
if (!fres.valid()) {
sol::error err = fres;
std::string what = err.what();
throw script_error(what);
}
sol::object res = fres;
if (res.is<double>()) {
return std::any(res.as<double>());
} else if(res.is<std::vector<uint8_t>>()) {
} else if (res.is<std::vector<uint8_t>>()) {
return std::any(res.as<std::vector<uint8_t>>());
}
return std::any();
Expand Down
12 changes: 12 additions & 0 deletions src/script.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,18 @@
#include <string>
#include <vector>

class script_error : public std::exception
{
public:
explicit script_error(std::string m = "Script error") : msg(std::move(m))
{}
const char* what() const noexcept override { return msg.c_str(); }

private:
std::string msg;
};


class Scripting
{
public:
Expand Down
7 changes: 7 additions & 0 deletions src/wrap.cpp
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
#include "wrap.h"

#include "script.h"
#include <peglib.h>

#include <coreutils/log.h>
#include <iostream>
#include <string>

using namespace std::string_literals;

SVWrap::SVWrap(peg::SemanticValues const& s) : sv(s) {}

Expand Down Expand Up @@ -126,6 +130,9 @@ void ParserWrapper::action(
LOGD("Caught %s", e.what());
current_error = e.what();
throw peg::parse_error(e.what());
} catch (script_error& e) {
throw peg::parse_error(e.what());

} catch (std::bad_any_cast& e) {
throw peg::parse_error("Data type error");
}
Expand Down

0 comments on commit caa2c28

Please sign in to comment.